aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorfloatdrop <floatdrop@yandex-team.ru>2022-02-10 16:47:15 +0300
committerDaniil Cherednik <dcherednik@yandex-team.ru>2022-02-10 16:47:15 +0300
commite63b84f1d39557d9e46ac380b1f388271894293c (patch)
tree338cdaff3fb027e030b847db66df06019a0e3149
parentf60febb7ea449535e7b073c386c7ff0539637fc0 (diff)
downloadydb-e63b84f1d39557d9e46ac380b1f388271894293c.tar.gz
Restoring authorship annotation for <floatdrop@yandex-team.ru>. Commit 1 of 2.
-rw-r--r--build/rules/go/vendor.policy14
-rw-r--r--contrib/libs/ya.make2
-rw-r--r--contrib/python/Jinja2/py2/README.rst32
-rw-r--r--contrib/python/Jinja2/py2/jinja2/__init__.py8
-rw-r--r--contrib/python/Jinja2/py2/jinja2/_compat.py170
-rw-r--r--contrib/python/Jinja2/py2/jinja2/_identifier.py2
-rw-r--r--contrib/python/Jinja2/py2/jinja2/bccache.py574
-rw-r--r--contrib/python/Jinja2/py2/jinja2/compiler.py2328
-rw-r--r--contrib/python/Jinja2/py2/jinja2/constants.py38
-rw-r--r--contrib/python/Jinja2/py2/jinja2/debug.py138
-rw-r--r--contrib/python/Jinja2/py2/jinja2/defaults.py32
-rw-r--r--contrib/python/Jinja2/py2/jinja2/environment.py2050
-rw-r--r--contrib/python/Jinja2/py2/jinja2/exceptions.py258
-rw-r--r--contrib/python/Jinja2/py2/jinja2/ext.py950
-rw-r--r--contrib/python/Jinja2/py2/jinja2/filters.py1858
-rw-r--r--contrib/python/Jinja2/py2/jinja2/idtracking.py518
-rw-r--r--contrib/python/Jinja2/py2/jinja2/lexer.py820
-rw-r--r--contrib/python/Jinja2/py2/jinja2/loaders.py878
-rw-r--r--contrib/python/Jinja2/py2/jinja2/meta.py174
-rw-r--r--contrib/python/Jinja2/py2/jinja2/nativetypes.py84
-rw-r--r--contrib/python/Jinja2/py2/jinja2/nodes.py1700
-rw-r--r--contrib/python/Jinja2/py2/jinja2/optimizer.py34
-rw-r--r--contrib/python/Jinja2/py2/jinja2/parser.py1278
-rw-r--r--contrib/python/Jinja2/py2/jinja2/runtime.py1142
-rw-r--r--contrib/python/Jinja2/py2/jinja2/sandbox.py768
-rw-r--r--contrib/python/Jinja2/py2/jinja2/tests.py248
-rw-r--r--contrib/python/Jinja2/py2/jinja2/utils.py986
-rw-r--r--contrib/python/Jinja2/py2/jinja2/visitor.py154
-rw-r--r--contrib/python/Jinja2/py2/tests/conftest.py80
-rw-r--r--contrib/python/Jinja2/py2/tests/res/templates/broken.html6
-rw-r--r--contrib/python/Jinja2/py2/tests/res/templates/foo/test.html2
-rw-r--r--contrib/python/Jinja2/py2/tests/res/templates/syntaxerror.html8
-rw-r--r--contrib/python/Jinja2/py2/tests/res/templates/test.html2
-rw-r--r--contrib/python/Jinja2/py2/tests/test_api.py334
-rw-r--r--contrib/python/Jinja2/py2/tests/test_async.py552
-rw-r--r--contrib/python/Jinja2/py2/tests/test_asyncfilters.py228
-rw-r--r--contrib/python/Jinja2/py2/tests/test_bytecode_cache.py124
-rw-r--r--contrib/python/Jinja2/py2/tests/test_core_tags.py462
-rw-r--r--contrib/python/Jinja2/py2/tests/test_debug.py68
-rw-r--r--contrib/python/Jinja2/py2/tests/test_ext.py624
-rw-r--r--contrib/python/Jinja2/py2/tests/test_features.py54
-rw-r--r--contrib/python/Jinja2/py2/tests/test_filters.py636
-rw-r--r--contrib/python/Jinja2/py2/tests/test_idtracking.py168
-rw-r--r--contrib/python/Jinja2/py2/tests/test_imports.py208
-rw-r--r--contrib/python/Jinja2/py2/tests/test_inheritance.py236
-rw-r--r--contrib/python/Jinja2/py2/tests/test_lexnparse.py664
-rw-r--r--contrib/python/Jinja2/py2/tests/test_loader.py234
-rw-r--r--contrib/python/Jinja2/py2/tests/test_nativetypes.py62
-rw-r--r--contrib/python/Jinja2/py2/tests/test_regression.py606
-rw-r--r--contrib/python/Jinja2/py2/tests/test_security.py196
-rw-r--r--contrib/python/Jinja2/py2/tests/test_tests.py96
-rw-r--r--contrib/python/Jinja2/py2/tests/test_utils.py88
-rw-r--r--contrib/python/Jinja2/py2/ya.make72
-rw-r--r--contrib/python/Jinja2/py3/README.rst32
-rw-r--r--contrib/python/Jinja2/py3/jinja2/__init__.py4
-rw-r--r--contrib/python/Jinja2/py3/jinja2/_identifier.py2
-rw-r--r--contrib/python/Jinja2/py3/jinja2/bccache.py480
-rw-r--r--contrib/python/Jinja2/py3/jinja2/compiler.py1852
-rw-r--r--contrib/python/Jinja2/py3/jinja2/constants.py36
-rw-r--r--contrib/python/Jinja2/py3/jinja2/debug.py122
-rw-r--r--contrib/python/Jinja2/py3/jinja2/defaults.py24
-rw-r--r--contrib/python/Jinja2/py3/jinja2/environment.py1596
-rw-r--r--contrib/python/Jinja2/py3/jinja2/exceptions.py170
-rw-r--r--contrib/python/Jinja2/py3/jinja2/ext.py788
-rw-r--r--contrib/python/Jinja2/py3/jinja2/filters.py1486
-rw-r--r--contrib/python/Jinja2/py3/jinja2/idtracking.py404
-rw-r--r--contrib/python/Jinja2/py3/jinja2/lexer.py624
-rw-r--r--contrib/python/Jinja2/py3/jinja2/loaders.py680
-rw-r--r--contrib/python/Jinja2/py3/jinja2/meta.py136
-rw-r--r--contrib/python/Jinja2/py3/jinja2/nativetypes.py74
-rw-r--r--contrib/python/Jinja2/py3/jinja2/nodes.py1418
-rw-r--r--contrib/python/Jinja2/py3/jinja2/optimizer.py26
-rw-r--r--contrib/python/Jinja2/py3/jinja2/parser.py1098
-rw-r--r--contrib/python/Jinja2/py3/jinja2/runtime.py762
-rw-r--r--contrib/python/Jinja2/py3/jinja2/sandbox.py494
-rw-r--r--contrib/python/Jinja2/py3/jinja2/tests.py202
-rw-r--r--contrib/python/Jinja2/py3/jinja2/utils.py682
-rw-r--r--contrib/python/Jinja2/py3/jinja2/visitor.py136
-rw-r--r--contrib/python/Jinja2/py3/tests/conftest.py68
-rw-r--r--contrib/python/Jinja2/py3/tests/res/templates/broken.html6
-rw-r--r--contrib/python/Jinja2/py3/tests/res/templates/foo/test.html2
-rw-r--r--contrib/python/Jinja2/py3/tests/res/templates/syntaxerror.html8
-rw-r--r--contrib/python/Jinja2/py3/tests/res/templates/test.html2
-rw-r--r--contrib/python/Jinja2/py3/tests/test_api.py308
-rw-r--r--contrib/python/Jinja2/py3/tests/test_async.py534
-rw-r--r--contrib/python/Jinja2/py3/tests/test_bytecode_cache.py116
-rw-r--r--contrib/python/Jinja2/py3/tests/test_core_tags.py442
-rw-r--r--contrib/python/Jinja2/py3/tests/test_debug.py60
-rw-r--r--contrib/python/Jinja2/py3/tests/test_ext.py552
-rw-r--r--contrib/python/Jinja2/py3/tests/test_features.py20
-rw-r--r--contrib/python/Jinja2/py3/tests/test_filters.py620
-rw-r--r--contrib/python/Jinja2/py3/tests/test_idtracking.py166
-rw-r--r--contrib/python/Jinja2/py3/tests/test_imports.py202
-rw-r--r--contrib/python/Jinja2/py3/tests/test_inheritance.py226
-rw-r--r--contrib/python/Jinja2/py3/tests/test_lexnparse.py616
-rw-r--r--contrib/python/Jinja2/py3/tests/test_loader.py212
-rw-r--r--contrib/python/Jinja2/py3/tests/test_nativetypes.py60
-rw-r--r--contrib/python/Jinja2/py3/tests/test_regression.py568
-rw-r--r--contrib/python/Jinja2/py3/tests/test_security.py138
-rw-r--r--contrib/python/Jinja2/py3/tests/test_tests.py92
-rw-r--r--contrib/python/Jinja2/py3/tests/test_utils.py76
-rw-r--r--contrib/python/Jinja2/py3/ya.make72
-rw-r--r--contrib/python/Jinja2/ya.make10
-rw-r--r--contrib/python/botocore/botocore/data/endpoints.json108
-rw-r--r--contrib/python/botocore/botocore/data/s3/2006-03-01/examples-1.json10
-rw-r--r--contrib/python/botocore/botocore/data/s3/2006-03-01/paginators-1.json138
-rw-r--r--contrib/python/botocore/botocore/data/s3/2006-03-01/service-2.json12370
-rw-r--r--contrib/python/botocore/botocore/data/s3/2006-03-01/waiters-2.json146
-rw-r--r--contrib/python/botocore/tests/SQS-119.py10
-rw-r--r--contrib/python/ya.make6
-rw-r--r--library/cpp/timezone_conversion/civil.cpp8
-rw-r--r--library/cpp/timezone_conversion/civil.h14
112 files changed, 27181 insertions, 27181 deletions
diff --git a/build/rules/go/vendor.policy b/build/rules/go/vendor.policy
index 3e9c0acada..c1f682e19b 100644
--- a/build/rules/go/vendor.policy
+++ b/build/rules/go/vendor.policy
@@ -217,9 +217,9 @@ ALLOW .* -> vendor/github.com/gorilla/websocket
# http sessions with cookie and filesystem session storage
ALLOW .* -> vendor/github.com/gorilla/sessions
-# Package gorilla/schema fills a struct with form values
-ALLOW .* -> vendor/github.com/gorilla/schema
-
+# Package gorilla/schema fills a struct with form values
+ALLOW .* -> vendor/github.com/gorilla/schema
+
# S2 geometry
ALLOW .* -> vendor/github.com/golang/geo
@@ -1032,11 +1032,11 @@ ALLOW infra/infractl/.* -> vendor/gopkg.in/yaml.v3
# CONTRIB-2445
ALLOW psp -> vendor/github.com/zimmski/go-mutesting
-# CONTRIB-2460
-ALLOW .* -> vendor/github.com/dgraph-io/ristretto
-
+# CONTRIB-2460
+ALLOW .* -> vendor/github.com/dgraph-io/ristretto
+
#
# This section is for EXCEPTIONS. Add new rule above, not here.
#
-
+
DENY .* -> vendor/
diff --git a/contrib/libs/ya.make b/contrib/libs/ya.make
index 9c4640fdcf..54798690d2 100644
--- a/contrib/libs/ya.make
+++ b/contrib/libs/ya.make
@@ -320,7 +320,7 @@ RECURSE(
svm
svt-hevc
svt-vp9
- szip
+ szip
t1ha
taocrypt
tbb
diff --git a/contrib/python/Jinja2/py2/README.rst b/contrib/python/Jinja2/py2/README.rst
index 060b19efee..cd1e0eac53 100644
--- a/contrib/python/Jinja2/py2/README.rst
+++ b/contrib/python/Jinja2/py2/README.rst
@@ -1,12 +1,12 @@
Jinja
=====
-
+
Jinja is a fast, expressive, extensible templating engine. Special
placeholders in the template allow writing code similar to Python
syntax. Then the template is passed data to render the final document.
-
+
It includes:
-
+
- Template inheritance and inclusion.
- Define and import macros within templates.
- HTML templates can use autoescaping to prevent XSS from untrusted
@@ -20,7 +20,7 @@ It includes:
- Exceptions point to the correct line in templates to make debugging
easier.
- Extensible filters, tests, functions, and even syntax.
-
+
Jinja's philosophy is that while application logic belongs in Python if
possible, it shouldn't make the template designer's job difficult by
restricting functionality too much.
@@ -41,22 +41,22 @@ Install and update using `pip`_:
In A Nutshell
-------------
-.. code-block:: jinja
-
+.. code-block:: jinja
+
{% extends "base.html" %}
{% block title %}Members{% endblock %}
- {% block content %}
- <ul>
- {% for user in users %}
- <li><a href="{{ user.url }}">{{ user.username }}</a></li>
- {% endfor %}
- </ul>
- {% endblock %}
-
-
+ {% block content %}
+ <ul>
+ {% for user in users %}
+ <li><a href="{{ user.url }}">{{ user.username }}</a></li>
+ {% endfor %}
+ </ul>
+ {% endblock %}
+
+
Links
-----
-
+
- Website: https://palletsprojects.com/p/jinja/
- Documentation: https://jinja.palletsprojects.com/
- Releases: https://pypi.org/project/Jinja2/
diff --git a/contrib/python/Jinja2/py2/jinja2/__init__.py b/contrib/python/Jinja2/py2/jinja2/__init__.py
index b444e9a841..6fd022be73 100644
--- a/contrib/python/Jinja2/py2/jinja2/__init__.py
+++ b/contrib/python/Jinja2/py2/jinja2/__init__.py
@@ -1,11 +1,11 @@
-# -*- coding: utf-8 -*-
+# -*- 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.
-"""
+"""
from markupsafe import escape
from markupsafe import Markup
-
+
from .bccache import BytecodeCache
from .bccache import FileSystemBytecodeCache
from .bccache import MemcachedBytecodeCache
@@ -41,5 +41,5 @@ from .utils import environmentfunction
from .utils import evalcontextfunction
from .utils import is_undefined
from .utils import select_autoescape
-
+
__version__ = "2.11.3"
diff --git a/contrib/python/Jinja2/py2/jinja2/_compat.py b/contrib/python/Jinja2/py2/jinja2/_compat.py
index 1f044954a0..0632a9e99d 100644
--- a/contrib/python/Jinja2/py2/jinja2/_compat.py
+++ b/contrib/python/Jinja2/py2/jinja2/_compat.py
@@ -1,110 +1,110 @@
-# -*- coding: utf-8 -*-
+# -*- coding: utf-8 -*-
# flake8: noqa
import marshal
-import sys
-
-PY2 = sys.version_info[0] == 2
+import sys
+
+PY2 = sys.version_info[0] == 2
PYPY = hasattr(sys, "pypy_translation_info")
-_identity = lambda x: x
-
-if not PY2:
- unichr = chr
- range_type = range
- text_type = str
- string_types = (str,)
- integer_types = (int,)
-
- iterkeys = lambda d: iter(d.keys())
- itervalues = lambda d: iter(d.values())
- iteritems = lambda d: iter(d.items())
-
- import pickle
- from io import BytesIO, StringIO
-
- NativeStringIO = StringIO
-
- def reraise(tp, value, tb=None):
- if value.__traceback__ is not tb:
- raise value.with_traceback(tb)
- raise value
-
- ifilter = filter
- imap = map
- izip = zip
- intern = sys.intern
-
- implements_iterator = _identity
- implements_to_string = _identity
- encode_filename = _identity
-
+_identity = lambda x: x
+
+if not PY2:
+ unichr = chr
+ range_type = range
+ text_type = str
+ string_types = (str,)
+ integer_types = (int,)
+
+ iterkeys = lambda d: iter(d.keys())
+ itervalues = lambda d: iter(d.values())
+ iteritems = lambda d: iter(d.items())
+
+ import pickle
+ from io import BytesIO, StringIO
+
+ NativeStringIO = StringIO
+
+ def reraise(tp, value, tb=None):
+ if value.__traceback__ is not tb:
+ raise value.with_traceback(tb)
+ raise value
+
+ ifilter = filter
+ imap = map
+ izip = zip
+ intern = sys.intern
+
+ implements_iterator = _identity
+ implements_to_string = _identity
+ encode_filename = _identity
+
marshal_dump = marshal.dump
marshal_load = marshal.load
-else:
- unichr = unichr
- text_type = unicode
- range_type = xrange
- string_types = (str, unicode)
- integer_types = (int, long)
-
- iterkeys = lambda d: d.iterkeys()
- itervalues = lambda d: d.itervalues()
- iteritems = lambda d: d.iteritems()
-
- import cPickle as pickle
- from cStringIO import StringIO as BytesIO, StringIO
-
- NativeStringIO = BytesIO
-
+else:
+ unichr = unichr
+ text_type = unicode
+ range_type = xrange
+ string_types = (str, unicode)
+ integer_types = (int, long)
+
+ iterkeys = lambda d: d.iterkeys()
+ itervalues = lambda d: d.itervalues()
+ iteritems = lambda d: d.iteritems()
+
+ 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")
-
- from itertools import imap, izip, ifilter
-
- intern = intern
-
- def implements_iterator(cls):
- cls.next = cls.__next__
- del cls.__next__
- return cls
-
- def implements_to_string(cls):
- cls.__unicode__ = cls.__str__
+
+ from itertools import imap, izip, ifilter
+
+ intern = intern
+
+ def implements_iterator(cls):
+ cls.next = cls.__next__
+ del cls.__next__
+ return cls
+
+ def implements_to_string(cls):
+ cls.__unicode__ = cls.__str__
cls.__str__ = lambda x: x.__unicode__().encode("utf-8")
- return cls
-
- def encode_filename(filename):
- if isinstance(filename, unicode):
+ return cls
+
+ def encode_filename(filename):
+ if isinstance(filename, unicode):
return filename.encode("utf-8")
- return filename
-
+ 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."""
- # This requires a bit of explanation: the basic idea is to make a
- # dummy metaclass for one level of class instantiation that replaces
- # itself with the actual metaclass.
- class metaclass(type):
- def __new__(cls, name, this_bases, d):
- return meta(name, bases, d)
-
+def with_metaclass(meta, *bases):
+ """Create a base class with a metaclass."""
+ # This requires a bit of explanation: the basic idea is to make a
+ # dummy metaclass for one level of class instantiation that replaces
+ # itself with the actual metaclass.
+ class metaclass(type):
+ def __new__(cls, name, this_bases, d):
+ return meta(name, bases, d)
+
return type.__new__(metaclass, "temporary_class", (), {})
+
-
-try:
- from urllib.parse import quote_from_bytes as url_quote
-except ImportError:
- from urllib import quote as url_quote
+try:
+ from urllib.parse import quote_from_bytes as url_quote
+except ImportError:
+ from urllib import quote as url_quote
try:
diff --git a/contrib/python/Jinja2/py2/jinja2/_identifier.py b/contrib/python/Jinja2/py2/jinja2/_identifier.py
index 224d5449d1..b0a761fc2a 100644
--- a/contrib/python/Jinja2/py2/jinja2/_identifier.py
+++ b/contrib/python/Jinja2/py2/jinja2/_identifier.py
@@ -1,6 +1,6 @@
import re
-# generated by scripts/generate_identifier_pattern.py
+# generated by scripts/generate_identifier_pattern.py
pattern = re.compile(
r"[\w·̀-ͯ·҃-֑҇-ׇֽֿׁׂׅׄؐ-ًؚ-ٰٟۖ-ۜ۟-۪ۤۧۨ-ܑۭܰ-݊ަ-ް߫-߳ࠖ-࠙ࠛ-ࠣࠥ-ࠧࠩ-࡙࠭-࡛ࣔ-ࣣ࣡-ःऺ-़ा-ॏ॑-ॗॢॣঁ-ঃ়া-ৄেৈো-্ৗৢৣਁ-ਃ਼ਾ-ੂੇੈੋ-੍ੑੰੱੵઁ-ઃ઼ા-ૅે-ૉો-્ૢૣଁ-ଃ଼ା-ୄେୈୋ-୍ୖୗୢୣஂா-ூெ-ைொ-்ௗఀ-ఃా-ౄె-ైొ-్ౕౖౢౣಁ-ಃ಼ಾ-ೄೆ-ೈೊ-್ೕೖೢೣഁ-ഃാ-ൄെ-ൈൊ-്ൗൢൣංඃ්ා-ුූෘ-ෟෲෳัิ-ฺ็-๎ັິ-ູົຼ່-ໍ༹༘༙༵༷༾༿ཱ-྄྆྇ྍ-ྗྙ-ྼ࿆ါ-ှၖ-ၙၞ-ၠၢ-ၤၧ-ၭၱ-ၴႂ-ႍႏႚ-ႝ፝-፟ᜒ-᜔ᜲ-᜴ᝒᝓᝲᝳ឴-៓៝᠋-᠍ᢅᢆᢩᤠ-ᤫᤰ-᤻ᨗ-ᨛᩕ-ᩞ᩠-᩿᩼᪰-᪽ᬀ-ᬄ᬴-᭄᭫-᭳ᮀ-ᮂᮡ-ᮭ᯦-᯳ᰤ-᰷᳐-᳔᳒-᳨᳭ᳲ-᳴᳸᳹᷀-᷵᷻-᷿‿⁀⁔⃐-⃥⃜⃡-⃰℘℮⳯-⵿⳱ⷠ-〪ⷿ-゙゚〯꙯ꙴ-꙽ꚞꚟ꛰꛱ꠂ꠆ꠋꠣ-ꠧꢀꢁꢴ-ꣅ꣠-꣱ꤦ-꤭ꥇ-꥓ꦀ-ꦃ꦳-꧀ꧥꨩ-ꨶꩃꩌꩍꩻ-ꩽꪰꪲ-ꪴꪷꪸꪾ꪿꫁ꫫ-ꫯꫵ꫶ꯣ-ꯪ꯬꯭ﬞ︀-️︠-︯︳︴﹍-﹏_𐇽𐋠𐍶-𐍺𐨁-𐨃𐨅𐨆𐨌-𐨏𐨸-𐨿𐨺𐫦𐫥𑀀-𑀂𑀸-𑁆𑁿-𑂂𑂰-𑂺𑄀-𑄂𑄧-𑅳𑄴𑆀-𑆂𑆳-𑇊𑇀-𑇌𑈬-𑈷𑈾𑋟-𑋪𑌀-𑌃𑌼𑌾-𑍄𑍇𑍈𑍋-𑍍𑍗𑍢𑍣𑍦-𑍬𑍰-𑍴𑐵-𑑆𑒰-𑓃𑖯-𑖵𑖸-𑗀𑗜𑗝𑘰-𑙀𑚫-𑚷𑜝-𑜫𑰯-𑰶𑰸-𑰿𑲒-𑲧𑲩-𑲶𖫰-𖫴𖬰-𖬶𖽑-𖽾𖾏-𖾒𛲝𛲞𝅥-𝅩𝅭-𝅲𝅻-𝆂𝆅-𝆋𝆪-𝆭𝉂-𝉄𝨀-𝨶𝨻-𝩬𝩵𝪄𝪛-𝪟𝪡-𝪯𞀀-𞀆𞀈-𞀘𞀛-𞀡𞀣𞀤𞀦-𞣐𞀪-𞣖𞥄-𞥊󠄀-󠇯]+" # noqa: B950
)
diff --git a/contrib/python/Jinja2/py2/jinja2/bccache.py b/contrib/python/Jinja2/py2/jinja2/bccache.py
index 9c0661030f..4ed6579d9c 100644
--- a/contrib/python/Jinja2/py2/jinja2/bccache.py
+++ b/contrib/python/Jinja2/py2/jinja2/bccache.py
@@ -1,28 +1,28 @@
-# -*- coding: utf-8 -*-
+# -*- coding: utf-8 -*-
"""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.
-
+
Situations where this is useful are often forking web applications that
are initialized on the first request.
-"""
+"""
import errno
import fnmatch
-import os
+import os
import stat
-import sys
-import tempfile
-from hashlib import sha1
+import sys
+import tempfile
+from hashlib import sha1
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
@@ -32,291 +32,291 @@ bc_magic = (
+ pickle.dumps(bc_version, 2)
+ pickle.dumps((sys.version_info[0] << 24) | sys.version_info[1], 2)
)
-
-
-class Bucket(object):
- """Buckets are used to store the bytecode for one template. It's created
- and initialized by the bytecode cache and passed to the loading functions.
-
- The buckets get an internal checksum from the cache assigned and use this
- to automatically reject outdated cache material. Individual bytecode
- cache subclasses don't have to care about cache invalidation.
- """
-
- def __init__(self, environment, key, checksum):
- self.environment = environment
- self.key = key
- self.checksum = checksum
- self.reset()
-
- def reset(self):
- """Resets the bucket (unloads the bytecode)."""
- self.code = None
-
- def load_bytecode(self, f):
- """Loads bytecode from a file or file like object."""
- # make sure the magic header is correct
- magic = f.read(len(bc_magic))
- if magic != bc_magic:
- self.reset()
- return
- # the source code of the file changed, we need to reload
- checksum = pickle.load(f)
- if self.checksum != checksum:
- self.reset()
- return
- # if marshal_load fails then we need to reload
- try:
- self.code = marshal_load(f)
- except (EOFError, ValueError, TypeError):
- self.reset()
- return
-
- def write_bytecode(self, f):
- """Dump the bytecode into the file or file like object passed."""
- if self.code is None:
+
+
+class Bucket(object):
+ """Buckets are used to store the bytecode for one template. It's created
+ and initialized by the bytecode cache and passed to the loading functions.
+
+ The buckets get an internal checksum from the cache assigned and use this
+ to automatically reject outdated cache material. Individual bytecode
+ cache subclasses don't have to care about cache invalidation.
+ """
+
+ def __init__(self, environment, key, checksum):
+ self.environment = environment
+ self.key = key
+ self.checksum = checksum
+ self.reset()
+
+ def reset(self):
+ """Resets the bucket (unloads the bytecode)."""
+ self.code = None
+
+ def load_bytecode(self, f):
+ """Loads bytecode from a file or file like object."""
+ # make sure the magic header is correct
+ magic = f.read(len(bc_magic))
+ if magic != bc_magic:
+ self.reset()
+ return
+ # the source code of the file changed, we need to reload
+ checksum = pickle.load(f)
+ if self.checksum != checksum:
+ self.reset()
+ return
+ # if marshal_load fails then we need to reload
+ try:
+ self.code = marshal_load(f)
+ except (EOFError, ValueError, TypeError):
+ self.reset()
+ return
+
+ 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")
- f.write(bc_magic)
- pickle.dump(self.checksum, f, 2)
- marshal_dump(self.code, f)
-
- def bytecode_from_string(self, string):
- """Load bytecode from a string."""
- self.load_bytecode(BytesIO(string))
-
- def bytecode_to_string(self):
- """Return the bytecode as string."""
- out = BytesIO()
- self.write_bytecode(out)
- return out.getvalue()
-
-
-class BytecodeCache(object):
- """To implement your own bytecode cache you have to subclass this class
- and override :meth:`load_bytecode` and :meth:`dump_bytecode`. Both of
- these methods are passed a :class:`~jinja2.bccache.Bucket`.
-
- A very basic bytecode cache that saves the bytecode on the file system::
-
- from os import path
-
- class MyCache(BytecodeCache):
-
- def __init__(self, directory):
- self.directory = directory
-
- def load_bytecode(self, bucket):
- filename = path.join(self.directory, bucket.key)
- if path.exists(filename):
- with open(filename, 'rb') as f:
- bucket.load_bytecode(f)
-
- def dump_bytecode(self, bucket):
- filename = path.join(self.directory, bucket.key)
- with open(filename, 'wb') as f:
- bucket.write_bytecode(f)
-
- A more advanced version of a filesystem based bytecode cache is part of
+ f.write(bc_magic)
+ pickle.dump(self.checksum, f, 2)
+ marshal_dump(self.code, f)
+
+ def bytecode_from_string(self, string):
+ """Load bytecode from a string."""
+ self.load_bytecode(BytesIO(string))
+
+ def bytecode_to_string(self):
+ """Return the bytecode as string."""
+ out = BytesIO()
+ self.write_bytecode(out)
+ return out.getvalue()
+
+
+class BytecodeCache(object):
+ """To implement your own bytecode cache you have to subclass this class
+ and override :meth:`load_bytecode` and :meth:`dump_bytecode`. Both of
+ these methods are passed a :class:`~jinja2.bccache.Bucket`.
+
+ A very basic bytecode cache that saves the bytecode on the file system::
+
+ from os import path
+
+ class MyCache(BytecodeCache):
+
+ def __init__(self, directory):
+ self.directory = directory
+
+ def load_bytecode(self, bucket):
+ filename = path.join(self.directory, bucket.key)
+ if path.exists(filename):
+ with open(filename, 'rb') as f:
+ bucket.load_bytecode(f)
+
+ def dump_bytecode(self, bucket):
+ filename = path.join(self.directory, bucket.key)
+ with open(filename, 'wb') as f:
+ bucket.write_bytecode(f)
+
+ A more advanced version of a filesystem based bytecode cache is part of
Jinja.
- """
-
- def load_bytecode(self, bucket):
- """Subclasses have to override this method to load bytecode into a
- bucket. If they are not able to find code in the cache for the
- bucket, it must not do anything.
- """
- raise NotImplementedError()
-
- def dump_bytecode(self, bucket):
- """Subclasses have to override this method to write the bytecode
- from a bucket back to the cache. If it unable to do so it must not
- fail silently but raise an exception.
- """
- raise NotImplementedError()
-
- def clear(self):
+ """
+
+ def load_bytecode(self, bucket):
+ """Subclasses have to override this method to load bytecode into a
+ bucket. If they are not able to find code in the cache for the
+ bucket, it must not do anything.
+ """
+ raise NotImplementedError()
+
+ def dump_bytecode(self, bucket):
+ """Subclasses have to override this method to write the bytecode
+ from a bucket back to the cache. If it unable to do so it must not
+ fail silently but raise an exception.
+ """
+ raise NotImplementedError()
+
+ def clear(self):
"""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."""
+ 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"))
- if filename is not None:
+ if filename is not None:
filename = "|" + filename
- if isinstance(filename, text_type):
+ if isinstance(filename, text_type):
filename = filename.encode("utf-8")
- hash.update(filename)
- return hash.hexdigest()
-
- def get_source_checksum(self, source):
- """Returns a checksum for the source."""
+ 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()
-
- def get_bucket(self, environment, name, filename, source):
- """Return a cache bucket for the given template. All arguments are
- mandatory but filename may be `None`.
- """
- key = self.get_cache_key(name, filename)
- checksum = self.get_source_checksum(source)
- bucket = Bucket(environment, key, checksum)
- self.load_bytecode(bucket)
- return bucket
-
- def set_bucket(self, bucket):
- """Put the bucket into the cache."""
- self.dump_bytecode(bucket)
-
-
-class FileSystemBytecodeCache(BytecodeCache):
- """A bytecode cache that stores bytecode on the filesystem. It accepts
- two arguments: The directory where the cache items are stored and a
- pattern string that is used to build the filename.
-
- If no directory is specified a default cache directory is selected. On
- Windows the user's temp directory is used, on UNIX systems a directory
- is created for the user in the system temp directory.
-
- The pattern can be used to have multiple separate caches operate on the
- same directory. The default pattern is ``'__jinja2_%s.cache'``. ``%s``
- is replaced with the cache key.
-
- >>> bcc = FileSystemBytecodeCache('/tmp/jinja_cache', '%s.cache')
-
- This bytecode cache supports clearing of the cache using the clear method.
- """
-
+
+ def get_bucket(self, environment, name, filename, source):
+ """Return a cache bucket for the given template. All arguments are
+ mandatory but filename may be `None`.
+ """
+ key = self.get_cache_key(name, filename)
+ checksum = self.get_source_checksum(source)
+ bucket = Bucket(environment, key, checksum)
+ self.load_bytecode(bucket)
+ return bucket
+
+ def set_bucket(self, bucket):
+ """Put the bucket into the cache."""
+ self.dump_bytecode(bucket)
+
+
+class FileSystemBytecodeCache(BytecodeCache):
+ """A bytecode cache that stores bytecode on the filesystem. It accepts
+ two arguments: The directory where the cache items are stored and a
+ pattern string that is used to build the filename.
+
+ If no directory is specified a default cache directory is selected. On
+ Windows the user's temp directory is used, on UNIX systems a directory
+ is created for the user in the system temp directory.
+
+ The pattern can be used to have multiple separate caches operate on the
+ same directory. The default pattern is ``'__jinja2_%s.cache'``. ``%s``
+ is replaced with the cache key.
+
+ >>> bcc = FileSystemBytecodeCache('/tmp/jinja_cache', '%s.cache')
+
+ This bytecode cache supports clearing of the cache using the clear method.
+ """
+
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():
+ 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."
)
-
- tmpdir = tempfile.gettempdir()
-
- # On windows the temporary directory is used specific unless
- # explicitly forced otherwise. We can just use that.
+
+ tmpdir = tempfile.gettempdir()
+
+ # On windows the temporary directory is used specific unless
+ # explicitly forced otherwise. We can just use that.
if os.name == "nt":
- return tmpdir
+ return tmpdir
if not hasattr(os, "getuid"):
- _unsafe_dir()
-
+ _unsafe_dir()
+
dirname = "_jinja2-cache-%d" % os.getuid()
- actual_dir = os.path.join(tmpdir, dirname)
-
- try:
- os.mkdir(actual_dir, stat.S_IRWXU)
- except OSError as e:
- if e.errno != errno.EEXIST:
- raise
- try:
- os.chmod(actual_dir, stat.S_IRWXU)
- actual_dir_stat = os.lstat(actual_dir)
+ actual_dir = os.path.join(tmpdir, dirname)
+
+ try:
+ os.mkdir(actual_dir, stat.S_IRWXU)
+ except OSError as e:
+ if e.errno != errno.EEXIST:
+ raise
+ 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
):
- _unsafe_dir()
- except OSError as e:
- if e.errno != errno.EEXIST:
- raise
-
- actual_dir_stat = os.lstat(actual_dir)
+ _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
):
- _unsafe_dir()
-
- return actual_dir
-
- def _get_cache_filename(self, bucket):
- return path.join(self.directory, self.pattern % bucket.key)
-
- def load_bytecode(self, bucket):
+ _unsafe_dir()
+
+ return actual_dir
+
+ 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")
- if f is not None:
- try:
- bucket.load_bytecode(f)
- finally:
- f.close()
-
- def dump_bytecode(self, bucket):
+ 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")
- try:
- bucket.write_bytecode(f)
- finally:
- f.close()
-
- def clear(self):
- # imported lazily here because google app-engine doesn't support
- # write access on the file system and the function does not exist
- # normally.
- from os import remove
+ try:
+ bucket.write_bytecode(f)
+ finally:
+ f.close()
+
+ def clear(self):
+ # imported lazily here because google app-engine doesn't support
+ # 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 % "*")
- for filename in files:
- try:
- remove(path.join(self.directory, filename))
- except OSError:
- pass
-
-
-class MemcachedBytecodeCache(BytecodeCache):
- """This class implements a bytecode cache that uses a memcache cache for
- storing the information. It does not enforce a specific memcache library
- (tummy's memcache or cmemcache) but will accept any class that provides
- the minimal interface required.
-
- Libraries compatible with this class:
-
+ for filename in files:
+ try:
+ remove(path.join(self.directory, filename))
+ except OSError:
+ pass
+
+
+class MemcachedBytecodeCache(BytecodeCache):
+ """This class implements a bytecode cache that uses a memcache cache for
+ storing the information. It does not enforce a specific memcache library
+ (tummy's memcache or cmemcache) but will accept any class that provides
+ the minimal interface required.
+
+ Libraries compatible with this class:
+
- `cachelib <https://github.com/pallets/cachelib>`_
- `python-memcached <https://pypi.org/project/python-memcached/>`_
-
- (Unfortunately the django cache interface is not compatible because it
- does not support storing binary data, only unicode. You can however pass
- the underlying cache client to the bytecode cache which is available
- as `django.core.cache.cache._client`.)
-
- The minimal interface for the client passed to the constructor is this:
-
- .. class:: MinimalClientInterface
-
- .. method:: set(key, value[, timeout])
-
- Stores the bytecode in the cache. `value` is a string and
- `timeout` the timeout of the key. If timeout is not provided
- a default timeout or no timeout should be assumed, if it's
- provided it's an integer with the number of seconds the cache
- item should exist.
-
- .. method:: get(key)
-
- Returns the value for the cache key. If the item does not
- exist in the cache the return value must be `None`.
-
- The other arguments to the constructor are the prefix for all keys that
- is added before the actual cache key and the timeout for the bytecode in
- the cache system. We recommend a high (or no) timeout.
-
- This bytecode cache does not support clearing of used items in the cache.
- The clear method is a no-operation function.
-
- .. versionadded:: 2.7
- Added support for ignoring memcache errors through the
- `ignore_memcache_errors` parameter.
- """
-
+
+ (Unfortunately the django cache interface is not compatible because it
+ does not support storing binary data, only unicode. You can however pass
+ the underlying cache client to the bytecode cache which is available
+ as `django.core.cache.cache._client`.)
+
+ The minimal interface for the client passed to the constructor is this:
+
+ .. class:: MinimalClientInterface
+
+ .. method:: set(key, value[, timeout])
+
+ Stores the bytecode in the cache. `value` is a string and
+ `timeout` the timeout of the key. If timeout is not provided
+ a default timeout or no timeout should be assumed, if it's
+ provided it's an integer with the number of seconds the cache
+ item should exist.
+
+ .. method:: get(key)
+
+ Returns the value for the cache key. If the item does not
+ exist in the cache the return value must be `None`.
+
+ The other arguments to the constructor are the prefix for all keys that
+ is added before the actual cache key and the timeout for the bytecode in
+ the cache system. We recommend a high (or no) timeout.
+
+ This bytecode cache does not support clearing of used items in the cache.
+ The clear method is a no-operation function.
+
+ .. versionadded:: 2.7
+ Added support for ignoring memcache errors through the
+ `ignore_memcache_errors` parameter.
+ """
+
def __init__(
self,
client,
@@ -324,27 +324,27 @@ class MemcachedBytecodeCache(BytecodeCache):
timeout=None,
ignore_memcache_errors=True,
):
- self.client = client
- self.prefix = prefix
- self.timeout = timeout
- self.ignore_memcache_errors = ignore_memcache_errors
-
- def load_bytecode(self, bucket):
- try:
- code = self.client.get(self.prefix + bucket.key)
- except Exception:
- if not self.ignore_memcache_errors:
- raise
- code = None
- if code is not None:
- bucket.bytecode_from_string(code)
-
- def dump_bytecode(self, bucket):
- args = (self.prefix + bucket.key, bucket.bytecode_to_string())
- if self.timeout is not None:
- args += (self.timeout,)
- try:
- self.client.set(*args)
- except Exception:
- if not self.ignore_memcache_errors:
- raise
+ self.client = client
+ self.prefix = prefix
+ self.timeout = timeout
+ self.ignore_memcache_errors = ignore_memcache_errors
+
+ def load_bytecode(self, bucket):
+ try:
+ code = self.client.get(self.prefix + bucket.key)
+ except Exception:
+ if not self.ignore_memcache_errors:
+ raise
+ code = None
+ if code is not None:
+ bucket.bytecode_from_string(code)
+
+ def dump_bytecode(self, bucket):
+ args = (self.prefix + bucket.key, bucket.bytecode_to_string())
+ if self.timeout is not None:
+ args += (self.timeout,)
+ try:
+ self.client.set(*args)
+ except Exception:
+ if not self.ignore_memcache_errors:
+ raise
diff --git a/contrib/python/Jinja2/py2/jinja2/compiler.py b/contrib/python/Jinja2/py2/jinja2/compiler.py
index 63297b42c3..6bec80c9ce 100644
--- a/contrib/python/Jinja2/py2/jinja2/compiler.py
+++ b/contrib/python/Jinja2/py2/jinja2/compiler.py
@@ -1,13 +1,13 @@
-# -*- coding: utf-8 -*-
+# -*- coding: utf-8 -*-
"""Compiles nodes from the parser into Python code."""
from collections import namedtuple
from functools import update_wrapper
-from itertools import chain
-from keyword import iskeyword as is_python_keyword
-
+from itertools import chain
+from keyword import iskeyword as is_python_keyword
+
from markupsafe import escape
from markupsafe import Markup
-
+
from . import nodes
from ._compat import imap
from ._compat import iteritems
@@ -27,7 +27,7 @@ from .optimizer import Optimizer
from .utils import concat
from .visitor import NodeVisitor
-operators = {
+operators = {
"eq": "==",
"ne": "!=",
"gt": ">",
@@ -36,559 +36,559 @@ operators = {
"lteq": "<=",
"in": "in",
"notin": "not in",
-}
-
-# what method to iterate over items do we want to use for dict iteration
-# in generated code? on 2.x let's go with iteritems, on 3.x with items
+}
+
+# what method to iterate over items do we want to use for dict iteration
+# in generated code? on 2.x let's go with iteritems, on 3.x with items
if hasattr(dict, "iteritems"):
dict_item_iter = "iteritems"
-else:
+else:
dict_item_iter = "items"
-
+
code_features = ["division"]
-
-# does this python version support generator stops? (PEP 0479)
-try:
+
+# does this python version support generator stops? (PEP 0479)
+try:
exec("from __future__ import generator_stop")
code_features.append("generator_stop")
-except SyntaxError:
- pass
-
-# does this python version support yield from?
-try:
+except SyntaxError:
+ pass
+
+# does this python version support yield from?
+try:
exec("def f(): yield from x()")
-except SyntaxError:
- supports_yield_from = False
-else:
- supports_yield_from = True
-
-
-def optimizeconst(f):
- def new_func(self, node, frame, **kwargs):
- # Only optimize if the frame is not volatile
- if self.optimized and not frame.eval_ctx.volatile:
- new_node = self.optimizer.visit(node, frame.eval_ctx)
- if new_node != node:
- return self.visit(new_node, frame)
- return f(self, node, frame, **kwargs)
-
- return update_wrapper(new_func, f)
-
-
+except SyntaxError:
+ supports_yield_from = False
+else:
+ supports_yield_from = True
+
+
+def optimizeconst(f):
+ def new_func(self, node, frame, **kwargs):
+ # Only optimize if the frame is not volatile
+ if self.optimized and not frame.eval_ctx.volatile:
+ new_node = self.optimizer.visit(node, frame.eval_ctx)
+ if new_node != node:
+ return self.visit(new_node, frame)
+ return f(self, node, frame, **kwargs)
+
+ return update_wrapper(new_func, f)
+
+
def generate(
node, environment, name, filename, stream=None, defer_init=False, optimized=True
):
- """Generate the python source for a node tree."""
- if not isinstance(node, nodes.Template):
+ """Generate the python source for a node tree."""
+ if not isinstance(node, nodes.Template):
raise TypeError("Can't compile non template nodes")
generator = environment.code_generator_class(
environment, name, filename, stream, defer_init, optimized
)
- generator.visit(node)
- if stream is None:
- return generator.stream.getvalue()
-
-
-def has_safe_repr(value):
- """Does the node have a safe representation?"""
- if value is None or value is NotImplemented or value is Ellipsis:
- return True
- if type(value) in (bool, int, float, complex, range_type, Markup) + string_types:
- return True
- if type(value) in (tuple, list, set, frozenset):
- for item in value:
- if not has_safe_repr(item):
- return False
- return True
- elif type(value) is dict:
- for key, value in iteritems(value):
- if not has_safe_repr(key):
- return False
- if not has_safe_repr(value):
- return False
- return True
- return False
-
-
-def find_undeclared(nodes, names):
- """Check if the names passed are accessed undeclared. The return value
- is a set of all the undeclared names from the sequence of names found.
- """
- visitor = UndeclaredNameVisitor(names)
- try:
- for node in nodes:
- visitor.visit(node)
- except VisitorExit:
- pass
- return visitor.undeclared
-
-
-class MacroRef(object):
- def __init__(self, node):
- self.node = node
- self.accesses_caller = False
- self.accesses_kwargs = False
- self.accesses_varargs = False
-
-
-class Frame(object):
- """Holds compile time information for us."""
-
- def __init__(self, eval_ctx, parent=None, level=None):
- self.eval_ctx = eval_ctx
+ generator.visit(node)
+ if stream is None:
+ return generator.stream.getvalue()
+
+
+def has_safe_repr(value):
+ """Does the node have a safe representation?"""
+ if value is None or value is NotImplemented or value is Ellipsis:
+ return True
+ if type(value) in (bool, int, float, complex, range_type, Markup) + string_types:
+ return True
+ if type(value) in (tuple, list, set, frozenset):
+ for item in value:
+ if not has_safe_repr(item):
+ return False
+ return True
+ elif type(value) is dict:
+ for key, value in iteritems(value):
+ if not has_safe_repr(key):
+ return False
+ if not has_safe_repr(value):
+ return False
+ return True
+ return False
+
+
+def find_undeclared(nodes, names):
+ """Check if the names passed are accessed undeclared. The return value
+ is a set of all the undeclared names from the sequence of names found.
+ """
+ visitor = UndeclaredNameVisitor(names)
+ try:
+ for node in nodes:
+ visitor.visit(node)
+ except VisitorExit:
+ pass
+ return visitor.undeclared
+
+
+class MacroRef(object):
+ def __init__(self, node):
+ self.node = node
+ self.accesses_caller = False
+ self.accesses_kwargs = False
+ self.accesses_varargs = False
+
+
+class Frame(object):
+ """Holds compile time information for us."""
+
+ def __init__(self, eval_ctx, parent=None, level=None):
+ self.eval_ctx = eval_ctx
self.symbols = Symbols(parent and parent.symbols or None, level=level)
-
- # a toplevel frame is the root + soft frames such as if conditions.
- self.toplevel = False
-
- # the root frame is basically just the outermost frame, so no if
- # conditions. This information is used to optimize inheritance
- # situations.
- self.rootlevel = False
-
- # in some dynamic inheritance situations the compiler needs to add
- # write tests around output statements.
- self.require_output_check = parent and parent.require_output_check
-
- # inside some tags we are using a buffer rather than yield statements.
- # this for example affects {% filter %} or {% macro %}. If a frame
- # is buffered this variable points to the name of the list used as
- # buffer.
- self.buffer = None
-
- # the name of the block we're in, otherwise None.
- self.block = parent and parent.block or None
-
- # the parent of this frame
- self.parent = parent
-
- if parent is not None:
- self.buffer = parent.buffer
-
- def copy(self):
- """Create a copy of the current one."""
- rv = object.__new__(self.__class__)
- rv.__dict__.update(self.__dict__)
- rv.symbols = self.symbols.copy()
- return rv
-
- def inner(self, isolated=False):
- """Return an inner frame."""
- if isolated:
- return Frame(self.eval_ctx, level=self.symbols.level + 1)
- return Frame(self.eval_ctx, self)
-
- def soft(self):
- """Return a soft frame. A soft frame may not be modified as
- standalone thing as it shares the resources with the frame it
- was created of, but it's not a rootlevel frame any longer.
-
- This is only used to implement if-statements.
- """
- rv = self.copy()
- rv.rootlevel = False
- return rv
-
- __copy__ = copy
-
-
-class VisitorExit(RuntimeError):
- """Exception used by the `UndeclaredNameVisitor` to signal a stop."""
-
-
-class DependencyFinderVisitor(NodeVisitor):
- """A visitor that collects filter and test calls."""
-
- def __init__(self):
- self.filters = set()
- self.tests = set()
-
- def visit_Filter(self, node):
- self.generic_visit(node)
- self.filters.add(node.name)
-
- def visit_Test(self, node):
- self.generic_visit(node)
- self.tests.add(node.name)
-
- def visit_Block(self, node):
- """Stop visiting at blocks."""
-
-
-class UndeclaredNameVisitor(NodeVisitor):
- """A visitor that checks if a name is accessed without being
- declared. This is different from the frame visitor as it will
- not stop at closure frames.
- """
-
- def __init__(self, names):
- self.names = set(names)
- self.undeclared = set()
-
- def visit_Name(self, node):
+
+ # a toplevel frame is the root + soft frames such as if conditions.
+ self.toplevel = False
+
+ # the root frame is basically just the outermost frame, so no if
+ # conditions. This information is used to optimize inheritance
+ # situations.
+ self.rootlevel = False
+
+ # in some dynamic inheritance situations the compiler needs to add
+ # write tests around output statements.
+ self.require_output_check = parent and parent.require_output_check
+
+ # inside some tags we are using a buffer rather than yield statements.
+ # this for example affects {% filter %} or {% macro %}. If a frame
+ # is buffered this variable points to the name of the list used as
+ # buffer.
+ self.buffer = None
+
+ # the name of the block we're in, otherwise None.
+ self.block = parent and parent.block or None
+
+ # the parent of this frame
+ self.parent = parent
+
+ if parent is not None:
+ self.buffer = parent.buffer
+
+ def copy(self):
+ """Create a copy of the current one."""
+ rv = object.__new__(self.__class__)
+ rv.__dict__.update(self.__dict__)
+ rv.symbols = self.symbols.copy()
+ return rv
+
+ def inner(self, isolated=False):
+ """Return an inner frame."""
+ if isolated:
+ return Frame(self.eval_ctx, level=self.symbols.level + 1)
+ return Frame(self.eval_ctx, self)
+
+ def soft(self):
+ """Return a soft frame. A soft frame may not be modified as
+ standalone thing as it shares the resources with the frame it
+ was created of, but it's not a rootlevel frame any longer.
+
+ This is only used to implement if-statements.
+ """
+ rv = self.copy()
+ rv.rootlevel = False
+ return rv
+
+ __copy__ = copy
+
+
+class VisitorExit(RuntimeError):
+ """Exception used by the `UndeclaredNameVisitor` to signal a stop."""
+
+
+class DependencyFinderVisitor(NodeVisitor):
+ """A visitor that collects filter and test calls."""
+
+ def __init__(self):
+ self.filters = set()
+ self.tests = set()
+
+ def visit_Filter(self, node):
+ self.generic_visit(node)
+ self.filters.add(node.name)
+
+ def visit_Test(self, node):
+ self.generic_visit(node)
+ self.tests.add(node.name)
+
+ def visit_Block(self, node):
+ """Stop visiting at blocks."""
+
+
+class UndeclaredNameVisitor(NodeVisitor):
+ """A visitor that checks if a name is accessed without being
+ declared. This is different from the frame visitor as it will
+ not stop at closure frames.
+ """
+
+ def __init__(self, names):
+ self.names = set(names)
+ self.undeclared = set()
+
+ def visit_Name(self, node):
if node.ctx == "load" and node.name in self.names:
- self.undeclared.add(node.name)
- if self.undeclared == self.names:
- raise VisitorExit()
- else:
- self.names.discard(node.name)
-
- def visit_Block(self, node):
- """Stop visiting a blocks."""
-
-
-class CompilerExit(Exception):
- """Raised if the compiler encountered a situation where it just
- doesn't make sense to further process the code. Any block that
- raises such an exception is not further processed.
- """
-
-
-class CodeGenerator(NodeVisitor):
+ self.undeclared.add(node.name)
+ if self.undeclared == self.names:
+ raise VisitorExit()
+ else:
+ self.names.discard(node.name)
+
+ def visit_Block(self, node):
+ """Stop visiting a blocks."""
+
+
+class CompilerExit(Exception):
+ """Raised if the compiler encountered a situation where it just
+ doesn't make sense to further process the code. Any block that
+ raises such an exception is not further processed.
+ """
+
+
+class CodeGenerator(NodeVisitor):
def __init__(
self, environment, name, filename, stream=None, defer_init=False, optimized=True
):
- if stream is None:
- stream = NativeStringIO()
- self.environment = environment
- self.name = name
- self.filename = filename
- self.stream = stream
- self.created_block_context = False
- self.defer_init = defer_init
- self.optimized = optimized
- if optimized:
- self.optimizer = Optimizer(environment)
-
- # aliases for imports
- self.import_aliases = {}
-
- # a registry for all blocks. Because blocks are moved out
- # into the global python scope they are registered here
- self.blocks = {}
-
- # the number of extends statements so far
- self.extends_so_far = 0
-
- # some templates have a rootlevel extends. In this case we
- # can safely assume that we're a child template and do some
- # more optimizations.
- self.has_known_extends = False
-
- # the current line number
- self.code_lineno = 1
-
- # registry of all filters and tests (global, not block local)
- self.tests = {}
- self.filters = {}
-
- # the debug information
- self.debug_info = []
- self._write_debug_info = None
-
- # the number of new lines before the next write()
- self._new_lines = 0
-
- # the line number of the last written statement
- self._last_line = 0
-
- # true if nothing was written so far.
- self._first_write = True
-
- # used by the `temporary_identifier` method to get new
- # unique, temporary identifier
- self._last_identifier = 0
-
- # the current indentation
- self._indentation = 0
-
- # Tracks toplevel assignments
- self._assign_stack = []
-
- # Tracks parameter definition blocks
- self._param_def_block = []
-
- # Tracks the current context.
+ if stream is None:
+ stream = NativeStringIO()
+ self.environment = environment
+ self.name = name
+ self.filename = filename
+ self.stream = stream
+ self.created_block_context = False
+ self.defer_init = defer_init
+ self.optimized = optimized
+ if optimized:
+ self.optimizer = Optimizer(environment)
+
+ # aliases for imports
+ self.import_aliases = {}
+
+ # a registry for all blocks. Because blocks are moved out
+ # into the global python scope they are registered here
+ self.blocks = {}
+
+ # the number of extends statements so far
+ self.extends_so_far = 0
+
+ # some templates have a rootlevel extends. In this case we
+ # can safely assume that we're a child template and do some
+ # more optimizations.
+ self.has_known_extends = False
+
+ # the current line number
+ self.code_lineno = 1
+
+ # registry of all filters and tests (global, not block local)
+ self.tests = {}
+ self.filters = {}
+
+ # the debug information
+ self.debug_info = []
+ self._write_debug_info = None
+
+ # the number of new lines before the next write()
+ self._new_lines = 0
+
+ # the line number of the last written statement
+ self._last_line = 0
+
+ # true if nothing was written so far.
+ self._first_write = True
+
+ # used by the `temporary_identifier` method to get new
+ # unique, temporary identifier
+ self._last_identifier = 0
+
+ # the current indentation
+ self._indentation = 0
+
+ # Tracks toplevel assignments
+ self._assign_stack = []
+
+ # Tracks parameter definition blocks
+ self._param_def_block = []
+
+ # Tracks the current context.
self._context_reference_stack = ["context"]
-
- # -- Various compilation helpers
-
- def fail(self, msg, lineno):
- """Fail with a :exc:`TemplateAssertionError`."""
- raise TemplateAssertionError(msg, lineno, self.name, self.filename)
-
- def temporary_identifier(self):
- """Get a new unique identifier."""
- self._last_identifier += 1
+
+ # -- Various compilation helpers
+
+ def fail(self, msg, lineno):
+ """Fail with a :exc:`TemplateAssertionError`."""
+ raise TemplateAssertionError(msg, lineno, self.name, self.filename)
+
+ def temporary_identifier(self):
+ """Get a new unique identifier."""
+ self._last_identifier += 1
return "t_%d" % self._last_identifier
-
- def buffer(self, frame):
- """Enable buffering for the frame from that point onwards."""
- frame.buffer = self.temporary_identifier()
+
+ def buffer(self, frame):
+ """Enable buffering for the frame from that point onwards."""
+ frame.buffer = self.temporary_identifier()
self.writeline("%s = []" % frame.buffer)
-
- def return_buffer_contents(self, frame, force_unescaped=False):
- """Return the buffer contents of the frame."""
- if not force_unescaped:
- if frame.eval_ctx.volatile:
+
+ def return_buffer_contents(self, frame, force_unescaped=False):
+ """Return the buffer contents of the frame."""
+ if not force_unescaped:
+ if frame.eval_ctx.volatile:
self.writeline("if context.eval_ctx.autoescape:")
- self.indent()
+ self.indent()
self.writeline("return Markup(concat(%s))" % frame.buffer)
- self.outdent()
+ self.outdent()
self.writeline("else:")
- self.indent()
+ self.indent()
self.writeline("return concat(%s)" % frame.buffer)
- self.outdent()
- return
- elif frame.eval_ctx.autoescape:
+ self.outdent()
+ return
+ elif frame.eval_ctx.autoescape:
self.writeline("return Markup(concat(%s))" % frame.buffer)
- return
+ return
self.writeline("return concat(%s)" % frame.buffer)
-
- def indent(self):
- """Indent by one."""
- self._indentation += 1
-
- def outdent(self, step=1):
- """Outdent by step."""
- self._indentation -= step
-
- def start_write(self, frame, node=None):
- """Yield or write into the frame buffer."""
- if frame.buffer is None:
+
+ def indent(self):
+ """Indent by one."""
+ self._indentation += 1
+
+ def outdent(self, step=1):
+ """Outdent by step."""
+ self._indentation -= step
+
+ def start_write(self, frame, node=None):
+ """Yield or write into the frame buffer."""
+ if frame.buffer is None:
self.writeline("yield ", node)
- else:
+ else:
self.writeline("%s.append(" % frame.buffer, node)
-
- def end_write(self, frame):
- """End the writing process started by `start_write`."""
- if frame.buffer is not None:
+
+ def end_write(self, frame):
+ """End the writing process started by `start_write`."""
+ if frame.buffer is not None:
self.write(")")
-
- def simple_write(self, s, frame, node=None):
- """Simple shortcut for start_write + write + end_write."""
- self.start_write(frame, node)
- self.write(s)
- self.end_write(frame)
-
- def blockvisit(self, nodes, frame):
- """Visit a list of nodes as block in a frame. If the current frame
- is no buffer a dummy ``if 0: yield None`` is written automatically.
- """
- try:
+
+ def simple_write(self, s, frame, node=None):
+ """Simple shortcut for start_write + write + end_write."""
+ self.start_write(frame, node)
+ self.write(s)
+ self.end_write(frame)
+
+ def blockvisit(self, nodes, frame):
+ """Visit a list of nodes as block in a frame. If the current frame
+ is no buffer a dummy ``if 0: yield None`` is written automatically.
+ """
+ try:
self.writeline("pass")
- for node in nodes:
- self.visit(node, frame)
- except CompilerExit:
- pass
-
- def write(self, x):
- """Write a string into the output stream."""
- if self._new_lines:
- if not self._first_write:
+ for node in nodes:
+ self.visit(node, frame)
+ except CompilerExit:
+ pass
+
+ def write(self, x):
+ """Write a string into the output stream."""
+ if self._new_lines:
+ if not self._first_write:
self.stream.write("\n" * self._new_lines)
- self.code_lineno += self._new_lines
- if self._write_debug_info is not None:
+ self.code_lineno += self._new_lines
+ if self._write_debug_info is not None:
self.debug_info.append((self._write_debug_info, self.code_lineno))
- self._write_debug_info = None
- self._first_write = False
+ self._write_debug_info = None
+ self._first_write = False
self.stream.write(" " * self._indentation)
- self._new_lines = 0
- self.stream.write(x)
-
- def writeline(self, x, node=None, extra=0):
- """Combination of newline and write."""
- self.newline(node, extra)
- self.write(x)
-
- def newline(self, node=None, extra=0):
- """Add one or more newlines before the next write."""
- self._new_lines = max(self._new_lines, 1 + extra)
- if node is not None and node.lineno != self._last_line:
- self._write_debug_info = node.lineno
- self._last_line = node.lineno
-
- def signature(self, node, frame, extra_kwargs=None):
- """Writes a function call to the stream for the current node.
- A leading comma is added automatically. The extra keyword
- arguments may not include python keywords otherwise a syntax
+ self._new_lines = 0
+ self.stream.write(x)
+
+ def writeline(self, x, node=None, extra=0):
+ """Combination of newline and write."""
+ self.newline(node, extra)
+ self.write(x)
+
+ def newline(self, node=None, extra=0):
+ """Add one or more newlines before the next write."""
+ self._new_lines = max(self._new_lines, 1 + extra)
+ if node is not None and node.lineno != self._last_line:
+ self._write_debug_info = node.lineno
+ self._last_line = node.lineno
+
+ def signature(self, node, frame, extra_kwargs=None):
+ """Writes a function call to the stream for the current node.
+ A leading comma is added automatically. The extra keyword
+ arguments may not include python keywords otherwise a syntax
error could occur. The extra keyword arguments should be given
- as python dict.
- """
- # if any of the given keyword arguments is a python keyword
- # we have to make sure that no invalid call is created.
- kwarg_workaround = False
- for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
- if is_python_keyword(kwarg):
- kwarg_workaround = True
- break
-
- for arg in node.args:
+ as python dict.
+ """
+ # if any of the given keyword arguments is a python keyword
+ # we have to make sure that no invalid call is created.
+ kwarg_workaround = False
+ for kwarg in chain((x.key for x in node.kwargs), extra_kwargs or ()):
+ if is_python_keyword(kwarg):
+ kwarg_workaround = True
+ break
+
+ for arg in node.args:
self.write(", ")
- self.visit(arg, frame)
-
- if not kwarg_workaround:
- for kwarg in node.kwargs:
+ self.visit(arg, frame)
+
+ if not kwarg_workaround:
+ for kwarg in node.kwargs:
self.write(", ")
- self.visit(kwarg, frame)
- if extra_kwargs is not None:
- for key, value in iteritems(extra_kwargs):
+ self.visit(kwarg, frame)
+ if extra_kwargs is not None:
+ for key, value in iteritems(extra_kwargs):
self.write(", %s=%s" % (key, value))
- if node.dyn_args:
+ if node.dyn_args:
self.write(", *")
- self.visit(node.dyn_args, frame)
-
- if kwarg_workaround:
- if node.dyn_kwargs is not None:
+ self.visit(node.dyn_args, frame)
+
+ if kwarg_workaround:
+ if node.dyn_kwargs is not None:
self.write(", **dict({")
- else:
+ else:
self.write(", **{")
- for kwarg in node.kwargs:
+ for kwarg in node.kwargs:
self.write("%r: " % kwarg.key)
- self.visit(kwarg.value, frame)
+ self.visit(kwarg.value, frame)
self.write(", ")
- if extra_kwargs is not None:
- for key, value in iteritems(extra_kwargs):
+ if extra_kwargs is not None:
+ for key, value in iteritems(extra_kwargs):
self.write("%r: %s, " % (key, value))
- if node.dyn_kwargs is not None:
+ if node.dyn_kwargs is not None:
self.write("}, **")
- self.visit(node.dyn_kwargs, frame)
+ self.visit(node.dyn_kwargs, frame)
self.write(")")
- else:
+ else:
self.write("}")
-
- elif node.dyn_kwargs is not None:
+
+ elif node.dyn_kwargs is not None:
self.write(", **")
- self.visit(node.dyn_kwargs, frame)
-
- def pull_dependencies(self, nodes):
- """Pull all the dependencies."""
- visitor = DependencyFinderVisitor()
- for node in nodes:
- visitor.visit(node)
+ self.visit(node.dyn_kwargs, frame)
+
+ def pull_dependencies(self, nodes):
+ """Pull all the dependencies."""
+ visitor = DependencyFinderVisitor()
+ for node in nodes:
+ visitor.visit(node)
for dependency in "filters", "tests":
- mapping = getattr(self, dependency)
- for name in getattr(visitor, dependency):
- if name not in mapping:
- mapping[name] = self.temporary_identifier()
+ mapping = getattr(self, dependency)
+ for name in getattr(visitor, dependency):
+ if name not in mapping:
+ mapping[name] = self.temporary_identifier()
self.writeline(
"%s = environment.%s[%r]" % (mapping[name], dependency, name)
)
-
- def enter_frame(self, frame):
- undefs = []
- for target, (action, param) in iteritems(frame.symbols.loads):
- if action == VAR_LOAD_PARAMETER:
- pass
- elif action == VAR_LOAD_RESOLVE:
+
+ def enter_frame(self, frame):
+ undefs = []
+ for target, (action, param) in iteritems(frame.symbols.loads):
+ if action == VAR_LOAD_PARAMETER:
+ pass
+ elif action == VAR_LOAD_RESOLVE:
self.writeline("%s = %s(%r)" % (target, self.get_resolve_func(), param))
- elif action == VAR_LOAD_ALIAS:
+ elif action == VAR_LOAD_ALIAS:
self.writeline("%s = %s" % (target, param))
- elif action == VAR_LOAD_UNDEFINED:
- undefs.append(target)
- else:
+ elif action == VAR_LOAD_UNDEFINED:
+ undefs.append(target)
+ else:
raise NotImplementedError("unknown load instruction")
- if undefs:
+ if undefs:
self.writeline("%s = missing" % " = ".join(undefs))
-
- def leave_frame(self, frame, with_python_scope=False):
- if not with_python_scope:
- undefs = []
- for target, _ in iteritems(frame.symbols.loads):
- undefs.append(target)
- if undefs:
+
+ def leave_frame(self, frame, with_python_scope=False):
+ if not with_python_scope:
+ undefs = []
+ for target, _ in iteritems(frame.symbols.loads):
+ undefs.append(target)
+ if undefs:
self.writeline("%s = missing" % " = ".join(undefs))
-
- def func(self, name):
- if self.environment.is_async:
+
+ def func(self, name):
+ if self.environment.is_async:
return "async def %s" % name
return "def %s" % name
-
- def macro_body(self, node, frame):
- """Dump the function def of a macro or call block."""
- frame = frame.inner()
- frame.symbols.analyze_node(node)
- macro_ref = MacroRef(node)
-
- explicit_caller = None
- skip_special_params = set()
- args = []
- for idx, arg in enumerate(node.args):
+
+ def macro_body(self, node, frame):
+ """Dump the function def of a macro or call block."""
+ frame = frame.inner()
+ frame.symbols.analyze_node(node)
+ macro_ref = MacroRef(node)
+
+ explicit_caller = None
+ skip_special_params = set()
+ args = []
+ for idx, arg in enumerate(node.args):
if arg.name == "caller":
- explicit_caller = idx
+ explicit_caller = idx
if arg.name in ("kwargs", "varargs"):
- skip_special_params.add(arg.name)
- args.append(frame.symbols.ref(arg.name))
-
+ skip_special_params.add(arg.name)
+ args.append(frame.symbols.ref(arg.name))
+
undeclared = find_undeclared(node.body, ("caller", "kwargs", "varargs"))
-
+
if "caller" in undeclared:
# In older Jinja versions there was a bug that allowed caller
- # to retain the special behavior even if it was mentioned in
- # the argument list. However thankfully this was only really
- # working if it was the last argument. So we are explicitly
- # checking this now and error out if it is anywhere else in
- # the argument list.
- if explicit_caller is not None:
- try:
- node.defaults[explicit_caller - len(node.args)]
- except IndexError:
+ # to retain the special behavior even if it was mentioned in
+ # the argument list. However thankfully this was only really
+ # working if it was the last argument. So we are explicitly
+ # checking this now and error out if it is anywhere else in
+ # the argument list.
+ if explicit_caller is not None:
+ try:
+ node.defaults[explicit_caller - len(node.args)]
+ except IndexError:
self.fail(
"When defining macros or call blocks the "
'special "caller" argument must be omitted '
"or be given a default.",
node.lineno,
)
- else:
+ else:
args.append(frame.symbols.declare_parameter("caller"))
- macro_ref.accesses_caller = True
+ macro_ref.accesses_caller = True
if "kwargs" in undeclared and "kwargs" not in skip_special_params:
args.append(frame.symbols.declare_parameter("kwargs"))
- macro_ref.accesses_kwargs = True
+ macro_ref.accesses_kwargs = True
if "varargs" in undeclared and "varargs" not in skip_special_params:
args.append(frame.symbols.declare_parameter("varargs"))
- macro_ref.accesses_varargs = True
-
- # macros are delayed, they never require output checks
- frame.require_output_check = False
- frame.symbols.analyze_node(node)
+ macro_ref.accesses_varargs = True
+
+ # macros are delayed, they never require output checks
+ frame.require_output_check = False
+ frame.symbols.analyze_node(node)
self.writeline("%s(%s):" % (self.func("macro"), ", ".join(args)), node)
- self.indent()
-
- self.buffer(frame)
- self.enter_frame(frame)
-
- self.push_parameter_definitions(frame)
- for idx, arg in enumerate(node.args):
- ref = frame.symbols.ref(arg.name)
+ self.indent()
+
+ self.buffer(frame)
+ self.enter_frame(frame)
+
+ self.push_parameter_definitions(frame)
+ for idx, arg in enumerate(node.args):
+ ref = frame.symbols.ref(arg.name)
self.writeline("if %s is missing:" % ref)
- self.indent()
- try:
- default = node.defaults[idx - len(node.args)]
- except IndexError:
+ self.indent()
+ try:
+ default = node.defaults[idx - len(node.args)]
+ except IndexError:
self.writeline(
"%s = undefined(%r, name=%r)"
% (ref, "parameter %r was not provided" % arg.name, arg.name)
)
- else:
+ else:
self.writeline("%s = " % ref)
- self.visit(default, frame)
- self.mark_parameter_stored(ref)
- self.outdent()
- self.pop_parameter_definitions()
-
- self.blockvisit(node.body, frame)
- self.return_buffer_contents(frame, force_unescaped=True)
- self.leave_frame(frame, with_python_scope=True)
- self.outdent()
-
- return frame, macro_ref
-
- def macro_def(self, macro_ref, frame):
- """Dump the macro definition for the def created by macro_body."""
+ self.visit(default, frame)
+ self.mark_parameter_stored(ref)
+ self.outdent()
+ self.pop_parameter_definitions()
+
+ self.blockvisit(node.body, frame)
+ self.return_buffer_contents(frame, force_unescaped=True)
+ self.leave_frame(frame, with_python_scope=True)
+ self.outdent()
+
+ return frame, macro_ref
+
+ def macro_def(self, macro_ref, frame):
+ """Dump the macro definition for the def created by macro_body."""
arg_tuple = ", ".join(repr(x.name) for x in macro_ref.node.args)
name = getattr(macro_ref.node, "name", None)
- if len(macro_ref.node.args) == 1:
+ if len(macro_ref.node.args) == 1:
arg_tuple += ","
self.write(
"Macro(environment, macro, %r, (%s), %r, %r, %r, "
@@ -601,213 +601,213 @@ class CodeGenerator(NodeVisitor):
macro_ref.accesses_caller,
)
)
-
- def position(self, node):
- """Return a human readable position for the node."""
+
+ def position(self, node):
+ """Return a human readable position for the node."""
rv = "line %d" % node.lineno
- if self.name is not None:
+ if self.name is not None:
rv += " in " + repr(self.name)
- return rv
-
- def dump_local_context(self, frame):
+ return rv
+
+ def dump_local_context(self, frame):
return "{%s}" % ", ".join(
"%r: %s" % (name, target)
for name, target in iteritems(frame.symbols.dump_stores())
)
-
- def write_commons(self):
- """Writes a common preamble that is used by root and block functions.
- Primarily this sets up common local helpers and enforces a generator
- through a dead branch.
- """
+
+ def write_commons(self):
+ """Writes a common preamble that is used by root and block functions.
+ Primarily this sets up common local helpers and enforces a generator
+ through a dead branch.
+ """
self.writeline("resolve = context.resolve_or_missing")
self.writeline("undefined = environment.undefined")
# always use the standard Undefined class for the implicit else of
# conditional expressions
self.writeline("cond_expr_undefined = Undefined")
self.writeline("if 0: yield None")
-
- def push_parameter_definitions(self, frame):
- """Pushes all parameter targets from the given frame into a local
- stack that permits tracking of yet to be assigned parameters. In
- particular this enables the optimization from `visit_Name` to skip
- undefined expressions for parameters in macros as macros can reference
- otherwise unbound parameters.
- """
- self._param_def_block.append(frame.symbols.dump_param_targets())
-
- def pop_parameter_definitions(self):
- """Pops the current parameter definitions set."""
- self._param_def_block.pop()
-
- def mark_parameter_stored(self, target):
- """Marks a parameter in the current parameter definitions as stored.
- This will skip the enforced undefined checks.
- """
- if self._param_def_block:
- self._param_def_block[-1].discard(target)
-
- def push_context_reference(self, target):
- self._context_reference_stack.append(target)
-
- def pop_context_reference(self):
- self._context_reference_stack.pop()
-
- def get_context_ref(self):
- return self._context_reference_stack[-1]
-
- def get_resolve_func(self):
- target = self._context_reference_stack[-1]
+
+ def push_parameter_definitions(self, frame):
+ """Pushes all parameter targets from the given frame into a local
+ stack that permits tracking of yet to be assigned parameters. In
+ particular this enables the optimization from `visit_Name` to skip
+ undefined expressions for parameters in macros as macros can reference
+ otherwise unbound parameters.
+ """
+ self._param_def_block.append(frame.symbols.dump_param_targets())
+
+ def pop_parameter_definitions(self):
+ """Pops the current parameter definitions set."""
+ self._param_def_block.pop()
+
+ def mark_parameter_stored(self, target):
+ """Marks a parameter in the current parameter definitions as stored.
+ This will skip the enforced undefined checks.
+ """
+ if self._param_def_block:
+ self._param_def_block[-1].discard(target)
+
+ def push_context_reference(self, target):
+ self._context_reference_stack.append(target)
+
+ def pop_context_reference(self):
+ self._context_reference_stack.pop()
+
+ def get_context_ref(self):
+ return self._context_reference_stack[-1]
+
+ def get_resolve_func(self):
+ target = self._context_reference_stack[-1]
if target == "context":
return "resolve"
return "%s.resolve" % target
-
- def derive_context(self, frame):
+
+ def derive_context(self, frame):
return "%s.derived(%s)" % (
- self.get_context_ref(),
- self.dump_local_context(frame),
- )
-
- def parameter_is_undeclared(self, target):
- """Checks if a given target is an undeclared parameter."""
- if not self._param_def_block:
- return False
- return target in self._param_def_block[-1]
-
- def push_assign_tracking(self):
- """Pushes a new layer for assignment tracking."""
- self._assign_stack.append(set())
-
- def pop_assign_tracking(self, frame):
- """Pops the topmost level for assignment tracking and updates the
- context variables if necessary.
- """
- vars = self._assign_stack.pop()
- if not frame.toplevel or not vars:
- return
+ self.get_context_ref(),
+ self.dump_local_context(frame),
+ )
+
+ def parameter_is_undeclared(self, target):
+ """Checks if a given target is an undeclared parameter."""
+ if not self._param_def_block:
+ return False
+ return target in self._param_def_block[-1]
+
+ def push_assign_tracking(self):
+ """Pushes a new layer for assignment tracking."""
+ self._assign_stack.append(set())
+
+ def pop_assign_tracking(self, frame):
+ """Pops the topmost level for assignment tracking and updates the
+ context variables if necessary.
+ """
+ vars = self._assign_stack.pop()
+ if not frame.toplevel or not vars:
+ return
public_names = [x for x in vars if x[:1] != "_"]
- if len(vars) == 1:
- name = next(iter(vars))
- ref = frame.symbols.ref(name)
+ if len(vars) == 1:
+ name = next(iter(vars))
+ ref = frame.symbols.ref(name)
self.writeline("context.vars[%r] = %s" % (name, ref))
- else:
+ else:
self.writeline("context.vars.update({")
- for idx, name in enumerate(vars):
- if idx:
+ for idx, name in enumerate(vars):
+ if idx:
self.write(", ")
- ref = frame.symbols.ref(name)
+ ref = frame.symbols.ref(name)
self.write("%r: %s" % (name, ref))
self.write("})")
- if public_names:
- if len(public_names) == 1:
+ if public_names:
+ if len(public_names) == 1:
self.writeline("context.exported_vars.add(%r)" % public_names[0])
- else:
+ else:
self.writeline(
"context.exported_vars.update((%s))"
% ", ".join(imap(repr, public_names))
)
-
- # -- Statement Visitors
-
- def visit_Template(self, node, frame=None):
+
+ # -- Statement Visitors
+
+ def visit_Template(self, node, frame=None):
assert frame is None, "no root frame allowed"
- eval_ctx = EvalContext(self.environment, self.name)
-
+ eval_ctx = EvalContext(self.environment, self.name)
+
from .runtime import exported
-
+
self.writeline("from __future__ import %s" % ", ".join(code_features))
self.writeline("from jinja2.runtime import " + ", ".join(exported))
- if self.environment.is_async:
+ if self.environment.is_async:
self.writeline(
"from jinja2.asyncsupport import auto_await, "
"auto_aiter, AsyncLoopContext"
)
-
- # if we want a deferred initialization we cannot move the
- # environment into a local name
+
+ # if we want a deferred initialization we cannot move the
+ # environment into a local name
envenv = not self.defer_init and ", environment=environment" or ""
-
- # do we have an extends tag at all? If not, we can save some
- # overhead by just not processing any inheritance code.
- have_extends = node.find(nodes.Extends) is not None
-
- # find all blocks
- for block in node.find_all(nodes.Block):
- if block.name in self.blocks:
+
+ # do we have an extends tag at all? If not, we can save some
+ # overhead by just not processing any inheritance code.
+ have_extends = node.find(nodes.Extends) is not None
+
+ # find all blocks
+ for block in node.find_all(nodes.Block):
+ if block.name in self.blocks:
self.fail("block %r defined twice" % block.name, block.lineno)
- self.blocks[block.name] = block
-
- # find all imports and import them
- for import_ in node.find_all(nodes.ImportedName):
- if import_.importname not in self.import_aliases:
- imp = import_.importname
- self.import_aliases[imp] = alias = self.temporary_identifier()
+ self.blocks[block.name] = block
+
+ # find all imports and import them
+ for import_ in node.find_all(nodes.ImportedName):
+ if import_.importname not in self.import_aliases:
+ imp = import_.importname
+ self.import_aliases[imp] = alias = self.temporary_identifier()
if "." in imp:
module, obj = imp.rsplit(".", 1)
self.writeline("from %s import %s as %s" % (module, obj, alias))
- else:
+ else:
self.writeline("import %s as %s" % (imp, alias))
-
- # add the load name
+
+ # add the load name
self.writeline("name = %r" % self.name)
-
- # generate the root render function.
+
+ # generate the root render function.
self.writeline(
"%s(context, missing=missing%s):" % (self.func("root"), envenv), extra=1
)
- self.indent()
- self.write_commons()
-
- # process the root
- frame = Frame(eval_ctx)
+ self.indent()
+ self.write_commons()
+
+ # process the root
+ frame = Frame(eval_ctx)
if "self" in find_undeclared(node.body, ("self",)):
ref = frame.symbols.declare_parameter("self")
self.writeline("%s = TemplateReference(context)" % ref)
- frame.symbols.analyze_node(node)
- frame.toplevel = frame.rootlevel = True
- frame.require_output_check = have_extends and not self.has_known_extends
- if have_extends:
+ frame.symbols.analyze_node(node)
+ frame.toplevel = frame.rootlevel = True
+ frame.require_output_check = have_extends and not self.has_known_extends
+ if have_extends:
self.writeline("parent_template = None")
- self.enter_frame(frame)
- self.pull_dependencies(node.body)
- self.blockvisit(node.body, frame)
- self.leave_frame(frame, with_python_scope=True)
- self.outdent()
-
- # make sure that the parent root is called.
- if have_extends:
- if not self.has_known_extends:
- self.indent()
+ self.enter_frame(frame)
+ self.pull_dependencies(node.body)
+ self.blockvisit(node.body, frame)
+ self.leave_frame(frame, with_python_scope=True)
+ self.outdent()
+
+ # make sure that the parent root is called.
+ if have_extends:
+ if not self.has_known_extends:
+ self.indent()
self.writeline("if parent_template is not None:")
- self.indent()
- if supports_yield_from and not self.environment.is_async:
+ self.indent()
+ if supports_yield_from and not self.environment.is_async:
self.writeline("yield from parent_template.root_render_func(context)")
- else:
+ else:
self.writeline(
"%sfor event in parent_template."
"root_render_func(context):"
% (self.environment.is_async and "async " or "")
)
- self.indent()
+ self.indent()
self.writeline("yield event")
- self.outdent()
- self.outdent(1 + (not self.has_known_extends))
-
- # at this point we now have the blocks collected and can visit them too.
- for name, block in iteritems(self.blocks):
+ self.outdent()
+ self.outdent(1 + (not self.has_known_extends))
+
+ # at this point we now have the blocks collected and can visit them too.
+ for name, block in iteritems(self.blocks):
self.writeline(
"%s(context, missing=missing%s):"
% (self.func("block_" + name), envenv),
block,
1,
)
- self.indent()
- self.write_commons()
- # It's important that we do not make this frame a child of the
- # toplevel template. This would cause a variety of
- # interesting issues with identifier tracking.
- block_frame = Frame(eval_ctx)
+ self.indent()
+ self.write_commons()
+ # It's important that we do not make this frame a child of the
+ # toplevel template. This would cause a variety of
+ # interesting issues with identifier tracking.
+ block_frame = Frame(eval_ctx)
undeclared = find_undeclared(block.body, ("self", "super"))
if "self" in undeclared:
ref = block_frame.symbols.declare_parameter("self")
@@ -815,42 +815,42 @@ class CodeGenerator(NodeVisitor):
if "super" in undeclared:
ref = block_frame.symbols.declare_parameter("super")
self.writeline("%s = context.super(%r, block_%s)" % (ref, name, name))
- block_frame.symbols.analyze_node(block)
- block_frame.block = name
- self.enter_frame(block_frame)
- self.pull_dependencies(block.body)
- self.blockvisit(block.body, block_frame)
- self.leave_frame(block_frame, with_python_scope=True)
- self.outdent()
-
+ block_frame.symbols.analyze_node(block)
+ block_frame.block = name
+ self.enter_frame(block_frame)
+ self.pull_dependencies(block.body)
+ self.blockvisit(block.body, block_frame)
+ self.leave_frame(block_frame, with_python_scope=True)
+ self.outdent()
+
self.writeline(
"blocks = {%s}" % ", ".join("%r: block_%s" % (x, x) for x in self.blocks),
extra=1,
)
-
- # add a function that returns the debug info
+
+ # add a function that returns the debug info
self.writeline(
"debug_info = %r" % "&".join("%s=%s" % x for x in self.debug_info)
)
-
- def visit_Block(self, node, frame):
- """Call a block and register it for the template."""
- level = 0
- if frame.toplevel:
- # if we know that we are a child template, there is no need to
- # check if we are one
- if self.has_known_extends:
- return
- if self.extends_so_far > 0:
+
+ def visit_Block(self, node, frame):
+ """Call a block and register it for the template."""
+ level = 0
+ if frame.toplevel:
+ # if we know that we are a child template, there is no need to
+ # check if we are one
+ if self.has_known_extends:
+ return
+ if self.extends_so_far > 0:
self.writeline("if parent_template is None:")
- self.indent()
- level += 1
-
- if node.scoped:
- context = self.derive_context(frame)
- else:
- context = self.get_context_ref()
-
+ self.indent()
+ level += 1
+
+ if node.scoped:
+ context = self.derive_context(frame)
+ else:
+ context = self.get_context_ref()
+
if (
supports_yield_from
and not self.environment.is_async
@@ -859,132 +859,132 @@ class CodeGenerator(NodeVisitor):
self.writeline(
"yield from context.blocks[%r][0](%s)" % (node.name, context), node
)
- else:
+ else:
loop = self.environment.is_async and "async for" or "for"
self.writeline(
"%s event in context.blocks[%r][0](%s):" % (loop, node.name, context),
node,
)
- self.indent()
+ self.indent()
self.simple_write("event", frame)
- self.outdent()
-
- self.outdent(level)
-
- def visit_Extends(self, node, frame):
- """Calls the extender."""
- if not frame.toplevel:
+ self.outdent()
+
+ self.outdent(level)
+
+ def visit_Extends(self, node, frame):
+ """Calls the extender."""
+ if not frame.toplevel:
self.fail("cannot use extend from a non top-level scope", node.lineno)
-
- # if the number of extends statements in general is zero so
- # far, we don't have to add a check if something extended
- # the template before this one.
- if self.extends_so_far > 0:
-
- # if we have a known extends we just add a template runtime
- # error into the generated code. We could catch that at compile
- # time too, but i welcome it not to confuse users by throwing the
- # same error at different times just "because we can".
- if not self.has_known_extends:
+
+ # if the number of extends statements in general is zero so
+ # far, we don't have to add a check if something extended
+ # the template before this one.
+ if self.extends_so_far > 0:
+
+ # if we have a known extends we just add a template runtime
+ # error into the generated code. We could catch that at compile
+ # time too, but i welcome it not to confuse users by throwing the
+ # same error at different times just "because we can".
+ if not self.has_known_extends:
self.writeline("if parent_template is not None:")
- self.indent()
+ self.indent()
self.writeline("raise TemplateRuntimeError(%r)" % "extended multiple times")
-
- # if we have a known extends already we don't need that code here
- # as we know that the template execution will end here.
- if self.has_known_extends:
- raise CompilerExit()
- else:
- self.outdent()
-
+
+ # if we have a known extends already we don't need that code here
+ # as we know that the template execution will end here.
+ if self.has_known_extends:
+ raise CompilerExit()
+ else:
+ self.outdent()
+
self.writeline("parent_template = environment.get_template(", node)
- self.visit(node.template, frame)
+ self.visit(node.template, frame)
self.write(", %r)" % self.name)
self.writeline(
"for name, parent_block in parent_template.blocks.%s():" % dict_item_iter
)
- self.indent()
+ self.indent()
self.writeline("context.blocks.setdefault(name, []).append(parent_block)")
- self.outdent()
-
- # if this extends statement was in the root level we can take
- # advantage of that information and simplify the generated code
- # in the top level from this point onwards
- if frame.rootlevel:
- self.has_known_extends = True
-
- # and now we have one more
- self.extends_so_far += 1
-
- def visit_Include(self, node, frame):
- """Handles includes."""
- if node.ignore_missing:
+ self.outdent()
+
+ # if this extends statement was in the root level we can take
+ # advantage of that information and simplify the generated code
+ # in the top level from this point onwards
+ if frame.rootlevel:
+ self.has_known_extends = True
+
+ # and now we have one more
+ self.extends_so_far += 1
+
+ def visit_Include(self, node, frame):
+ """Handles includes."""
+ if node.ignore_missing:
self.writeline("try:")
- self.indent()
-
+ self.indent()
+
func_name = "get_or_select_template"
- if isinstance(node.template, nodes.Const):
- if isinstance(node.template.value, string_types):
+ if isinstance(node.template, nodes.Const):
+ if isinstance(node.template.value, string_types):
func_name = "get_template"
- elif isinstance(node.template.value, (tuple, list)):
+ elif isinstance(node.template.value, (tuple, list)):
func_name = "select_template"
- elif isinstance(node.template, (nodes.Tuple, nodes.List)):
+ elif isinstance(node.template, (nodes.Tuple, nodes.List)):
func_name = "select_template"
-
+
self.writeline("template = environment.%s(" % func_name, node)
- self.visit(node.template, frame)
+ self.visit(node.template, frame)
self.write(", %r)" % self.name)
- if node.ignore_missing:
- self.outdent()
+ if node.ignore_missing:
+ self.outdent()
self.writeline("except TemplateNotFound:")
- self.indent()
+ self.indent()
self.writeline("pass")
- self.outdent()
+ self.outdent()
self.writeline("else:")
- self.indent()
-
- skip_event_yield = False
- if node.with_context:
+ self.indent()
+
+ skip_event_yield = False
+ if node.with_context:
loop = self.environment.is_async and "async for" or "for"
self.writeline(
"%s event in template.root_render_func("
"template.new_context(context.get_all(), True, "
"%s)):" % (loop, self.dump_local_context(frame))
)
- elif self.environment.is_async:
+ elif self.environment.is_async:
self.writeline(
"for event in (await "
"template._get_default_module_async())"
"._body_stream:"
)
- else:
- if supports_yield_from:
+ else:
+ if supports_yield_from:
self.writeline("yield from template._get_default_module()._body_stream")
- skip_event_yield = True
- else:
+ skip_event_yield = True
+ else:
self.writeline(
"for event in template._get_default_module()._body_stream:"
)
-
- if not skip_event_yield:
- self.indent()
+
+ if not skip_event_yield:
+ self.indent()
self.simple_write("event", frame)
- self.outdent()
-
- if node.ignore_missing:
- self.outdent()
-
- def visit_Import(self, node, frame):
- """Visit regular imports."""
+ self.outdent()
+
+ if node.ignore_missing:
+ self.outdent()
+
+ def visit_Import(self, node, frame):
+ """Visit regular imports."""
self.writeline("%s = " % frame.symbols.ref(node.target), node)
- if frame.toplevel:
+ if frame.toplevel:
self.write("context.vars[%r] = " % node.target)
- if self.environment.is_async:
+ if self.environment.is_async:
self.write("await ")
self.write("environment.get_template(")
- self.visit(node.template, frame)
+ self.visit(node.template, frame)
self.write(", %r)." % self.name)
- if node.with_context:
+ if node.with_context:
self.write(
"make_module%s(context.get_all(), True, %s)"
% (
@@ -992,23 +992,23 @@ class CodeGenerator(NodeVisitor):
self.dump_local_context(frame),
)
)
- elif self.environment.is_async:
+ elif self.environment.is_async:
self.write("_get_default_module_async()")
- else:
+ else:
self.write("_get_default_module()")
if frame.toplevel and not node.target.startswith("_"):
self.writeline("context.exported_vars.discard(%r)" % node.target)
-
- def visit_FromImport(self, node, frame):
- """Visit named imports."""
- self.newline(node)
+
+ def visit_FromImport(self, node, frame):
+ """Visit named imports."""
+ self.newline(node)
self.write(
"included_template = %senvironment.get_template("
% (self.environment.is_async and "await " or "")
)
- self.visit(node.template, frame)
+ self.visit(node.template, frame)
self.write(", %r)." % self.name)
- if node.with_context:
+ if node.with_context:
self.write(
"make_module%s(context.get_all(), True, %s)"
% (
@@ -1016,24 +1016,24 @@ class CodeGenerator(NodeVisitor):
self.dump_local_context(frame),
)
)
- elif self.environment.is_async:
+ elif self.environment.is_async:
self.write("_get_default_module_async()")
- else:
+ else:
self.write("_get_default_module()")
-
- var_names = []
- discarded_names = []
- for name in node.names:
- if isinstance(name, tuple):
- name, alias = name
- else:
- alias = name
+
+ var_names = []
+ discarded_names = []
+ for name in node.names:
+ if isinstance(name, tuple):
+ name, alias = name
+ else:
+ alias = name
self.writeline(
"%s = getattr(included_template, "
"%r, missing)" % (frame.symbols.ref(alias), name)
)
self.writeline("if %s is missing:" % frame.symbols.ref(alias))
- self.indent()
+ self.indent()
self.writeline(
"%s = undefined(%r %% "
"included_template.__name__, "
@@ -1046,241 +1046,241 @@ class CodeGenerator(NodeVisitor):
name,
)
)
- self.outdent()
- if frame.toplevel:
- var_names.append(alias)
+ self.outdent()
+ if frame.toplevel:
+ var_names.append(alias)
if not alias.startswith("_"):
- discarded_names.append(alias)
-
- if var_names:
- if len(var_names) == 1:
- name = var_names[0]
+ discarded_names.append(alias)
+
+ if var_names:
+ if len(var_names) == 1:
+ name = var_names[0]
self.writeline(
"context.vars[%r] = %s" % (name, frame.symbols.ref(name))
)
- else:
+ else:
self.writeline(
"context.vars.update({%s})"
% ", ".join(
"%r: %s" % (name, frame.symbols.ref(name)) for name in var_names
)
)
- if discarded_names:
- if len(discarded_names) == 1:
+ if discarded_names:
+ if len(discarded_names) == 1:
self.writeline("context.exported_vars.discard(%r)" % discarded_names[0])
- else:
+ else:
self.writeline(
"context.exported_vars.difference_"
"update((%s))" % ", ".join(imap(repr, discarded_names))
)
-
- def visit_For(self, node, frame):
- loop_frame = frame.inner()
- test_frame = frame.inner()
- else_frame = frame.inner()
-
- # try to figure out if we have an extended loop. An extended loop
- # is necessary if the loop is in recursive mode if the special loop
- # variable is accessed in the body.
+
+ def visit_For(self, node, frame):
+ loop_frame = frame.inner()
+ test_frame = frame.inner()
+ else_frame = frame.inner()
+
+ # try to figure out if we have an extended loop. An extended loop
+ # is necessary if the loop is in recursive mode if the special loop
+ # variable is accessed in the body.
extended_loop = node.recursive or "loop" in find_undeclared(
node.iter_child_nodes(only=("body",)), ("loop",)
)
-
- loop_ref = None
- if extended_loop:
+
+ loop_ref = None
+ if extended_loop:
loop_ref = loop_frame.symbols.declare_parameter("loop")
-
+
loop_frame.symbols.analyze_node(node, for_branch="body")
- if node.else_:
+ if node.else_:
else_frame.symbols.analyze_node(node, for_branch="else")
-
- if node.test:
- loop_filter_func = self.temporary_identifier()
+
+ if node.test:
+ loop_filter_func = self.temporary_identifier()
test_frame.symbols.analyze_node(node, for_branch="test")
self.writeline("%s(fiter):" % self.func(loop_filter_func), node.test)
- self.indent()
- self.enter_frame(test_frame)
+ self.indent()
+ self.enter_frame(test_frame)
self.writeline(self.environment.is_async and "async for " or "for ")
- self.visit(node.target, loop_frame)
+ self.visit(node.target, loop_frame)
self.write(" in ")
self.write(self.environment.is_async and "auto_aiter(fiter)" or "fiter")
self.write(":")
- self.indent()
+ self.indent()
self.writeline("if ", node.test)
- self.visit(node.test, test_frame)
+ self.visit(node.test, test_frame)
self.write(":")
- self.indent()
+ self.indent()
self.writeline("yield ")
- self.visit(node.target, loop_frame)
- self.outdent(3)
- self.leave_frame(test_frame, with_python_scope=True)
-
- # if we don't have an recursive loop we have to find the shadowed
- # variables at that point. Because loops can be nested but the loop
- # variable is a special one we have to enforce aliasing for it.
- if node.recursive:
+ self.visit(node.target, loop_frame)
+ self.outdent(3)
+ self.leave_frame(test_frame, with_python_scope=True)
+
+ # if we don't have an recursive loop we have to find the shadowed
+ # variables at that point. Because loops can be nested but the loop
+ # variable is a special one we have to enforce aliasing for it.
+ if node.recursive:
self.writeline(
"%s(reciter, loop_render_func, depth=0):" % self.func("loop"), node
)
- self.indent()
- self.buffer(loop_frame)
-
- # Use the same buffer for the else frame
- else_frame.buffer = loop_frame.buffer
-
- # make sure the loop variable is a special one and raise a template
- # assertion error if a loop tries to write to loop
- if extended_loop:
+ self.indent()
+ self.buffer(loop_frame)
+
+ # Use the same buffer for the else frame
+ else_frame.buffer = loop_frame.buffer
+
+ # make sure the loop variable is a special one and raise a template
+ # assertion error if a loop tries to write to loop
+ if extended_loop:
self.writeline("%s = missing" % loop_ref)
-
- for name in node.find_all(nodes.Name):
+
+ for name in node.find_all(nodes.Name):
if name.ctx == "store" and name.name == "loop":
self.fail(
"Can't assign to special loop variable in for-loop target",
name.lineno,
)
-
- if node.else_:
- iteration_indicator = self.temporary_identifier()
+
+ if node.else_:
+ iteration_indicator = self.temporary_identifier()
self.writeline("%s = 1" % iteration_indicator)
-
+
self.writeline(self.environment.is_async and "async for " or "for ", node)
- self.visit(node.target, loop_frame)
- if extended_loop:
- if self.environment.is_async:
+ self.visit(node.target, loop_frame)
+ if extended_loop:
+ if self.environment.is_async:
self.write(", %s in AsyncLoopContext(" % loop_ref)
- else:
+ else:
self.write(", %s in LoopContext(" % loop_ref)
- else:
+ else:
self.write(" in ")
-
- if node.test:
+
+ if node.test:
self.write("%s(" % loop_filter_func)
- if node.recursive:
+ if node.recursive:
self.write("reciter")
- else:
- if self.environment.is_async and not extended_loop:
+ else:
+ if self.environment.is_async and not extended_loop:
self.write("auto_aiter(")
- self.visit(node.iter, frame)
- if self.environment.is_async and not extended_loop:
+ self.visit(node.iter, frame)
+ if self.environment.is_async and not extended_loop:
self.write(")")
- if node.test:
+ if node.test:
self.write(")")
-
- if node.recursive:
+
+ if node.recursive:
self.write(", undefined, loop_render_func, depth):")
- else:
+ else:
self.write(extended_loop and ", undefined):" or ":")
-
- self.indent()
- self.enter_frame(loop_frame)
-
- self.blockvisit(node.body, loop_frame)
- if node.else_:
+
+ self.indent()
+ self.enter_frame(loop_frame)
+
+ self.blockvisit(node.body, loop_frame)
+ if node.else_:
self.writeline("%s = 0" % iteration_indicator)
- self.outdent()
+ self.outdent()
self.leave_frame(
loop_frame, with_python_scope=node.recursive and not node.else_
)
-
- if node.else_:
+
+ if node.else_:
self.writeline("if %s:" % iteration_indicator)
- self.indent()
- self.enter_frame(else_frame)
- self.blockvisit(node.else_, else_frame)
- self.leave_frame(else_frame)
- self.outdent()
-
- # if the node was recursive we have to return the buffer contents
- # and start the iteration code
- if node.recursive:
- self.return_buffer_contents(loop_frame)
- self.outdent()
- self.start_write(frame, node)
- if self.environment.is_async:
+ self.indent()
+ self.enter_frame(else_frame)
+ self.blockvisit(node.else_, else_frame)
+ self.leave_frame(else_frame)
+ self.outdent()
+
+ # if the node was recursive we have to return the buffer contents
+ # and start the iteration code
+ if node.recursive:
+ self.return_buffer_contents(loop_frame)
+ self.outdent()
+ self.start_write(frame, node)
+ if self.environment.is_async:
self.write("await ")
self.write("loop(")
- if self.environment.is_async:
+ if self.environment.is_async:
self.write("auto_aiter(")
- self.visit(node.iter, frame)
- if self.environment.is_async:
+ self.visit(node.iter, frame)
+ if self.environment.is_async:
self.write(")")
self.write(", loop)")
- self.end_write(frame)
-
- def visit_If(self, node, frame):
- if_frame = frame.soft()
+ self.end_write(frame)
+
+ def visit_If(self, node, frame):
+ if_frame = frame.soft()
self.writeline("if ", node)
- self.visit(node.test, if_frame)
+ self.visit(node.test, if_frame)
self.write(":")
- self.indent()
- self.blockvisit(node.body, if_frame)
- self.outdent()
- for elif_ in node.elif_:
+ self.indent()
+ self.blockvisit(node.body, if_frame)
+ self.outdent()
+ for elif_ in node.elif_:
self.writeline("elif ", elif_)
- self.visit(elif_.test, if_frame)
+ self.visit(elif_.test, if_frame)
self.write(":")
- self.indent()
- self.blockvisit(elif_.body, if_frame)
- self.outdent()
- if node.else_:
+ self.indent()
+ self.blockvisit(elif_.body, if_frame)
+ self.outdent()
+ if node.else_:
self.writeline("else:")
- self.indent()
- self.blockvisit(node.else_, if_frame)
- self.outdent()
-
- def visit_Macro(self, node, frame):
- macro_frame, macro_ref = self.macro_body(node, frame)
- self.newline()
- if frame.toplevel:
+ self.indent()
+ self.blockvisit(node.else_, if_frame)
+ self.outdent()
+
+ def visit_Macro(self, node, frame):
+ macro_frame, macro_ref = self.macro_body(node, frame)
+ self.newline()
+ if frame.toplevel:
if not node.name.startswith("_"):
self.write("context.exported_vars.add(%r)" % node.name)
self.writeline("context.vars[%r] = " % node.name)
self.write("%s = " % frame.symbols.ref(node.name))
- self.macro_def(macro_ref, macro_frame)
-
- def visit_CallBlock(self, node, frame):
- call_frame, macro_ref = self.macro_body(node, frame)
+ self.macro_def(macro_ref, macro_frame)
+
+ def visit_CallBlock(self, node, frame):
+ call_frame, macro_ref = self.macro_body(node, frame)
self.writeline("caller = ")
- self.macro_def(macro_ref, call_frame)
- self.start_write(frame, node)
- self.visit_Call(node.call, frame, forward_caller=True)
- self.end_write(frame)
-
- def visit_FilterBlock(self, node, frame):
- filter_frame = frame.inner()
- filter_frame.symbols.analyze_node(node)
- self.enter_frame(filter_frame)
- self.buffer(filter_frame)
- self.blockvisit(node.body, filter_frame)
- self.start_write(frame, node)
- self.visit_Filter(node.filter, filter_frame)
- self.end_write(frame)
- self.leave_frame(filter_frame)
-
- def visit_With(self, node, frame):
- with_frame = frame.inner()
- with_frame.symbols.analyze_node(node)
- self.enter_frame(with_frame)
+ self.macro_def(macro_ref, call_frame)
+ self.start_write(frame, node)
+ self.visit_Call(node.call, frame, forward_caller=True)
+ self.end_write(frame)
+
+ def visit_FilterBlock(self, node, frame):
+ filter_frame = frame.inner()
+ filter_frame.symbols.analyze_node(node)
+ self.enter_frame(filter_frame)
+ self.buffer(filter_frame)
+ self.blockvisit(node.body, filter_frame)
+ self.start_write(frame, node)
+ self.visit_Filter(node.filter, filter_frame)
+ self.end_write(frame)
+ self.leave_frame(filter_frame)
+
+ def visit_With(self, node, frame):
+ with_frame = frame.inner()
+ with_frame.symbols.analyze_node(node)
+ self.enter_frame(with_frame)
for target, expr in izip(node.targets, node.values):
- self.newline()
- self.visit(target, with_frame)
+ self.newline()
+ self.visit(target, with_frame)
self.write(" = ")
- self.visit(expr, frame)
- self.blockvisit(node.body, with_frame)
- self.leave_frame(with_frame)
-
- def visit_ExprStmt(self, node, frame):
- self.newline(node)
- self.visit(node.node, frame)
-
+ self.visit(expr, frame)
+ self.blockvisit(node.body, with_frame)
+ self.leave_frame(with_frame)
+
+ def visit_ExprStmt(self, node, frame):
+ self.newline(node)
+ self.visit(node.node, frame)
+
_FinalizeInfo = namedtuple("_FinalizeInfo", ("const", "src"))
#: The default finalize function if the environment isn't configured
#: with one. Or if the environment has one, this is called on that
#: function's output for constants.
_default_finalize = text_type
_finalize = None
-
+
def _make_finalize(self):
"""Build the finalize function to be used on constants and at
runtime. Cached so it's only created once for all output nodes.
@@ -1300,7 +1300,7 @@ class CodeGenerator(NodeVisitor):
finalize = default = self._default_finalize
src = None
- if self.environment.finalize:
+ if self.environment.finalize:
src = "environment.finalize("
env_finalize = self.environment.finalize
@@ -1356,9 +1356,9 @@ class CodeGenerator(NodeVisitor):
self.write("(escape if context.eval_ctx.autoescape else to_string)(")
elif frame.eval_ctx.autoescape:
self.write("escape(")
- else:
+ else:
self.write("to_string(")
-
+
if finalize.src is not None:
self.write(finalize.src)
@@ -1373,22 +1373,22 @@ class CodeGenerator(NodeVisitor):
def visit_Output(self, node, frame):
# If an extends is active, don't render outside a block.
- if frame.require_output_check:
+ if frame.require_output_check:
# A top-level extends is known to exist at compile time.
if self.has_known_extends:
return
self.writeline("if parent_template is None:")
- self.indent()
-
+ self.indent()
+
finalize = self._make_finalize()
- body = []
+ body = []
# Evaluate constants at compile time if possible. Each item in
# body will be either a list of static data or a node to be
# evaluated at runtime.
- for child in node.nodes:
- try:
+ for child in node.nodes:
+ try:
if not (
# If the finalize function requires runtime context,
# constants can't be evaluated at compile time.
@@ -1397,21 +1397,21 @@ class CodeGenerator(NodeVisitor):
# finalized anyway.
or isinstance(child, nodes.TemplateData)
):
- raise nodes.Impossible()
+ raise nodes.Impossible()
const = self._output_child_to_const(child, frame, finalize)
except (nodes.Impossible, Exception):
# The node was not constant and needs to be evaluated at
# runtime. Or another error was raised, which is easier
# to debug at runtime.
- body.append(child)
- continue
-
- if body and isinstance(body[-1], list):
- body[-1].append(const)
- else:
- body.append([const])
-
+ body.append(child)
+ continue
+
+ if body and isinstance(body[-1], list):
+ body[-1].append(const)
+ else:
+ body.append([const])
+
if frame.buffer is not None:
if len(body) == 1:
self.writeline("%s.append(" % frame.buffer)
@@ -1427,14 +1427,14 @@ class CodeGenerator(NodeVisitor):
if frame.buffer is None:
self.writeline("yield " + val)
- else:
+ else:
self.writeline(val + ",")
else:
if frame.buffer is None:
self.writeline("yield ", item)
- else:
+ else:
self.newline(item)
-
+
# A node to be evaluated at runtime.
self._output_child_pre(item, frame, finalize)
self.visit(item, frame)
@@ -1444,55 +1444,55 @@ class CodeGenerator(NodeVisitor):
self.write(",")
if frame.buffer is not None:
- self.outdent()
+ self.outdent()
self.writeline(")" if len(body) == 1 else "))")
-
+
if frame.require_output_check:
- self.outdent()
-
- def visit_Assign(self, node, frame):
- self.push_assign_tracking()
- self.newline(node)
- self.visit(node.target, frame)
+ self.outdent()
+
+ def visit_Assign(self, node, frame):
+ self.push_assign_tracking()
+ self.newline(node)
+ self.visit(node.target, frame)
self.write(" = ")
- self.visit(node.node, frame)
- self.pop_assign_tracking(frame)
-
- def visit_AssignBlock(self, node, frame):
- self.push_assign_tracking()
- block_frame = frame.inner()
- # This is a special case. Since a set block always captures we
- # will disable output checks. This way one can use set blocks
- # toplevel even in extended templates.
- block_frame.require_output_check = False
- block_frame.symbols.analyze_node(node)
- self.enter_frame(block_frame)
- self.buffer(block_frame)
- self.blockvisit(node.body, block_frame)
- self.newline(node)
- self.visit(node.target, frame)
+ self.visit(node.node, frame)
+ self.pop_assign_tracking(frame)
+
+ def visit_AssignBlock(self, node, frame):
+ self.push_assign_tracking()
+ block_frame = frame.inner()
+ # This is a special case. Since a set block always captures we
+ # will disable output checks. This way one can use set blocks
+ # toplevel even in extended templates.
+ block_frame.require_output_check = False
+ block_frame.symbols.analyze_node(node)
+ self.enter_frame(block_frame)
+ self.buffer(block_frame)
+ self.blockvisit(node.body, block_frame)
+ self.newline(node)
+ self.visit(node.target, frame)
self.write(" = (Markup if context.eval_ctx.autoescape else identity)(")
- if node.filter is not None:
- self.visit_Filter(node.filter, block_frame)
- else:
+ if node.filter is not None:
+ self.visit_Filter(node.filter, block_frame)
+ else:
self.write("concat(%s)" % block_frame.buffer)
self.write(")")
- self.pop_assign_tracking(frame)
- self.leave_frame(block_frame)
-
- # -- Expression Visitors
-
- def visit_Name(self, node, frame):
+ self.pop_assign_tracking(frame)
+ self.leave_frame(block_frame)
+
+ # -- Expression Visitors
+
+ def visit_Name(self, node, frame):
if node.ctx == "store" and frame.toplevel:
- if self._assign_stack:
- self._assign_stack[-1].add(node.name)
- ref = frame.symbols.ref(node.name)
-
- # If we are looking up a variable we might have to deal with the
- # case where it's undefined. We can skip that case if the load
- # instruction indicates a parameter which are always defined.
+ if self._assign_stack:
+ self._assign_stack[-1].add(node.name)
+ ref = frame.symbols.ref(node.name)
+
+ # If we are looking up a variable we might have to deal with the
+ # case where it's undefined. We can skip that case if the load
+ # instruction indicates a parameter which are always defined.
if node.ctx == "load":
- load = frame.symbols.find_load(ref)
+ load = frame.symbols.find_load(ref)
if not (
load is not None
and load[0] == VAR_LOAD_PARAMETER
@@ -1502,102 +1502,102 @@ class CodeGenerator(NodeVisitor):
"(undefined(name=%r) if %s is missing else %s)"
% (node.name, ref, ref)
)
- return
-
- self.write(ref)
-
- def visit_NSRef(self, node, frame):
- # NSRefs can only be used to store values; since they use the normal
- # `foo.bar` notation they will be parsed as a normal attribute access
- # when used anywhere but in a `set` context
- ref = frame.symbols.ref(node.name)
+ return
+
+ self.write(ref)
+
+ def visit_NSRef(self, node, frame):
+ # NSRefs can only be used to store values; since they use the normal
+ # `foo.bar` notation they will be parsed as a normal attribute access
+ # when used anywhere but in a `set` context
+ ref = frame.symbols.ref(node.name)
self.writeline("if not isinstance(%s, Namespace):" % ref)
- self.indent()
+ self.indent()
self.writeline(
"raise TemplateRuntimeError(%r)"
% "cannot assign attribute on non-namespace object"
)
- self.outdent()
+ self.outdent()
self.writeline("%s[%r]" % (ref, node.attr))
-
- def visit_Const(self, node, frame):
- val = node.as_const(frame.eval_ctx)
- if isinstance(val, float):
- self.write(str(val))
- else:
- self.write(repr(val))
-
- def visit_TemplateData(self, node, frame):
- try:
- self.write(repr(node.as_const(frame.eval_ctx)))
- except nodes.Impossible:
+
+ def visit_Const(self, node, frame):
+ val = node.as_const(frame.eval_ctx)
+ if isinstance(val, float):
+ self.write(str(val))
+ else:
+ self.write(repr(val))
+
+ def visit_TemplateData(self, node, frame):
+ try:
+ self.write(repr(node.as_const(frame.eval_ctx)))
+ except nodes.Impossible:
self.write(
"(Markup if context.eval_ctx.autoescape else identity)(%r)" % node.data
)
-
- def visit_Tuple(self, node, frame):
+
+ def visit_Tuple(self, node, frame):
self.write("(")
- idx = -1
- for idx, item in enumerate(node.items):
- if idx:
+ idx = -1
+ for idx, item in enumerate(node.items):
+ if idx:
self.write(", ")
- self.visit(item, frame)
+ self.visit(item, frame)
self.write(idx == 0 and ",)" or ")")
-
- def visit_List(self, node, frame):
+
+ def visit_List(self, node, frame):
self.write("[")
- for idx, item in enumerate(node.items):
- if idx:
+ for idx, item in enumerate(node.items):
+ if idx:
self.write(", ")
- self.visit(item, frame)
+ self.visit(item, frame)
self.write("]")
-
- def visit_Dict(self, node, frame):
+
+ def visit_Dict(self, node, frame):
self.write("{")
- for idx, item in enumerate(node.items):
- if idx:
+ for idx, item in enumerate(node.items):
+ if idx:
self.write(", ")
- self.visit(item.key, frame)
+ self.visit(item.key, frame)
self.write(": ")
- self.visit(item.value, frame)
+ self.visit(item.value, frame)
self.write("}")
-
+
def binop(operator, interceptable=True): # noqa: B902
- @optimizeconst
- def visitor(self, node, frame):
+ @optimizeconst
+ def visitor(self, node, frame):
if (
self.environment.sandboxed
and operator in self.environment.intercepted_binops
):
self.write("environment.call_binop(context, %r, " % operator)
- self.visit(node.left, frame)
+ self.visit(node.left, frame)
self.write(", ")
- self.visit(node.right, frame)
- else:
+ self.visit(node.right, frame)
+ else:
self.write("(")
- self.visit(node.left, frame)
+ self.visit(node.left, frame)
self.write(" %s " % operator)
- self.visit(node.right, frame)
+ self.visit(node.right, frame)
self.write(")")
- return visitor
-
+ return visitor
+
def uaop(operator, interceptable=True): # noqa: B902
- @optimizeconst
- def visitor(self, node, frame):
+ @optimizeconst
+ def visitor(self, node, frame):
if (
self.environment.sandboxed
and operator in self.environment.intercepted_unops
):
self.write("environment.call_unop(context, %r, " % operator)
- self.visit(node.node, frame)
- else:
+ self.visit(node.node, frame)
+ else:
self.write("(" + operator)
- self.visit(node.node, frame)
+ self.visit(node.node, frame)
self.write(")")
- return visitor
-
+ return visitor
+
visit_Add = binop("+")
visit_Sub = binop("-")
visit_Mul = binop("*")
@@ -1610,84 +1610,84 @@ class CodeGenerator(NodeVisitor):
visit_Pos = uaop("+")
visit_Neg = uaop("-")
visit_Not = uaop("not ", interceptable=False)
- del binop, uaop
-
- @optimizeconst
- def visit_Concat(self, node, frame):
- if frame.eval_ctx.volatile:
+ del binop, uaop
+
+ @optimizeconst
+ def visit_Concat(self, node, frame):
+ if frame.eval_ctx.volatile:
func_name = "(context.eval_ctx.volatile and markup_join or unicode_join)"
- elif frame.eval_ctx.autoescape:
+ elif frame.eval_ctx.autoescape:
func_name = "markup_join"
- else:
+ else:
func_name = "unicode_join"
self.write("%s((" % func_name)
- for arg in node.nodes:
- self.visit(arg, frame)
+ for arg in node.nodes:
+ self.visit(arg, frame)
self.write(", ")
self.write("))")
-
- @optimizeconst
- def visit_Compare(self, node, frame):
+
+ @optimizeconst
+ def visit_Compare(self, node, frame):
self.write("(")
- self.visit(node.expr, frame)
- for op in node.ops:
- self.visit(op, frame)
+ self.visit(node.expr, frame)
+ for op in node.ops:
+ self.visit(op, frame)
self.write(")")
-
- def visit_Operand(self, node, frame):
+
+ def visit_Operand(self, node, frame):
self.write(" %s " % operators[node.op])
- self.visit(node.expr, frame)
-
- @optimizeconst
- def visit_Getattr(self, node, frame):
+ self.visit(node.expr, frame)
+
+ @optimizeconst
+ def visit_Getattr(self, node, frame):
if self.environment.is_async:
self.write("(await auto_await(")
self.write("environment.getattr(")
- self.visit(node.node, frame)
+ self.visit(node.node, frame)
self.write(", %r)" % node.attr)
-
+
if self.environment.is_async:
self.write("))")
- @optimizeconst
- def visit_Getitem(self, node, frame):
- # slices bypass the environment getitem method.
- if isinstance(node.arg, nodes.Slice):
- self.visit(node.node, frame)
+ @optimizeconst
+ def visit_Getitem(self, node, frame):
+ # slices bypass the environment getitem method.
+ if isinstance(node.arg, nodes.Slice):
+ self.visit(node.node, frame)
self.write("[")
- self.visit(node.arg, frame)
+ self.visit(node.arg, frame)
self.write("]")
- else:
+ else:
if self.environment.is_async:
self.write("(await auto_await(")
self.write("environment.getitem(")
- self.visit(node.node, frame)
+ self.visit(node.node, frame)
self.write(", ")
- self.visit(node.arg, frame)
+ self.visit(node.arg, frame)
self.write(")")
-
+
if self.environment.is_async:
self.write("))")
- def visit_Slice(self, node, frame):
- if node.start is not None:
- self.visit(node.start, frame)
+ def visit_Slice(self, node, frame):
+ if node.start is not None:
+ self.visit(node.start, frame)
self.write(":")
- if node.stop is not None:
- self.visit(node.stop, frame)
- if node.step is not None:
+ if node.stop is not None:
+ self.visit(node.stop, frame)
+ if node.step is not None:
self.write(":")
- self.visit(node.step, frame)
-
- @optimizeconst
- def visit_Filter(self, node, frame):
- if self.environment.is_async:
+ self.visit(node.step, frame)
+
+ @optimizeconst
+ def visit_Filter(self, node, frame):
+ if self.environment.is_async:
self.write("await auto_await(")
self.write(self.filters[node.name] + "(")
- func = self.environment.filters.get(node.name)
- if func is None:
+ 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) is True:
self.write("context, ")
@@ -1695,39 +1695,39 @@ class CodeGenerator(NodeVisitor):
self.write("context.eval_ctx, ")
elif getattr(func, "environmentfilter", False) is True:
self.write("environment, ")
-
- # if the filter node is None we are inside a filter block
- # and want to write to the current buffer
- if node.node is not None:
- self.visit(node.node, frame)
- elif frame.eval_ctx.volatile:
+
+ # if the filter node is None we are inside a filter block
+ # and want to write to the current buffer
+ if node.node is not None:
+ self.visit(node.node, frame)
+ elif frame.eval_ctx.volatile:
self.write(
"(context.eval_ctx.autoescape and"
" Markup(concat(%s)) or concat(%s))" % (frame.buffer, frame.buffer)
)
- elif frame.eval_ctx.autoescape:
+ elif frame.eval_ctx.autoescape:
self.write("Markup(concat(%s))" % frame.buffer)
- else:
+ else:
self.write("concat(%s)" % frame.buffer)
- self.signature(node, frame)
+ self.signature(node, frame)
self.write(")")
- if self.environment.is_async:
+ if self.environment.is_async:
self.write(")")
-
- @optimizeconst
- def visit_Test(self, node, frame):
+
+ @optimizeconst
+ def visit_Test(self, node, frame):
self.write(self.tests[node.name] + "(")
- if node.name not in self.environment.tests:
+ if node.name not in self.environment.tests:
self.fail("no test named %r" % node.name, node.lineno)
- self.visit(node.node, frame)
- self.signature(node, frame)
+ self.visit(node.node, frame)
+ self.signature(node, frame)
self.write(")")
-
- @optimizeconst
- def visit_CondExpr(self, node, frame):
- def write_expr2():
- if node.expr2 is not None:
- return self.visit(node.expr2, frame)
+
+ @optimizeconst
+ def visit_CondExpr(self, node, frame):
+ def write_expr2():
+ if node.expr2 is not None:
+ return self.visit(node.expr2, frame)
self.write(
"cond_expr_undefined(%r)"
% (
@@ -1736,108 +1736,108 @@ class CodeGenerator(NodeVisitor):
"no else section was defined." % self.position(node)
)
)
-
+
self.write("(")
- self.visit(node.expr1, frame)
+ self.visit(node.expr1, frame)
self.write(" if ")
- self.visit(node.test, frame)
+ self.visit(node.test, frame)
self.write(" else ")
- write_expr2()
+ write_expr2()
self.write(")")
-
- @optimizeconst
- def visit_Call(self, node, frame, forward_caller=False):
- if self.environment.is_async:
+
+ @optimizeconst
+ def visit_Call(self, node, frame, forward_caller=False):
+ if self.environment.is_async:
self.write("await auto_await(")
- if self.environment.sandboxed:
+ if self.environment.sandboxed:
self.write("environment.call(context, ")
- else:
+ else:
self.write("context.call(")
- self.visit(node.node, frame)
+ self.visit(node.node, frame)
extra_kwargs = forward_caller and {"caller": "caller"} or None
- self.signature(node, frame, extra_kwargs)
+ self.signature(node, frame, extra_kwargs)
self.write(")")
- if self.environment.is_async:
+ if self.environment.is_async:
self.write(")")
-
- def visit_Keyword(self, node, frame):
+
+ def visit_Keyword(self, node, frame):
self.write(node.key + "=")
- self.visit(node.value, frame)
-
- # -- Unused nodes for extensions
-
- def visit_MarkSafe(self, node, frame):
+ self.visit(node.value, frame)
+
+ # -- Unused nodes for extensions
+
+ def visit_MarkSafe(self, node, frame):
self.write("Markup(")
- self.visit(node.expr, frame)
+ self.visit(node.expr, frame)
self.write(")")
-
- def visit_MarkSafeIfAutoescape(self, node, frame):
+
+ def visit_MarkSafeIfAutoescape(self, node, frame):
self.write("(context.eval_ctx.autoescape and Markup or identity)(")
- self.visit(node.expr, frame)
+ self.visit(node.expr, frame)
self.write(")")
-
- def visit_EnvironmentAttribute(self, node, frame):
+
+ def visit_EnvironmentAttribute(self, node, frame):
self.write("environment." + node.name)
-
- def visit_ExtensionAttribute(self, node, frame):
+
+ def visit_ExtensionAttribute(self, node, frame):
self.write("environment.extensions[%r].%s" % (node.identifier, node.name))
-
- def visit_ImportedName(self, node, frame):
- self.write(self.import_aliases[node.importname])
-
- def visit_InternalName(self, node, frame):
- self.write(node.name)
-
- def visit_ContextReference(self, node, frame):
+
+ def visit_ImportedName(self, node, frame):
+ self.write(self.import_aliases[node.importname])
+
+ def visit_InternalName(self, node, frame):
+ self.write(node.name)
+
+ def visit_ContextReference(self, node, frame):
self.write("context")
-
+
def visit_DerivedContextReference(self, node, frame):
self.write(self.derive_context(frame))
- def visit_Continue(self, node, frame):
+ def visit_Continue(self, node, frame):
self.writeline("continue", node)
-
- def visit_Break(self, node, frame):
+
+ def visit_Break(self, node, frame):
self.writeline("break", node)
-
- def visit_Scope(self, node, frame):
- scope_frame = frame.inner()
- scope_frame.symbols.analyze_node(node)
- self.enter_frame(scope_frame)
- self.blockvisit(node.body, scope_frame)
- self.leave_frame(scope_frame)
-
- def visit_OverlayScope(self, node, frame):
- ctx = self.temporary_identifier()
+
+ def visit_Scope(self, node, frame):
+ scope_frame = frame.inner()
+ scope_frame.symbols.analyze_node(node)
+ self.enter_frame(scope_frame)
+ self.blockvisit(node.body, scope_frame)
+ self.leave_frame(scope_frame)
+
+ def visit_OverlayScope(self, node, frame):
+ ctx = self.temporary_identifier()
self.writeline("%s = %s" % (ctx, self.derive_context(frame)))
self.writeline("%s.vars = " % ctx)
- self.visit(node.context, frame)
- self.push_context_reference(ctx)
-
- scope_frame = frame.inner(isolated=True)
- scope_frame.symbols.analyze_node(node)
- self.enter_frame(scope_frame)
- self.blockvisit(node.body, scope_frame)
- self.leave_frame(scope_frame)
- self.pop_context_reference()
-
- def visit_EvalContextModifier(self, node, frame):
- for keyword in node.options:
+ self.visit(node.context, frame)
+ self.push_context_reference(ctx)
+
+ scope_frame = frame.inner(isolated=True)
+ scope_frame.symbols.analyze_node(node)
+ self.enter_frame(scope_frame)
+ self.blockvisit(node.body, scope_frame)
+ self.leave_frame(scope_frame)
+ self.pop_context_reference()
+
+ def visit_EvalContextModifier(self, node, frame):
+ for keyword in node.options:
self.writeline("context.eval_ctx.%s = " % keyword.key)
- self.visit(keyword.value, frame)
- try:
- val = keyword.value.as_const(frame.eval_ctx)
- except nodes.Impossible:
- frame.eval_ctx.volatile = True
- else:
- setattr(frame.eval_ctx, keyword.key, val)
-
- def visit_ScopedEvalContextModifier(self, node, frame):
- old_ctx_name = self.temporary_identifier()
- saved_ctx = frame.eval_ctx.save()
+ self.visit(keyword.value, frame)
+ try:
+ val = keyword.value.as_const(frame.eval_ctx)
+ except nodes.Impossible:
+ frame.eval_ctx.volatile = True
+ else:
+ setattr(frame.eval_ctx, keyword.key, val)
+
+ def visit_ScopedEvalContextModifier(self, node, frame):
+ old_ctx_name = self.temporary_identifier()
+ saved_ctx = frame.eval_ctx.save()
self.writeline("%s = context.eval_ctx.save()" % old_ctx_name)
- self.visit_EvalContextModifier(node, frame)
- for child in node.body:
- self.visit(child, frame)
- frame.eval_ctx.revert(saved_ctx)
+ self.visit_EvalContextModifier(node, frame)
+ for child in node.body:
+ self.visit(child, frame)
+ frame.eval_ctx.revert(saved_ctx)
self.writeline("context.eval_ctx.revert(%s)" % old_ctx_name)
diff --git a/contrib/python/Jinja2/py2/jinja2/constants.py b/contrib/python/Jinja2/py2/jinja2/constants.py
index bf7f2ca721..1c39d8cf27 100644
--- a/contrib/python/Jinja2/py2/jinja2/constants.py
+++ b/contrib/python/Jinja2/py2/jinja2/constants.py
@@ -1,21 +1,21 @@
-# -*- coding: utf-8 -*-
-#: list of lorem ipsum words used by the lipsum() helper function
+# -*- coding: utf-8 -*-
+#: list of lorem ipsum words used by the lipsum() helper function
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
-diam dictum dictumst dignissim dis dolor donec dui duis egestas eget eleifend
-elementum elit enim erat eros est et etiam eu euismod facilisi facilisis fames
-faucibus felis fermentum feugiat fringilla fusce gravida habitant habitasse hac
-hendrerit hymenaeos iaculis id imperdiet in inceptos integer interdum ipsum
-justo lacinia lacus laoreet lectus leo libero ligula litora lobortis lorem
-luctus maecenas magna magnis malesuada massa mattis mauris metus mi molestie
-mollis montes morbi mus nam nascetur natoque nec neque netus nibh nisi nisl non
-nonummy nostra nulla nullam nunc odio orci ornare parturient pede pellentesque
-penatibus per pharetra phasellus placerat platea porta porttitor posuere
-potenti praesent pretium primis proin pulvinar purus quam quis quisque rhoncus
-ridiculus risus rutrum sagittis sapien scelerisque sed sem semper senectus sit
-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
+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
+diam dictum dictumst dignissim dis dolor donec dui duis egestas eget eleifend
+elementum elit enim erat eros est et etiam eu euismod facilisi facilisis fames
+faucibus felis fermentum feugiat fringilla fusce gravida habitant habitasse hac
+hendrerit hymenaeos iaculis id imperdiet in inceptos integer interdum ipsum
+justo lacinia lacus laoreet lectus leo libero ligula litora lobortis lorem
+luctus maecenas magna magnis malesuada massa mattis mauris metus mi molestie
+mollis montes morbi mus nam nascetur natoque nec neque netus nibh nisi nisl non
+nonummy nostra nulla nullam nunc odio orci ornare parturient pede pellentesque
+penatibus per pharetra phasellus placerat platea porta porttitor posuere
+potenti praesent pretium primis proin pulvinar purus quam quis quisque rhoncus
+ridiculus risus rutrum sagittis sapien scelerisque sed sem semper senectus sit
+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"""
diff --git a/contrib/python/Jinja2/py2/jinja2/debug.py b/contrib/python/Jinja2/py2/jinja2/debug.py
index 5d8aec31d0..70f7f66c64 100644
--- a/contrib/python/Jinja2/py2/jinja2/debug.py
+++ b/contrib/python/Jinja2/py2/jinja2/debug.py
@@ -1,19 +1,19 @@
-import sys
+import sys
from types import CodeType
-
+
from . import TemplateSyntaxError
from ._compat import PYPY
from .utils import internal_code
from .utils import missing
-
-
+
+
def rewrite_traceback_stack(source=None):
"""Rewrite the current exception to replace any tracebacks from
within compiled template code with tracebacks that look like they
came from the template source.
-
+
This must be called within an ``except`` block.
-
+
:param exc_info: A :meth:`sys.exc_info` tuple. If not provided,
the current ``exc_info`` is used.
:param source: For ``TemplateSyntaxError``, the original source if
@@ -21,18 +21,18 @@ def rewrite_traceback_stack(source=None):
:return: A :meth:`sys.exc_info` tuple that can be re-raised.
"""
exc_type, exc_value, tb = sys.exc_info()
-
+
if isinstance(exc_value, TemplateSyntaxError) and not exc_value.translated:
exc_value.translated = True
exc_value.source = source
-
+
try:
# Remove the old traceback on Python 3, otherwise the frames
# from the compiler still show up.
exc_value.with_traceback(None)
except AttributeError:
pass
-
+
# Outside of runtime, so the frame isn't executing template
# code, but it still needs to point at the template.
tb = fake_traceback(
@@ -41,9 +41,9 @@ def rewrite_traceback_stack(source=None):
else:
# Skip the frame for the render function.
tb = tb.tb_next
-
+
stack = []
-
+
# Build the stack of traceback object, replacing any in template
# code with the source file and line information.
while tb is not None:
@@ -52,33 +52,33 @@ def rewrite_traceback_stack(source=None):
if tb.tb_frame.f_code in internal_code:
tb = tb.tb_next
continue
-
+
template = tb.tb_frame.f_globals.get("__jinja_template__")
-
+
if template is not None:
lineno = template.get_corresponding_lineno(tb.tb_lineno)
fake_tb = fake_traceback(exc_value, tb, template.filename, lineno)
stack.append(fake_tb)
- else:
+ else:
stack.append(tb)
-
+
tb = tb.tb_next
-
+
tb_next = None
-
+
# Assign tb_next in reverse to avoid circular references.
for tb in reversed(stack):
tb_next = tb_set_next(tb, tb_next)
-
+
return exc_type, exc_value, tb_next
-
-
+
+
def fake_traceback(exc_value, tb, filename, lineno):
"""Produce a new traceback object that looks like it came from the
template source instead of the compiled code. The filename, line
number, and location name will point to the template, and the local
variables will be the current template context.
-
+
:param exc_value: The original exception to be re-raised to create
the new traceback.
:param tb: The original traceback to get the local variables and
@@ -91,9 +91,9 @@ def fake_traceback(exc_value, tb, filename, lineno):
# available at that point in the template.
locals = get_template_locals(tb.tb_frame.f_locals)
locals.pop("__jinja_exception__", None)
- else:
+ else:
locals = {}
-
+
globals = {
"__name__": filename,
"__file__": filename,
@@ -101,25 +101,25 @@ def fake_traceback(exc_value, tb, filename, lineno):
}
# Raise an exception at the correct line number.
code = compile("\n" * (lineno - 1) + "raise __jinja_exception__", filename, "exec")
-
+
# Build a new code object that points to the template file and
# replaces the location with a block name.
try:
location = "template"
-
+
if tb is not None:
function = tb.tb_frame.f_code.co_name
-
+
if function == "root":
location = "top-level template code"
elif function.startswith("block_"):
location = 'block "%s"' % function[6:]
-
+
# Collect arguments for the new code object. CodeType only
# accepts positional arguments, and arguments were inserted in
# new Python versions.
code_args = []
-
+
for attr in (
"argcount",
"posonlyargcount", # Python 3.8
@@ -142,88 +142,88 @@ def fake_traceback(exc_value, tb, filename, lineno):
# Replace with given value.
code_args.append(attr[1])
continue
-
+
try:
# Copy original value if it exists.
code_args.append(getattr(code, "co_" + attr))
except AttributeError:
# Some arguments were added later.
continue
-
+
code = CodeType(*code_args)
except Exception:
# Some environments such as Google App Engine don't support
# modifying code objects.
pass
-
+
# Execute the new code, which is guaranteed to raise, and return
# the new traceback without this frame.
try:
exec(code, globals, locals)
except BaseException:
return sys.exc_info()[2].tb_next
-
-
+
+
def get_template_locals(real_locals):
"""Based on the runtime locals, get the context that would be
available at that point in the template.
"""
# Start with the current template context.
ctx = real_locals.get("context")
-
- if ctx:
+
+ if ctx:
data = ctx.get_all().copy()
- else:
+ else:
data = {}
-
+
# Might be in a derived context that only sets local variables
# rather than pushing a context. Local variables follow the scheme
# l_depth_name. Find the highest-depth local that has a value for
# each name.
- local_overrides = {}
-
+ local_overrides = {}
+
for name, value in real_locals.items():
if not name.startswith("l_") or value is missing:
# Not a template variable, or no longer relevant.
- continue
+ continue
- try:
+ try:
_, depth, name = name.split("_", 2)
- depth = int(depth)
- except ValueError:
- continue
-
- cur_depth = local_overrides.get(name, (-1,))[0]
+ depth = int(depth)
+ except ValueError:
+ continue
- if cur_depth < depth:
- local_overrides[name] = (depth, value)
+ cur_depth = local_overrides.get(name, (-1,))[0]
+ if cur_depth < depth:
+ local_overrides[name] = (depth, value)
+
# Modify the context with any derived context.
for name, (_, value) in local_overrides.items():
- if value is missing:
+ if value is missing:
data.pop(name, None)
- else:
+ else:
data[name] = value
-
+
return data
-
-
+
+
if sys.version_info >= (3, 7):
# tb_next is directly assignable as of Python 3.7
def tb_set_next(tb, tb_next):
tb.tb_next = tb_next
return tb
-
-
+
+
elif PYPY:
# PyPy might have special support, and won't work with ctypes.
- try:
+ try:
import tputil
except ImportError:
# Without tproxy support, use the original traceback.
def tb_set_next(tb, tb_next):
return tb
-
+
else:
# With tproxy support, create a proxy around the traceback that
# returns the new tb_next.
@@ -231,38 +231,38 @@ elif PYPY:
def controller(op):
if op.opname == "__getattribute__" and op.args[0] == "tb_next":
return tb_next
-
+
return op.delegate()
-
+
return tputil.make_proxy(controller, obj=tb)
-
-
+
+
else:
# Use ctypes to assign tb_next at the C level since it's read-only
# from Python.
- import ctypes
-
+ import ctypes
+
class _CTraceback(ctypes.Structure):
_fields_ = [
# Extra PyObject slots when compiled with Py_TRACE_REFS.
("PyObject_HEAD", ctypes.c_byte * object().__sizeof__()),
# Only care about tb_next as an object, not a traceback.
("tb_next", ctypes.py_object),
- ]
-
+ ]
+
def tb_set_next(tb, tb_next):
c_tb = _CTraceback.from_address(id(tb))
-
+
# Clear out the old tb_next.
- if tb.tb_next is not None:
+ if tb.tb_next is not None:
c_tb_next = ctypes.py_object(tb.tb_next)
c_tb.tb_next = ctypes.py_object()
ctypes.pythonapi.Py_DecRef(c_tb_next)
-
+
# Assign the new tb_next.
if tb_next is not None:
c_tb_next = ctypes.py_object(tb_next)
ctypes.pythonapi.Py_IncRef(c_tb_next)
c_tb.tb_next = c_tb_next
-
+
return tb
diff --git a/contrib/python/Jinja2/py2/jinja2/defaults.py b/contrib/python/Jinja2/py2/jinja2/defaults.py
index 8e0e7d7710..31154b6b0e 100644
--- a/contrib/python/Jinja2/py2/jinja2/defaults.py
+++ b/contrib/python/Jinja2/py2/jinja2/defaults.py
@@ -1,4 +1,4 @@
-# -*- coding: utf-8 -*-
+# -*- coding: utf-8 -*-
from ._compat import range_type
from .filters import FILTERS as DEFAULT_FILTERS # noqa: F401
from .tests import TESTS as DEFAULT_TESTS # noqa: F401
@@ -6,34 +6,34 @@ from .utils import Cycler
from .utils import generate_lorem_ipsum
from .utils import Joiner
from .utils import Namespace
-
-# defaults for the parser / lexer
+
+# defaults for the parser / lexer
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
+LINE_STATEMENT_PREFIX = None
+LINE_COMMENT_PREFIX = None
+TRIM_BLOCKS = False
+LSTRIP_BLOCKS = False
NEWLINE_SEQUENCE = "\n"
-KEEP_TRAILING_NEWLINE = False
-
+KEEP_TRAILING_NEWLINE = False
+
# default filters, tests and namespace
-
-DEFAULT_NAMESPACE = {
+
+DEFAULT_NAMESPACE = {
"range": range_type,
"dict": dict,
"lipsum": generate_lorem_ipsum,
"cycler": Cycler,
"joiner": Joiner,
"namespace": Namespace,
-}
-
-# default policies
-DEFAULT_POLICIES = {
+}
+
+# default policies
+DEFAULT_POLICIES = {
"compiler.ascii_str": True,
"urlize.rel": "noopener",
"urlize.target": None,
@@ -41,4 +41,4 @@ DEFAULT_POLICIES = {
"json.dumps_function": None,
"json.dumps_kwargs": {"sort_keys": True},
"ext.i18n.trimmed": False,
-}
+}
diff --git a/contrib/python/Jinja2/py2/jinja2/environment.py b/contrib/python/Jinja2/py2/jinja2/environment.py
index 8430390eea..0fb5d37933 100644
--- a/contrib/python/Jinja2/py2/jinja2/environment.py
+++ b/contrib/python/Jinja2/py2/jinja2/environment.py
@@ -1,15 +1,15 @@
-# -*- coding: utf-8 -*-
+# -*- coding: utf-8 -*-
"""Classes for managing templates and their runtime and compile time
options.
-"""
-import os
-import sys
-import weakref
+"""
+import os
+import sys
+import weakref
from functools import partial
from functools import reduce
-
+
from markupsafe import Markup
-
+
from . import nodes
from ._compat import encode_filename
from ._compat import implements_iterator
@@ -58,70 +58,70 @@ from .utils import internalcode
from .utils import LRUCache
from .utils import missing
-# for direct template usage we have up to ten living environments
-_spontaneous_environments = LRUCache(10)
-
-
+# for direct template usage we have up to ten living environments
+_spontaneous_environments = LRUCache(10)
+
+
def get_spontaneous_environment(cls, *args):
"""Return a new spontaneous environment. A spontaneous environment
is used for templates created directly rather than through an
existing environment.
-
+
:param cls: Environment class to create.
:param args: Positional arguments passed to environment.
- """
+ """
key = (cls, args)
- try:
+ try:
return _spontaneous_environments[key]
except KeyError:
_spontaneous_environments[key] = env = cls(*args)
env.shared = True
- return env
-
-
-def create_cache(size):
- """Return the cache class for the given size."""
- if size == 0:
- return None
- if size < 0:
- return {}
- return LRUCache(size)
-
-
-def copy_cache(cache):
- """Create an empty copy of the given cache."""
- if cache is None:
- return None
- elif type(cache) is dict:
- return {}
- return LRUCache(cache.capacity)
-
-
-def load_extensions(environment, extensions):
- """Load the extensions from the list and bind it to the environment.
- Returns a dict of instantiated environments.
- """
- result = {}
- for extension in extensions:
- if isinstance(extension, string_types):
- extension = import_string(extension)
- result[extension.identifier] = extension(environment)
- return result
-
-
-def fail_for_missing_callable(string, name):
- msg = string % name
- if isinstance(name, Undefined):
- try:
- name._fail_with_undefined_error()
- except Exception as e:
+ return env
+
+
+def create_cache(size):
+ """Return the cache class for the given size."""
+ if size == 0:
+ return None
+ if size < 0:
+ return {}
+ return LRUCache(size)
+
+
+def copy_cache(cache):
+ """Create an empty copy of the given cache."""
+ if cache is None:
+ return None
+ elif type(cache) is dict:
+ return {}
+ return LRUCache(cache.capacity)
+
+
+def load_extensions(environment, extensions):
+ """Load the extensions from the list and bind it to the environment.
+ Returns a dict of instantiated environments.
+ """
+ result = {}
+ for extension in extensions:
+ if isinstance(extension, string_types):
+ extension = import_string(extension)
+ result[extension.identifier] = extension(environment)
+ return result
+
+
+def fail_for_missing_callable(string, name):
+ msg = string % name
+ if isinstance(name, Undefined):
+ try:
+ name._fail_with_undefined_error()
+ except Exception as e:
msg = "%s (%s; did you forget to quote the callable name?)" % (msg, e)
- raise TemplateRuntimeError(msg)
-
-
-def _environment_sanity_check(environment):
- """Perform a sanity check on the environment."""
+ raise TemplateRuntimeError(msg)
+
+
+def _environment_sanity_check(environment):
+ """Perform a sanity check on the environment."""
assert issubclass(
environment.undefined, Undefined
), "undefined must be a subclass of undefined because filters depend on it."
@@ -135,156 +135,156 @@ def _environment_sanity_check(environment):
"\r\n",
"\n",
), "newline_sequence set to unknown line ending string."
- return environment
-
-
-class Environment(object):
- r"""The core component of Jinja is the `Environment`. It contains
- important shared variables like configuration, filters, tests,
- globals and others. Instances of this class may be modified if
- they are not shared and if no template was loaded so far.
- Modifications on environments after the first template was loaded
- will lead to surprising effects and undefined behavior.
-
- Here are the possible initialization parameters:
-
- `block_start_string`
- The string marking the beginning of a block. Defaults to ``'{%'``.
-
- `block_end_string`
- The string marking the end of a block. Defaults to ``'%}'``.
-
- `variable_start_string`
- The string marking the beginning of a print statement.
- Defaults to ``'{{'``.
-
- `variable_end_string`
- The string marking the end of a print statement. Defaults to
- ``'}}'``.
-
- `comment_start_string`
- The string marking the beginning of a comment. Defaults to ``'{#'``.
-
- `comment_end_string`
- The string marking the end of a comment. Defaults to ``'#}'``.
-
- `line_statement_prefix`
- If given and a string, this will be used as prefix for line based
- statements. See also :ref:`line-statements`.
-
- `line_comment_prefix`
- If given and a string, this will be used as prefix for line based
- comments. See also :ref:`line-statements`.
-
- .. versionadded:: 2.2
-
- `trim_blocks`
- If this is set to ``True`` the first newline after a block is
- removed (block, not variable tag!). Defaults to `False`.
-
- `lstrip_blocks`
- If this is set to ``True`` leading spaces and tabs are stripped
- from the start of a line to a block. Defaults to `False`.
-
- `newline_sequence`
- The sequence that starts a newline. Must be one of ``'\r'``,
- ``'\n'`` or ``'\r\n'``. The default is ``'\n'`` which is a
- useful default for Linux and OS X systems as well as web
- applications.
-
- `keep_trailing_newline`
- Preserve the trailing newline when rendering templates.
- The default is ``False``, which causes a single newline,
- if present, to be stripped from the end of the template.
-
- .. versionadded:: 2.7
-
- `extensions`
- List of Jinja extensions to use. This can either be import paths
- as strings or extension classes. For more information have a
- look at :ref:`the extensions documentation <jinja-extensions>`.
-
- `optimized`
- should the optimizer be enabled? Default is ``True``.
-
- `undefined`
- :class:`Undefined` or a subclass of it that is used to represent
- undefined values in the template.
-
- `finalize`
- A callable that can be used to process the result of a variable
- expression before it is output. For example one can convert
- ``None`` implicitly into an empty string here.
-
- `autoescape`
- If set to ``True`` the XML/HTML autoescaping feature is enabled by
- default. For more details about autoescaping see
+ return environment
+
+
+class Environment(object):
+ r"""The core component of Jinja is the `Environment`. It contains
+ important shared variables like configuration, filters, tests,
+ globals and others. Instances of this class may be modified if
+ they are not shared and if no template was loaded so far.
+ Modifications on environments after the first template was loaded
+ will lead to surprising effects and undefined behavior.
+
+ Here are the possible initialization parameters:
+
+ `block_start_string`
+ The string marking the beginning of a block. Defaults to ``'{%'``.
+
+ `block_end_string`
+ The string marking the end of a block. Defaults to ``'%}'``.
+
+ `variable_start_string`
+ The string marking the beginning of a print statement.
+ Defaults to ``'{{'``.
+
+ `variable_end_string`
+ The string marking the end of a print statement. Defaults to
+ ``'}}'``.
+
+ `comment_start_string`
+ The string marking the beginning of a comment. Defaults to ``'{#'``.
+
+ `comment_end_string`
+ The string marking the end of a comment. Defaults to ``'#}'``.
+
+ `line_statement_prefix`
+ If given and a string, this will be used as prefix for line based
+ statements. See also :ref:`line-statements`.
+
+ `line_comment_prefix`
+ If given and a string, this will be used as prefix for line based
+ comments. See also :ref:`line-statements`.
+
+ .. versionadded:: 2.2
+
+ `trim_blocks`
+ If this is set to ``True`` the first newline after a block is
+ removed (block, not variable tag!). Defaults to `False`.
+
+ `lstrip_blocks`
+ If this is set to ``True`` leading spaces and tabs are stripped
+ from the start of a line to a block. Defaults to `False`.
+
+ `newline_sequence`
+ The sequence that starts a newline. Must be one of ``'\r'``,
+ ``'\n'`` or ``'\r\n'``. The default is ``'\n'`` which is a
+ useful default for Linux and OS X systems as well as web
+ applications.
+
+ `keep_trailing_newline`
+ Preserve the trailing newline when rendering templates.
+ The default is ``False``, which causes a single newline,
+ if present, to be stripped from the end of the template.
+
+ .. versionadded:: 2.7
+
+ `extensions`
+ List of Jinja extensions to use. This can either be import paths
+ as strings or extension classes. For more information have a
+ look at :ref:`the extensions documentation <jinja-extensions>`.
+
+ `optimized`
+ should the optimizer be enabled? Default is ``True``.
+
+ `undefined`
+ :class:`Undefined` or a subclass of it that is used to represent
+ undefined values in the template.
+
+ `finalize`
+ A callable that can be used to process the result of a variable
+ expression before it is output. For example one can convert
+ ``None`` implicitly into an empty string here.
+
+ `autoescape`
+ If set to ``True`` the XML/HTML autoescaping feature is enabled by
+ default. For more details about autoescaping see
:class:`~markupsafe.Markup`. As of Jinja 2.4 this can also
- be a callable that is passed the template name and has to
- return ``True`` or ``False`` depending on autoescape should be
- enabled by default.
-
- .. versionchanged:: 2.4
- `autoescape` can now be a function
-
- `loader`
- The template loader for this environment.
-
- `cache_size`
- The size of the cache. Per default this is ``400`` which means
- that if more than 400 templates are loaded the loader will clean
- out the least recently used template. If the cache size is set to
- ``0`` templates are recompiled all the time, if the cache size is
- ``-1`` the cache will not be cleaned.
-
- .. versionchanged:: 2.8
- The cache size was increased to 400 from a low 50.
-
- `auto_reload`
- Some loaders load templates from locations where the template
- sources may change (ie: file system or database). If
- ``auto_reload`` is set to ``True`` (default) every time a template is
- requested the loader checks if the source changed and if yes, it
- will reload the template. For higher performance it's possible to
- disable that.
-
- `bytecode_cache`
- If set to a bytecode cache object, this object will provide a
- cache for the internal Jinja bytecode so that templates don't
- have to be parsed if they were not changed.
-
- See :ref:`bytecode-cache` for more information.
-
- `enable_async`
- If set to true this enables async template execution which allows
- you to take advantage of newer Python features. This requires
- Python 3.6 or later.
- """
-
- #: if this environment is sandboxed. Modifying this variable won't make
- #: the environment sandboxed though. For a real sandboxed environment
- #: have a look at jinja2.sandbox. This flag alone controls the code
- #: generation by the compiler.
- sandboxed = False
-
- #: True if the environment is just an overlay
- overlayed = False
-
- #: the environment this environment is linked to if it is an overlay
- linked_to = None
-
- #: shared environments have this set to `True`. A shared environment
- #: must not be modified
- shared = False
-
- #: the class that is used for code generation. See
- #: :class:`~jinja2.compiler.CodeGenerator` for more information.
- code_generator_class = CodeGenerator
-
- #: the context class thatis used for templates. See
- #: :class:`~jinja2.runtime.Context` for more information.
- context_class = Context
-
+ be a callable that is passed the template name and has to
+ return ``True`` or ``False`` depending on autoescape should be
+ enabled by default.
+
+ .. versionchanged:: 2.4
+ `autoescape` can now be a function
+
+ `loader`
+ The template loader for this environment.
+
+ `cache_size`
+ The size of the cache. Per default this is ``400`` which means
+ that if more than 400 templates are loaded the loader will clean
+ out the least recently used template. If the cache size is set to
+ ``0`` templates are recompiled all the time, if the cache size is
+ ``-1`` the cache will not be cleaned.
+
+ .. versionchanged:: 2.8
+ The cache size was increased to 400 from a low 50.
+
+ `auto_reload`
+ Some loaders load templates from locations where the template
+ sources may change (ie: file system or database). If
+ ``auto_reload`` is set to ``True`` (default) every time a template is
+ requested the loader checks if the source changed and if yes, it
+ will reload the template. For higher performance it's possible to
+ disable that.
+
+ `bytecode_cache`
+ If set to a bytecode cache object, this object will provide a
+ cache for the internal Jinja bytecode so that templates don't
+ have to be parsed if they were not changed.
+
+ See :ref:`bytecode-cache` for more information.
+
+ `enable_async`
+ If set to true this enables async template execution which allows
+ you to take advantage of newer Python features. This requires
+ Python 3.6 or later.
+ """
+
+ #: if this environment is sandboxed. Modifying this variable won't make
+ #: the environment sandboxed though. For a real sandboxed environment
+ #: have a look at jinja2.sandbox. This flag alone controls the code
+ #: generation by the compiler.
+ sandboxed = False
+
+ #: True if the environment is just an overlay
+ overlayed = False
+
+ #: the environment this environment is linked to if it is an overlay
+ linked_to = None
+
+ #: shared environments have this set to `True`. A shared environment
+ #: must not be modified
+ shared = False
+
+ #: the class that is used for code generation. See
+ #: :class:`~jinja2.compiler.CodeGenerator` for more information.
+ code_generator_class = CodeGenerator
+
+ #: the context class thatis used for templates. See
+ #: :class:`~jinja2.runtime.Context` for more information.
+ context_class = Context
+
def __init__(
self,
block_start_string=BLOCK_START_STRING,
@@ -310,78 +310,78 @@ class Environment(object):
bytecode_cache=None,
enable_async=False,
):
- # !!Important notice!!
- # The constructor accepts quite a few arguments that should be
- # passed by keyword rather than position. However it's important to
- # not change the order of arguments because it's used at least
- # internally in those cases:
- # - spontaneous environments (i18n extension and Template)
- # - unittests
- # If parameter changes are required only add parameters at the end
- # and don't change the arguments (or the defaults!) of the arguments
- # existing already.
-
- # lexer / parser information
- self.block_start_string = block_start_string
- self.block_end_string = block_end_string
- self.variable_start_string = variable_start_string
- self.variable_end_string = variable_end_string
- self.comment_start_string = comment_start_string
- self.comment_end_string = comment_end_string
- self.line_statement_prefix = line_statement_prefix
- self.line_comment_prefix = line_comment_prefix
- self.trim_blocks = trim_blocks
- self.lstrip_blocks = lstrip_blocks
- self.newline_sequence = newline_sequence
- self.keep_trailing_newline = keep_trailing_newline
-
- # runtime information
- self.undefined = undefined
- self.optimized = optimized
- self.finalize = finalize
- self.autoescape = autoescape
-
- # defaults
- self.filters = DEFAULT_FILTERS.copy()
- self.tests = DEFAULT_TESTS.copy()
- self.globals = DEFAULT_NAMESPACE.copy()
-
- # set the loader provided
- self.loader = loader
- self.cache = create_cache(cache_size)
- self.bytecode_cache = bytecode_cache
- self.auto_reload = auto_reload
-
- # configurable policies
- self.policies = DEFAULT_POLICIES.copy()
-
- # load extensions
- self.extensions = load_extensions(self, extensions)
-
- self.enable_async = enable_async
- self.is_async = self.enable_async and have_async_gen
+ # !!Important notice!!
+ # The constructor accepts quite a few arguments that should be
+ # passed by keyword rather than position. However it's important to
+ # not change the order of arguments because it's used at least
+ # internally in those cases:
+ # - spontaneous environments (i18n extension and Template)
+ # - unittests
+ # If parameter changes are required only add parameters at the end
+ # and don't change the arguments (or the defaults!) of the arguments
+ # existing already.
+
+ # lexer / parser information
+ self.block_start_string = block_start_string
+ self.block_end_string = block_end_string
+ self.variable_start_string = variable_start_string
+ self.variable_end_string = variable_end_string
+ self.comment_start_string = comment_start_string
+ self.comment_end_string = comment_end_string
+ self.line_statement_prefix = line_statement_prefix
+ self.line_comment_prefix = line_comment_prefix
+ self.trim_blocks = trim_blocks
+ self.lstrip_blocks = lstrip_blocks
+ self.newline_sequence = newline_sequence
+ self.keep_trailing_newline = keep_trailing_newline
+
+ # runtime information
+ self.undefined = undefined
+ self.optimized = optimized
+ self.finalize = finalize
+ self.autoescape = autoescape
+
+ # defaults
+ self.filters = DEFAULT_FILTERS.copy()
+ self.tests = DEFAULT_TESTS.copy()
+ self.globals = DEFAULT_NAMESPACE.copy()
+
+ # set the loader provided
+ self.loader = loader
+ self.cache = create_cache(cache_size)
+ self.bytecode_cache = bytecode_cache
+ self.auto_reload = auto_reload
+
+ # configurable policies
+ self.policies = DEFAULT_POLICIES.copy()
+
+ # load extensions
+ self.extensions = load_extensions(self, extensions)
+
+ self.enable_async = enable_async
+ self.is_async = self.enable_async and have_async_gen
if self.is_async:
# runs patch_all() to enable async support
from . import asyncsupport # noqa: F401
-
- _environment_sanity_check(self)
-
- def add_extension(self, extension):
- """Adds an extension after the environment was created.
-
- .. versionadded:: 2.5
- """
- self.extensions.update(load_extensions(self, [extension]))
-
- def extend(self, **attributes):
- """Add the items to the instance of the environment if they do not exist
- yet. This is used by :ref:`extensions <writing-extensions>` to register
- callbacks and configuration values without breaking inheritance.
- """
- for key, value in iteritems(attributes):
- if not hasattr(self, key):
- setattr(self, key, value)
-
+
+ _environment_sanity_check(self)
+
+ def add_extension(self, extension):
+ """Adds an extension after the environment was created.
+
+ .. versionadded:: 2.5
+ """
+ self.extensions.update(load_extensions(self, [extension]))
+
+ def extend(self, **attributes):
+ """Add the items to the instance of the environment if they do not exist
+ yet. This is used by :ref:`extensions <writing-extensions>` to register
+ callbacks and configuration values without breaking inheritance.
+ """
+ for key, value in iteritems(attributes):
+ if not hasattr(self, key):
+ setattr(self, key, value)
+
def overlay(
self,
block_start_string=missing,
@@ -404,185 +404,185 @@ class Environment(object):
auto_reload=missing,
bytecode_cache=missing,
):
- """Create a new overlay environment that shares all the data with the
- current environment except for cache and the overridden attributes.
- Extensions cannot be removed for an overlayed environment. An overlayed
- environment automatically gets all the extensions of the environment it
- is linked to plus optional extra extensions.
-
- Creating overlays should happen after the initial environment was set
- up completely. Not all attributes are truly linked, some are just
- copied over so modifications on the original environment may not shine
- through.
- """
- args = dict(locals())
+ """Create a new overlay environment that shares all the data with the
+ current environment except for cache and the overridden attributes.
+ Extensions cannot be removed for an overlayed environment. An overlayed
+ environment automatically gets all the extensions of the environment it
+ is linked to plus optional extra extensions.
+
+ Creating overlays should happen after the initial environment was set
+ up completely. Not all attributes are truly linked, some are just
+ copied over so modifications on the original environment may not shine
+ through.
+ """
+ args = dict(locals())
del args["self"], args["cache_size"], args["extensions"]
-
- rv = object.__new__(self.__class__)
- rv.__dict__.update(self.__dict__)
- rv.overlayed = True
- rv.linked_to = self
-
- for key, value in iteritems(args):
- if value is not missing:
- setattr(rv, key, value)
-
- if cache_size is not missing:
- rv.cache = create_cache(cache_size)
- else:
- rv.cache = copy_cache(self.cache)
-
- rv.extensions = {}
- for key, value in iteritems(self.extensions):
- rv.extensions[key] = value.bind(rv)
- if extensions is not missing:
- rv.extensions.update(load_extensions(rv, extensions))
-
- return _environment_sanity_check(rv)
-
- lexer = property(get_lexer, doc="The lexer for this environment.")
-
- def iter_extensions(self):
- """Iterates over the extensions by priority."""
+
+ rv = object.__new__(self.__class__)
+ rv.__dict__.update(self.__dict__)
+ rv.overlayed = True
+ rv.linked_to = self
+
+ for key, value in iteritems(args):
+ if value is not missing:
+ setattr(rv, key, value)
+
+ if cache_size is not missing:
+ rv.cache = create_cache(cache_size)
+ else:
+ rv.cache = copy_cache(self.cache)
+
+ rv.extensions = {}
+ for key, value in iteritems(self.extensions):
+ rv.extensions[key] = value.bind(rv)
+ if extensions is not missing:
+ rv.extensions.update(load_extensions(rv, extensions))
+
+ return _environment_sanity_check(rv)
+
+ lexer = property(get_lexer, doc="The lexer for this environment.")
+
+ def iter_extensions(self):
+ """Iterates over the extensions by priority."""
return iter(sorted(self.extensions.values(), key=lambda x: x.priority))
-
- def getitem(self, obj, argument):
- """Get an item or attribute of an object but prefer the item."""
- try:
- return obj[argument]
- except (AttributeError, TypeError, LookupError):
- if isinstance(argument, string_types):
- try:
- attr = str(argument)
- except Exception:
- pass
- else:
- try:
- return getattr(obj, attr)
- except AttributeError:
- pass
- return self.undefined(obj=obj, name=argument)
-
- def getattr(self, obj, attribute):
- """Get an item or attribute of an object but prefer the attribute.
- Unlike :meth:`getitem` the attribute *must* be a bytestring.
- """
- try:
- return getattr(obj, attribute)
- except AttributeError:
- pass
- try:
- return obj[attribute]
- except (TypeError, LookupError, AttributeError):
- return self.undefined(obj=obj, name=attribute)
-
+
+ def getitem(self, obj, argument):
+ """Get an item or attribute of an object but prefer the item."""
+ try:
+ return obj[argument]
+ except (AttributeError, TypeError, LookupError):
+ if isinstance(argument, string_types):
+ try:
+ attr = str(argument)
+ except Exception:
+ pass
+ else:
+ try:
+ return getattr(obj, attr)
+ except AttributeError:
+ pass
+ return self.undefined(obj=obj, name=argument)
+
+ def getattr(self, obj, attribute):
+ """Get an item or attribute of an object but prefer the attribute.
+ Unlike :meth:`getitem` the attribute *must* be a bytestring.
+ """
+ try:
+ return getattr(obj, attribute)
+ except AttributeError:
+ pass
+ try:
+ return obj[attribute]
+ except (TypeError, LookupError, AttributeError):
+ return self.undefined(obj=obj, name=attribute)
+
def call_filter(
self, name, value, args=None, kwargs=None, context=None, eval_ctx=None
):
- """Invokes a filter on a value the same way the compiler does it.
-
- Note that on Python 3 this might return a coroutine in case the
- filter is running from an environment in async mode and the filter
- supports async execution. It's your responsibility to await this
- if needed.
-
- .. versionadded:: 2.7
- """
- func = self.filters.get(name)
- if func is None:
+ """Invokes a filter on a value the same way the compiler does it.
+
+ Note that on Python 3 this might return a coroutine in case the
+ filter is running from an environment in async mode and the filter
+ supports async execution. It's your responsibility to await this
+ if needed.
+
+ .. versionadded:: 2.7
+ """
+ func = self.filters.get(name)
+ if func is None:
fail_for_missing_callable("no filter named %r", name)
- args = [value] + list(args or ())
+ args = [value] + list(args or ())
if getattr(func, "contextfilter", False) is True:
- if context is None:
+ if context is None:
raise TemplateRuntimeError(
"Attempted to invoke context filter without context"
)
- args.insert(0, context)
+ args.insert(0, context)
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)
+ 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) is True:
- args.insert(0, self)
- return func(*args, **(kwargs or {}))
-
- def call_test(self, name, value, args=None, kwargs=None):
- """Invokes a test on a value the same way the compiler does it.
-
- .. versionadded:: 2.7
- """
- func = self.tests.get(name)
- if func is None:
+ args.insert(0, self)
+ return func(*args, **(kwargs or {}))
+
+ def call_test(self, name, value, args=None, kwargs=None):
+ """Invokes a test on a value the same way the compiler does it.
+
+ .. versionadded:: 2.7
+ """
+ func = self.tests.get(name)
+ if func is None:
fail_for_missing_callable("no test named %r", name)
- return func(value, *(args or ()), **(kwargs or {}))
-
- @internalcode
- def parse(self, source, name=None, filename=None):
- """Parse the sourcecode and return the abstract syntax tree. This
- tree of nodes is used by the compiler to convert the template into
- executable source- or bytecode. This is useful for debugging or to
- extract information from templates.
-
+ return func(value, *(args or ()), **(kwargs or {}))
+
+ @internalcode
+ def parse(self, source, name=None, filename=None):
+ """Parse the sourcecode and return the abstract syntax tree. This
+ tree of nodes is used by the compiler to convert the template into
+ executable source- or bytecode. This is useful for debugging or to
+ extract information from templates.
+
If you are :ref:`developing Jinja extensions <writing-extensions>`
- this gives you a good overview of the node tree generated.
- """
- try:
- return self._parse(source, name, filename)
- except TemplateSyntaxError:
+ this gives you a good overview of the node tree generated.
+ """
+ try:
+ return self._parse(source, name, filename)
+ except TemplateSyntaxError:
self.handle_exception(source=source)
-
- def _parse(self, source, name, filename):
- """Internal parsing function used by `parse` and `compile`."""
- return Parser(self, source, name, encode_filename(filename)).parse()
-
- def lex(self, source, name=None, filename=None):
- """Lex the given sourcecode and return a generator that yields
- tokens as tuples in the form ``(lineno, token_type, value)``.
- This can be useful for :ref:`extension development <writing-extensions>`
- and debugging templates.
-
- This does not perform preprocessing. If you want the preprocessing
- of the extensions to be applied you have to filter source through
- the :meth:`preprocess` method.
- """
- source = text_type(source)
- try:
- return self.lexer.tokeniter(source, name, filename)
- except TemplateSyntaxError:
+
+ def _parse(self, source, name, filename):
+ """Internal parsing function used by `parse` and `compile`."""
+ return Parser(self, source, name, encode_filename(filename)).parse()
+
+ def lex(self, source, name=None, filename=None):
+ """Lex the given sourcecode and return a generator that yields
+ tokens as tuples in the form ``(lineno, token_type, value)``.
+ This can be useful for :ref:`extension development <writing-extensions>`
+ and debugging templates.
+
+ This does not perform preprocessing. If you want the preprocessing
+ of the extensions to be applied you have to filter source through
+ the :meth:`preprocess` method.
+ """
+ source = text_type(source)
+ try:
+ return self.lexer.tokeniter(source, name, filename)
+ except TemplateSyntaxError:
self.handle_exception(source=source)
-
- def preprocess(self, source, name=None, filename=None):
- """Preprocesses the source with all extensions. This is automatically
- called for all parsing and compiling methods but *not* for :meth:`lex`
- because there you usually only want the actual source tokenized.
- """
+
+ def preprocess(self, source, name=None, filename=None):
+ """Preprocesses the source with all extensions. This is automatically
+ called for all parsing and compiling methods but *not* for :meth:`lex`
+ because there you usually only want the actual source tokenized.
+ """
return reduce(
lambda s, e: e.preprocess(s, name, filename),
self.iter_extensions(),
text_type(source),
)
-
- def _tokenize(self, source, name, filename=None, state=None):
- """Called by the parser to do the preprocessing and filtering
- for all the extensions. Returns a :class:`~jinja2.lexer.TokenStream`.
- """
- source = self.preprocess(source, name, filename)
- stream = self.lexer.tokenize(source, name, filename, state)
- for ext in self.iter_extensions():
- stream = ext.filter_stream(stream)
- if not isinstance(stream, TokenStream):
- stream = TokenStream(stream, name, filename)
- return stream
-
- def _generate(self, source, name, filename, defer_init=False):
- """Internal hook that can be overridden to hook a different generate
- method in.
-
- .. versionadded:: 2.5
- """
+
+ def _tokenize(self, source, name, filename=None, state=None):
+ """Called by the parser to do the preprocessing and filtering
+ for all the extensions. Returns a :class:`~jinja2.lexer.TokenStream`.
+ """
+ source = self.preprocess(source, name, filename)
+ stream = self.lexer.tokenize(source, name, filename, state)
+ for ext in self.iter_extensions():
+ stream = ext.filter_stream(stream)
+ if not isinstance(stream, TokenStream):
+ stream = TokenStream(stream, name, filename)
+ return stream
+
+ def _generate(self, source, name, filename, defer_init=False):
+ """Internal hook that can be overridden to hook a different generate
+ method in.
+
+ .. versionadded:: 2.5
+ """
return generate(
source,
self,
@@ -591,96 +591,96 @@ class Environment(object):
defer_init=defer_init,
optimized=self.optimized,
)
-
- def _compile(self, source, filename):
- """Internal hook that can be overridden to hook a different compile
- method in.
-
- .. versionadded:: 2.5
- """
+
+ def _compile(self, source, filename):
+ """Internal hook that can be overridden to hook a different compile
+ method in.
+
+ .. versionadded:: 2.5
+ """
return compile(source, filename, "exec")
-
- @internalcode
+
+ @internalcode
def compile(self, source, name=None, filename=None, raw=False, defer_init=False):
- """Compile a node or template source code. The `name` parameter is
- the load name of the template after it was joined using
- :meth:`join_path` if necessary, not the filename on the file system.
- the `filename` parameter is the estimated filename of the template on
- the file system. If the template came from a database or memory this
- can be omitted.
-
- The return value of this method is a python code object. If the `raw`
- parameter is `True` the return value will be a string with python
- code equivalent to the bytecode returned otherwise. This method is
- mainly used internally.
-
- `defer_init` is use internally to aid the module code generator. This
- causes the generated code to be able to import without the global
- environment variable to be set.
-
- .. versionadded:: 2.4
- `defer_init` parameter added.
- """
- source_hint = None
- try:
- if isinstance(source, string_types):
- source_hint = source
- source = self._parse(source, name, filename)
+ """Compile a node or template source code. The `name` parameter is
+ the load name of the template after it was joined using
+ :meth:`join_path` if necessary, not the filename on the file system.
+ the `filename` parameter is the estimated filename of the template on
+ the file system. If the template came from a database or memory this
+ can be omitted.
+
+ The return value of this method is a python code object. If the `raw`
+ parameter is `True` the return value will be a string with python
+ code equivalent to the bytecode returned otherwise. This method is
+ mainly used internally.
+
+ `defer_init` is use internally to aid the module code generator. This
+ causes the generated code to be able to import without the global
+ environment variable to be set.
+
+ .. versionadded:: 2.4
+ `defer_init` parameter added.
+ """
+ source_hint = None
+ try:
+ if isinstance(source, string_types):
+ source_hint = source
+ source = self._parse(source, name, filename)
source = self._generate(source, name, filename, defer_init=defer_init)
- if raw:
- return source
- if filename is None:
+ if raw:
+ return source
+ if filename is None:
filename = "<template>"
- else:
- filename = encode_filename(filename)
- return self._compile(source, filename)
- except TemplateSyntaxError:
+ else:
+ filename = encode_filename(filename)
+ return self._compile(source, filename)
+ except TemplateSyntaxError:
self.handle_exception(source=source_hint)
-
- def compile_expression(self, source, undefined_to_none=True):
- """A handy helper method that returns a callable that accepts keyword
- arguments that appear as variables in the expression. If called it
- returns the result of the expression.
-
- This is useful if applications want to use the same rules as Jinja
- in template "configuration files" or similar situations.
-
- Example usage:
-
- >>> env = Environment()
- >>> expr = env.compile_expression('foo == 42')
- >>> expr(foo=23)
- False
- >>> expr(foo=42)
- True
-
- Per default the return value is converted to `None` if the
- expression returns an undefined value. This can be changed
- by setting `undefined_to_none` to `False`.
-
- >>> env.compile_expression('var')() is None
- True
- >>> env.compile_expression('var', undefined_to_none=False)()
- Undefined
-
- .. versionadded:: 2.1
- """
+
+ def compile_expression(self, source, undefined_to_none=True):
+ """A handy helper method that returns a callable that accepts keyword
+ arguments that appear as variables in the expression. If called it
+ returns the result of the expression.
+
+ This is useful if applications want to use the same rules as Jinja
+ in template "configuration files" or similar situations.
+
+ Example usage:
+
+ >>> env = Environment()
+ >>> expr = env.compile_expression('foo == 42')
+ >>> expr(foo=23)
+ False
+ >>> expr(foo=42)
+ True
+
+ Per default the return value is converted to `None` if the
+ expression returns an undefined value. This can be changed
+ by setting `undefined_to_none` to `False`.
+
+ >>> env.compile_expression('var')() is None
+ True
+ >>> env.compile_expression('var', undefined_to_none=False)()
+ Undefined
+
+ .. versionadded:: 2.1
+ """
parser = Parser(self, source, state="variable")
- try:
- expr = parser.parse_expression()
- if not parser.stream.eos:
+ try:
+ expr = parser.parse_expression()
+ if not parser.stream.eos:
raise TemplateSyntaxError(
"chunk after expression", parser.stream.current.lineno, None, None
)
- expr.set_environment(self)
- except TemplateSyntaxError:
+ expr.set_environment(self)
+ except TemplateSyntaxError:
if sys.exc_info() is not None:
self.handle_exception(source=source)
body = [nodes.Assign(nodes.Name("result", "store"), expr, lineno=1)]
- template = self.from_string(nodes.Template(body, lineno=1))
- return TemplateExpression(template, undefined_to_none)
-
+ template = self.from_string(nodes.Template(body, lineno=1))
+ return TemplateExpression(template, undefined_to_none)
+
def compile_templates(
self,
target,
@@ -691,37 +691,37 @@ class Environment(object):
ignore_errors=True,
py_compile=False,
):
- """Finds all the templates the loader can find, compiles them
- and stores them in `target`. If `zip` is `None`, instead of in a
- zipfile, the templates will be stored in a directory.
- By default a deflate zip algorithm is used. To switch to
- the stored algorithm, `zip` can be set to ``'stored'``.
-
- `extensions` and `filter_func` are passed to :meth:`list_templates`.
- Each template returned will be compiled to the target folder or
- zipfile.
-
- By default template compilation errors are ignored. In case a
- log function is provided, errors are logged. If you want template
- syntax errors to abort the compilation you can set `ignore_errors`
- to `False` and you will get an exception on syntax errors.
-
- If `py_compile` is set to `True` .pyc files will be written to the
- target instead of standard .py files. This flag does not do anything
- on pypy and Python 3 where pyc files are not picked up by itself and
- don't give much benefit.
-
- .. versionadded:: 2.4
- """
+ """Finds all the templates the loader can find, compiles them
+ and stores them in `target`. If `zip` is `None`, instead of in a
+ zipfile, the templates will be stored in a directory.
+ By default a deflate zip algorithm is used. To switch to
+ the stored algorithm, `zip` can be set to ``'stored'``.
+
+ `extensions` and `filter_func` are passed to :meth:`list_templates`.
+ Each template returned will be compiled to the target folder or
+ zipfile.
+
+ By default template compilation errors are ignored. In case a
+ log function is provided, errors are logged. If you want template
+ syntax errors to abort the compilation you can set `ignore_errors`
+ to `False` and you will get an exception on syntax errors.
+
+ If `py_compile` is set to `True` .pyc files will be written to the
+ target instead of standard .py files. This flag does not do anything
+ on pypy and Python 3 where pyc files are not picked up by itself and
+ don't give much benefit.
+
+ .. versionadded:: 2.4
+ """
from .loaders import ModuleLoader
-
- if log_function is None:
-
+
+ if log_function is None:
+
def log_function(x):
pass
- if py_compile:
- if not PY2 or PYPY:
+ if py_compile:
+ if not PY2 or PYPY:
import warnings
warnings.warn(
@@ -730,87 +730,87 @@ class Environment(object):
DeprecationWarning,
stacklevel=2,
)
- py_compile = False
- else:
- import imp
- import marshal
-
+ py_compile = False
+ else:
+ import imp
+ import marshal
+
py_header = imp.get_magic() + u"\xff\xff\xff\xff".encode("iso-8859-15")
- # Python 3.3 added a source filesize to the header
- if sys.version_info >= (3, 3):
+ # Python 3.3 added a source filesize to the header
+ if sys.version_info >= (3, 3):
py_header += u"\x00\x00\x00\x00".encode("iso-8859-15")
-
+
def write_file(filename, data):
- if zip:
- info = ZipInfo(filename)
- info.external_attr = 0o755 << 16
- zip_file.writestr(info, data)
- else:
+ if zip:
+ info = ZipInfo(filename)
+ info.external_attr = 0o755 << 16
+ zip_file.writestr(info, data)
+ else:
if isinstance(data, text_type):
data = data.encode("utf8")
with open(os.path.join(target, filename), "wb") as f:
- f.write(data)
-
- if zip is not None:
- from zipfile import ZipFile, ZipInfo, ZIP_DEFLATED, ZIP_STORED
+ f.write(data)
+
+ if zip is not None:
+ from zipfile import ZipFile, ZipInfo, ZIP_DEFLATED, ZIP_STORED
zip_file = ZipFile(
target, "w", dict(deflated=ZIP_DEFLATED, stored=ZIP_STORED)[zip]
)
- log_function('Compiling into Zip archive "%s"' % target)
- else:
- if not os.path.isdir(target):
- os.makedirs(target)
- log_function('Compiling into folder "%s"' % target)
-
- try:
- for name in self.list_templates(extensions, filter_func):
- source, filename, _ = self.loader.get_source(self, name)
- try:
- code = self.compile(source, name, filename, True, True)
- except TemplateSyntaxError as e:
- if not ignore_errors:
- raise
- log_function('Could not compile "%s": %s' % (name, e))
- continue
-
- filename = ModuleLoader.get_module_filename(name)
-
- if py_compile:
- c = self._compile(code, encode_filename(filename))
+ log_function('Compiling into Zip archive "%s"' % target)
+ else:
+ if not os.path.isdir(target):
+ os.makedirs(target)
+ log_function('Compiling into folder "%s"' % target)
+
+ try:
+ for name in self.list_templates(extensions, filter_func):
+ source, filename, _ = self.loader.get_source(self, name)
+ try:
+ code = self.compile(source, name, filename, True, True)
+ except TemplateSyntaxError as e:
+ if not ignore_errors:
+ raise
+ log_function('Could not compile "%s": %s' % (name, e))
+ continue
+
+ filename = ModuleLoader.get_module_filename(name)
+
+ if py_compile:
+ c = self._compile(code, encode_filename(filename))
write_file(filename + "c", py_header + marshal.dumps(c))
log_function('Byte-compiled "%s" as %s' % (name, filename + "c"))
- else:
+ else:
write_file(filename, code)
- log_function('Compiled "%s" as %s' % (name, filename))
- finally:
- if zip:
- zip_file.close()
-
+ log_function('Compiled "%s" as %s' % (name, filename))
+ finally:
+ if zip:
+ zip_file.close()
+
log_function("Finished compiling templates")
-
- def list_templates(self, extensions=None, filter_func=None):
- """Returns a list of templates for this environment. This requires
- that the loader supports the loader's
- :meth:`~BaseLoader.list_templates` method.
-
- If there are other files in the template folder besides the
- actual templates, the returned list can be filtered. There are two
- ways: either `extensions` is set to a list of file extensions for
- templates, or a `filter_func` can be provided which is a callable that
- is passed a template name and should return `True` if it should end up
- in the result list.
-
- If the loader does not support that, a :exc:`TypeError` is raised.
-
- .. versionadded:: 2.4
- """
+
+ def list_templates(self, extensions=None, filter_func=None):
+ """Returns a list of templates for this environment. This requires
+ that the loader supports the loader's
+ :meth:`~BaseLoader.list_templates` method.
+
+ If there are other files in the template folder besides the
+ actual templates, the returned list can be filtered. There are two
+ ways: either `extensions` is set to a list of file extensions for
+ templates, or a `filter_func` can be provided which is a callable that
+ is passed a template name and should return `True` if it should end up
+ in the result list.
+
+ If the loader does not support that, a :exc:`TypeError` is raised.
+
+ .. versionadded:: 2.4
+ """
names = self.loader.list_templates()
- if extensions is not None:
- if filter_func is not None:
+ if extensions is not None:
+ if filter_func is not None:
raise TypeError(
"either extensions or filter_func can be passed, but not both"
)
@@ -818,165 +818,165 @@ class Environment(object):
def filter_func(x):
return "." in x and x.rsplit(".", 1)[1] in extensions
- if filter_func is not None:
+ if filter_func is not None:
names = [name for name in names if filter_func(name)]
-
+
return names
def handle_exception(self, source=None):
- """Exception handling helper. This is used internally to either raise
- rewritten exceptions or return a rendered traceback for the template.
- """
+ """Exception handling helper. This is used internally to either raise
+ rewritten exceptions or return a rendered traceback for the template.
+ """
from .debug import rewrite_traceback_stack
-
+
reraise(*rewrite_traceback_stack(source=source))
-
- def join_path(self, template, parent):
- """Join a template with the parent. By default all the lookups are
- relative to the loader root so this method returns the `template`
- parameter unchanged, but if the paths should be relative to the
- parent template, this function can be used to calculate the real
- template name.
-
- Subclasses may override this method and implement template path
- joining here.
- """
- return template
-
- @internalcode
- def _load_template(self, name, globals):
- if self.loader is None:
+
+ def join_path(self, template, parent):
+ """Join a template with the parent. By default all the lookups are
+ relative to the loader root so this method returns the `template`
+ parameter unchanged, but if the paths should be relative to the
+ parent template, this function can be used to calculate the real
+ template name.
+
+ Subclasses may override this method and implement template path
+ joining here.
+ """
+ return template
+
+ @internalcode
+ def _load_template(self, name, globals):
+ if self.loader is None:
raise TypeError("no loader for this environment specified")
- cache_key = (weakref.ref(self.loader), name)
- if self.cache is not None:
- template = self.cache.get(cache_key)
+ cache_key = (weakref.ref(self.loader), name)
+ if self.cache is not None:
+ template = self.cache.get(cache_key)
if template is not None and (
not self.auto_reload or template.is_up_to_date
):
- return template
- template = self.loader.load(self, name, globals)
- if self.cache is not None:
- self.cache[cache_key] = template
- return template
-
- @internalcode
- def get_template(self, name, parent=None, globals=None):
- """Load a template from the loader. If a loader is configured this
- method asks the loader for the template and returns a :class:`Template`.
- If the `parent` parameter is not `None`, :meth:`join_path` is called
- to get the real template name before loading.
-
- The `globals` parameter can be used to provide template wide globals.
- These variables are available in the context at render time.
-
- If the template does not exist a :exc:`TemplateNotFound` exception is
- raised.
-
- .. versionchanged:: 2.4
- If `name` is a :class:`Template` object it is returned from the
- function unchanged.
- """
- if isinstance(name, Template):
- return name
- if parent is not None:
- name = self.join_path(name, parent)
- return self._load_template(name, self.make_globals(globals))
-
- @internalcode
- def select_template(self, names, parent=None, globals=None):
- """Works like :meth:`get_template` but tries a number of templates
- before it fails. If it cannot find any of the templates, it will
- raise a :exc:`TemplatesNotFound` exception.
-
+ return template
+ template = self.loader.load(self, name, globals)
+ if self.cache is not None:
+ self.cache[cache_key] = template
+ return template
+
+ @internalcode
+ def get_template(self, name, parent=None, globals=None):
+ """Load a template from the loader. If a loader is configured this
+ method asks the loader for the template and returns a :class:`Template`.
+ If the `parent` parameter is not `None`, :meth:`join_path` is called
+ to get the real template name before loading.
+
+ The `globals` parameter can be used to provide template wide globals.
+ These variables are available in the context at render time.
+
+ If the template does not exist a :exc:`TemplateNotFound` exception is
+ raised.
+
+ .. versionchanged:: 2.4
+ If `name` is a :class:`Template` object it is returned from the
+ function unchanged.
+ """
+ if isinstance(name, Template):
+ return name
+ if parent is not None:
+ name = self.join_path(name, parent)
+ return self._load_template(name, self.make_globals(globals))
+
+ @internalcode
+ def select_template(self, names, parent=None, globals=None):
+ """Works like :meth:`get_template` but tries a number of templates
+ before it fails. If it cannot find any of the templates, it will
+ raise a :exc:`TemplatesNotFound` exception.
+
.. versionchanged:: 2.11
If names is :class:`Undefined`, an :exc:`UndefinedError` is
raised instead. If no templates were found and names
contains :class:`Undefined`, the message is more helpful.
-
- .. versionchanged:: 2.4
- If `names` contains a :class:`Template` object it is returned
- from the function unchanged.
+
+ .. versionchanged:: 2.4
+ If `names` contains a :class:`Template` object it is returned
+ from the function unchanged.
.. versionadded:: 2.3
- """
+ """
if isinstance(names, Undefined):
names._fail_with_undefined_error()
- if not names:
+ if not names:
raise TemplatesNotFound(
message=u"Tried to select from an empty list " u"of templates."
)
- globals = self.make_globals(globals)
- for name in names:
- if isinstance(name, Template):
- return name
- if parent is not None:
- name = self.join_path(name, parent)
- try:
- return self._load_template(name, globals)
+ globals = self.make_globals(globals)
+ for name in names:
+ if isinstance(name, Template):
+ return name
+ if parent is not None:
+ name = self.join_path(name, parent)
+ try:
+ return self._load_template(name, globals)
except (TemplateNotFound, UndefinedError):
- pass
- raise TemplatesNotFound(names)
-
- @internalcode
+ pass
+ raise TemplatesNotFound(names)
+
+ @internalcode
def get_or_select_template(self, template_name_or_list, parent=None, globals=None):
- """Does a typecheck and dispatches to :meth:`select_template`
- if an iterable of template names is given, otherwise to
- :meth:`get_template`.
-
- .. versionadded:: 2.3
- """
+ """Does a typecheck and dispatches to :meth:`select_template`
+ if an iterable of template names is given, otherwise to
+ :meth:`get_template`.
+
+ .. versionadded:: 2.3
+ """
if isinstance(template_name_or_list, (string_types, Undefined)):
- return self.get_template(template_name_or_list, parent, globals)
- elif isinstance(template_name_or_list, Template):
- return template_name_or_list
- return self.select_template(template_name_or_list, parent, globals)
-
- def from_string(self, source, globals=None, template_class=None):
- """Load a template from a string. This parses the source given and
- returns a :class:`Template` object.
- """
- globals = self.make_globals(globals)
- cls = template_class or self.template_class
- return cls.from_code(self, self.compile(source), globals, None)
-
- def make_globals(self, d):
- """Return a dict for the globals."""
- if not d:
- return self.globals
- return dict(self.globals, **d)
-
-
-class Template(object):
- """The central template object. This class represents a compiled template
- and is used to evaluate it.
-
- Normally the template object is generated from an :class:`Environment` but
- it also has a constructor that makes it possible to create a template
- instance directly using the constructor. It takes the same arguments as
- the environment constructor but it's not possible to specify a loader.
-
- Every template object has a few methods and members that are guaranteed
- to exist. However it's important that a template object should be
- considered immutable. Modifications on the object are not supported.
-
- Template objects created from the constructor rather than an environment
- do have an `environment` attribute that points to a temporary environment
- that is probably shared with other templates created with the constructor
- and compatible settings.
-
- >>> template = Template('Hello {{ name }}!')
- >>> template.render(name='John Doe') == u'Hello John Doe!'
- True
- >>> stream = template.stream(name='John Doe')
- >>> next(stream) == u'Hello John Doe!'
- True
- >>> next(stream)
- Traceback (most recent call last):
- ...
- StopIteration
- """
-
+ return self.get_template(template_name_or_list, parent, globals)
+ elif isinstance(template_name_or_list, Template):
+ return template_name_or_list
+ return self.select_template(template_name_or_list, parent, globals)
+
+ def from_string(self, source, globals=None, template_class=None):
+ """Load a template from a string. This parses the source given and
+ returns a :class:`Template` object.
+ """
+ globals = self.make_globals(globals)
+ cls = template_class or self.template_class
+ return cls.from_code(self, self.compile(source), globals, None)
+
+ def make_globals(self, d):
+ """Return a dict for the globals."""
+ if not d:
+ return self.globals
+ return dict(self.globals, **d)
+
+
+class Template(object):
+ """The central template object. This class represents a compiled template
+ and is used to evaluate it.
+
+ Normally the template object is generated from an :class:`Environment` but
+ it also has a constructor that makes it possible to create a template
+ instance directly using the constructor. It takes the same arguments as
+ the environment constructor but it's not possible to specify a loader.
+
+ Every template object has a few methods and members that are guaranteed
+ to exist. However it's important that a template object should be
+ considered immutable. Modifications on the object are not supported.
+
+ Template objects created from the constructor rather than an environment
+ do have an `environment` attribute that points to a temporary environment
+ that is probably shared with other templates created with the constructor
+ and compatible settings.
+
+ >>> template = Template('Hello {{ name }}!')
+ >>> template.render(name='John Doe') == u'Hello John Doe!'
+ True
+ >>> stream = template.stream(name='John Doe')
+ >>> next(stream) == u'Hello John Doe!'
+ True
+ >>> next(stream)
+ Traceback (most recent call last):
+ ...
+ StopIteration
+ """
+
#: Type of environment to create when creating a template directly
#: rather than through an existing environment.
environment_class = Environment
@@ -1003,7 +1003,7 @@ class Template(object):
autoescape=False,
enable_async=False,
):
- env = get_spontaneous_environment(
+ env = get_spontaneous_environment(
cls.environment_class,
block_start_string,
block_end_string,
@@ -1028,335 +1028,335 @@ class Template(object):
None,
enable_async,
)
- return env.from_string(source, template_class=cls)
-
- @classmethod
- def from_code(cls, environment, code, globals, uptodate=None):
- """Creates a template object from compiled code and the globals. This
- is used by the loaders and environment to create a template object.
- """
+ return env.from_string(source, template_class=cls)
+
+ @classmethod
+ def from_code(cls, environment, code, globals, uptodate=None):
+ """Creates a template object from compiled code and the globals. This
+ is used by the loaders and environment to create a template object.
+ """
namespace = {"environment": environment, "__file__": code.co_filename}
- exec(code, namespace)
- rv = cls._from_namespace(environment, namespace, globals)
- rv._uptodate = uptodate
- return rv
-
- @classmethod
- def from_module_dict(cls, environment, module_dict, globals):
- """Creates a template object from a module. This is used by the
- module loader to create a template object.
-
- .. versionadded:: 2.4
- """
- return cls._from_namespace(environment, module_dict, globals)
-
- @classmethod
- def _from_namespace(cls, environment, namespace, globals):
- t = object.__new__(cls)
- t.environment = environment
- t.globals = globals
+ exec(code, namespace)
+ rv = cls._from_namespace(environment, namespace, globals)
+ rv._uptodate = uptodate
+ return rv
+
+ @classmethod
+ def from_module_dict(cls, environment, module_dict, globals):
+ """Creates a template object from a module. This is used by the
+ module loader to create a template object.
+
+ .. versionadded:: 2.4
+ """
+ return cls._from_namespace(environment, module_dict, globals)
+
+ @classmethod
+ def _from_namespace(cls, environment, namespace, globals):
+ t = object.__new__(cls)
+ t.environment = environment
+ t.globals = globals
t.name = namespace["name"]
t.filename = namespace["__file__"]
t.blocks = namespace["blocks"]
-
- # render function and module
+
+ # render function and module
t.root_render_func = namespace["root"]
- t._module = None
-
- # debug and loader helpers
+ t._module = None
+
+ # debug and loader helpers
t._debug_info = namespace["debug_info"]
- t._uptodate = None
-
- # store the reference
+ t._uptodate = None
+
+ # store the reference
namespace["environment"] = environment
namespace["__jinja_template__"] = t
-
- return t
-
- def render(self, *args, **kwargs):
- """This method accepts the same arguments as the `dict` constructor:
- A dict, a dict subclass or some keyword arguments. If no arguments
- are given the context will be empty. These two calls do the same::
-
- template.render(knights='that say nih')
- template.render({'knights': 'that say nih'})
-
- This will return the rendered template as unicode string.
- """
- vars = dict(*args, **kwargs)
- try:
- return concat(self.root_render_func(self.new_context(vars)))
- except Exception:
+
+ return t
+
+ def render(self, *args, **kwargs):
+ """This method accepts the same arguments as the `dict` constructor:
+ A dict, a dict subclass or some keyword arguments. If no arguments
+ are given the context will be empty. These two calls do the same::
+
+ template.render(knights='that say nih')
+ template.render({'knights': 'that say nih'})
+
+ This will return the rendered template as unicode string.
+ """
+ vars = dict(*args, **kwargs)
+ try:
+ return concat(self.root_render_func(self.new_context(vars)))
+ except Exception:
self.environment.handle_exception()
-
- def render_async(self, *args, **kwargs):
- """This works similar to :meth:`render` but returns a coroutine
- that when awaited returns the entire rendered template string. This
- requires the async feature to be enabled.
-
- Example usage::
-
- await template.render_async(knights='that say nih; asynchronously')
- """
- # see asyncsupport for the actual implementation
+
+ def render_async(self, *args, **kwargs):
+ """This works similar to :meth:`render` but returns a coroutine
+ that when awaited returns the entire rendered template string. This
+ requires the async feature to be enabled.
+
+ Example usage::
+
+ await template.render_async(knights='that say nih; asynchronously')
+ """
+ # see asyncsupport for the actual implementation
raise NotImplementedError(
"This feature is not available for this version of Python"
)
-
- def stream(self, *args, **kwargs):
- """Works exactly like :meth:`generate` but returns a
- :class:`TemplateStream`.
- """
- return TemplateStream(self.generate(*args, **kwargs))
-
- def generate(self, *args, **kwargs):
- """For very large templates it can be useful to not render the whole
- template at once but evaluate each statement after another and yield
- piece for piece. This method basically does exactly that and returns
- a generator that yields one item after another as unicode strings.
-
- It accepts the same arguments as :meth:`render`.
- """
- vars = dict(*args, **kwargs)
- try:
- for event in self.root_render_func(self.new_context(vars)):
- yield event
- except Exception:
+
+ def stream(self, *args, **kwargs):
+ """Works exactly like :meth:`generate` but returns a
+ :class:`TemplateStream`.
+ """
+ return TemplateStream(self.generate(*args, **kwargs))
+
+ def generate(self, *args, **kwargs):
+ """For very large templates it can be useful to not render the whole
+ template at once but evaluate each statement after another and yield
+ piece for piece. This method basically does exactly that and returns
+ a generator that yields one item after another as unicode strings.
+
+ It accepts the same arguments as :meth:`render`.
+ """
+ vars = dict(*args, **kwargs)
+ try:
+ for event in self.root_render_func(self.new_context(vars)):
+ yield event
+ except Exception:
yield self.environment.handle_exception()
-
- def generate_async(self, *args, **kwargs):
- """An async version of :meth:`generate`. Works very similarly but
- returns an async iterator instead.
- """
- # see asyncsupport for the actual implementation
+
+ def generate_async(self, *args, **kwargs):
+ """An async version of :meth:`generate`. Works very similarly but
+ returns an async iterator instead.
+ """
+ # see asyncsupport for the actual implementation
raise NotImplementedError(
"This feature is not available for this version of Python"
)
-
- def new_context(self, vars=None, shared=False, locals=None):
- """Create a new :class:`Context` for this template. The vars
- provided will be passed to the template. Per default the globals
- are added to the context. If shared is set to `True` the data
+
+ def new_context(self, vars=None, shared=False, locals=None):
+ """Create a new :class:`Context` for this template. The vars
+ provided will be passed to the template. Per default the globals
+ are added to the context. If shared is set to `True` the data
is passed as is to the context without adding the globals.
-
- `locals` can be a dict of local variables for internal usage.
- """
+
+ `locals` can be a dict of local variables for internal usage.
+ """
return new_context(
self.environment, self.name, self.blocks, vars, shared, self.globals, locals
)
-
- def make_module(self, vars=None, shared=False, locals=None):
- """This method works like the :attr:`module` attribute when called
- without arguments but it will evaluate the template on every call
- rather than caching it. It's also possible to provide
- a dict which is then used as context. The arguments are the same
- as for the :meth:`new_context` method.
- """
- return TemplateModule(self, self.new_context(vars, shared, locals))
-
- def make_module_async(self, vars=None, shared=False, locals=None):
- """As template module creation can invoke template code for
+
+ def make_module(self, vars=None, shared=False, locals=None):
+ """This method works like the :attr:`module` attribute when called
+ without arguments but it will evaluate the template on every call
+ rather than caching it. It's also possible to provide
+ a dict which is then used as context. The arguments are the same
+ as for the :meth:`new_context` method.
+ """
+ return TemplateModule(self, self.new_context(vars, shared, locals))
+
+ def make_module_async(self, vars=None, shared=False, locals=None):
+ """As template module creation can invoke template code for
asynchronous executions this method must be used instead of the
- normal :meth:`make_module` one. Likewise the module attribute
- becomes unavailable in async mode.
- """
- # see asyncsupport for the actual implementation
+ normal :meth:`make_module` one. Likewise the module attribute
+ becomes unavailable in async mode.
+ """
+ # see asyncsupport for the actual implementation
raise NotImplementedError(
"This feature is not available for this version of Python"
)
-
- @internalcode
- def _get_default_module(self):
- if self._module is not None:
- return self._module
- self._module = rv = self.make_module()
- return rv
-
- @property
- def module(self):
- """The template as module. This is used for imports in the
- template runtime but is also useful if one wants to access
- exported template variables from the Python layer:
-
- >>> t = Template('{% macro foo() %}42{% endmacro %}23')
- >>> str(t.module)
- '23'
- >>> t.module.foo() == u'42'
- True
-
- This attribute is not available if async mode is enabled.
- """
- return self._get_default_module()
-
- def get_corresponding_lineno(self, lineno):
- """Return the source line number of a line number in the
- generated bytecode as they are not in sync.
- """
- for template_line, code_line in reversed(self.debug_info):
- if code_line <= lineno:
- return template_line
- return 1
-
- @property
- def is_up_to_date(self):
- """If this variable is `False` there is a newer version available."""
- if self._uptodate is None:
- return True
- return self._uptodate()
-
- @property
- def debug_info(self):
- """The debug info mapping."""
+
+ @internalcode
+ def _get_default_module(self):
+ if self._module is not None:
+ return self._module
+ self._module = rv = self.make_module()
+ return rv
+
+ @property
+ def module(self):
+ """The template as module. This is used for imports in the
+ template runtime but is also useful if one wants to access
+ exported template variables from the Python layer:
+
+ >>> t = Template('{% macro foo() %}42{% endmacro %}23')
+ >>> str(t.module)
+ '23'
+ >>> t.module.foo() == u'42'
+ True
+
+ This attribute is not available if async mode is enabled.
+ """
+ return self._get_default_module()
+
+ def get_corresponding_lineno(self, lineno):
+ """Return the source line number of a line number in the
+ generated bytecode as they are not in sync.
+ """
+ for template_line, code_line in reversed(self.debug_info):
+ if code_line <= lineno:
+ return template_line
+ return 1
+
+ @property
+ def is_up_to_date(self):
+ """If this variable is `False` there is a newer version available."""
+ if self._uptodate is None:
+ return True
+ return self._uptodate()
+
+ @property
+ def debug_info(self):
+ """The debug info mapping."""
if self._debug_info:
return [tuple(map(int, x.split("="))) for x in self._debug_info.split("&")]
return []
-
- def __repr__(self):
- if self.name is None:
+
+ def __repr__(self):
+ if self.name is None:
name = "memory:%x" % id(self)
- else:
- name = repr(self.name)
+ else:
+ name = repr(self.name)
return "<%s %s>" % (self.__class__.__name__, name)
-
-
-@implements_to_string
-class TemplateModule(object):
- """Represents an imported template. All the exported names of the
- template are available as attributes on this object. Additionally
- converting it into an unicode- or bytestrings renders the contents.
- """
-
- def __init__(self, template, context, body_stream=None):
- if body_stream is None:
- if context.environment.is_async:
+
+
+@implements_to_string
+class TemplateModule(object):
+ """Represents an imported template. All the exported names of the
+ template are available as attributes on this object. Additionally
+ converting it into an unicode- or bytestrings renders the contents.
+ """
+
+ def __init__(self, template, context, body_stream=None):
+ if body_stream is None:
+ if context.environment.is_async:
raise RuntimeError(
"Async mode requires a body stream "
"to be passed to a template module. Use "
"the async methods of the API you are "
"using."
)
- body_stream = list(template.root_render_func(context))
- self._body_stream = body_stream
- self.__dict__.update(context.get_exported())
- self.__name__ = template.name
-
- def __html__(self):
- return Markup(concat(self._body_stream))
-
- def __str__(self):
- return concat(self._body_stream)
-
- def __repr__(self):
- if self.__name__ is None:
+ body_stream = list(template.root_render_func(context))
+ self._body_stream = body_stream
+ self.__dict__.update(context.get_exported())
+ self.__name__ = template.name
+
+ def __html__(self):
+ return Markup(concat(self._body_stream))
+
+ def __str__(self):
+ return concat(self._body_stream)
+
+ def __repr__(self):
+ if self.__name__ is None:
name = "memory:%x" % id(self)
- else:
- name = repr(self.__name__)
+ else:
+ name = repr(self.__name__)
return "<%s %s>" % (self.__class__.__name__, name)
-
-
-class TemplateExpression(object):
- """The :meth:`jinja2.Environment.compile_expression` method returns an
- instance of this object. It encapsulates the expression-like access
- to the template with an expression it wraps.
- """
-
- def __init__(self, template, undefined_to_none):
- self._template = template
- self._undefined_to_none = undefined_to_none
-
- def __call__(self, *args, **kwargs):
- context = self._template.new_context(dict(*args, **kwargs))
- consume(self._template.root_render_func(context))
+
+
+class TemplateExpression(object):
+ """The :meth:`jinja2.Environment.compile_expression` method returns an
+ instance of this object. It encapsulates the expression-like access
+ to the template with an expression it wraps.
+ """
+
+ def __init__(self, template, undefined_to_none):
+ self._template = template
+ self._undefined_to_none = undefined_to_none
+
+ def __call__(self, *args, **kwargs):
+ context = self._template.new_context(dict(*args, **kwargs))
+ consume(self._template.root_render_func(context))
rv = context.vars["result"]
- if self._undefined_to_none and isinstance(rv, Undefined):
- rv = None
- return rv
-
-
-@implements_iterator
-class TemplateStream(object):
- """A template stream works pretty much like an ordinary python generator
- but it can buffer multiple items to reduce the number of total iterations.
- Per default the output is unbuffered which means that for every unbuffered
- instruction in the template one unicode string is yielded.
-
- If buffering is enabled with a buffer size of 5, five items are combined
- into a new unicode string. This is mainly useful if you are streaming
- big templates to a client via WSGI which flushes after each iteration.
- """
-
- def __init__(self, gen):
- self._gen = gen
- self.disable_buffering()
-
+ if self._undefined_to_none and isinstance(rv, Undefined):
+ rv = None
+ return rv
+
+
+@implements_iterator
+class TemplateStream(object):
+ """A template stream works pretty much like an ordinary python generator
+ but it can buffer multiple items to reduce the number of total iterations.
+ Per default the output is unbuffered which means that for every unbuffered
+ instruction in the template one unicode string is yielded.
+
+ If buffering is enabled with a buffer size of 5, five items are combined
+ into a new unicode string. This is mainly useful if you are streaming
+ big templates to a client via WSGI which flushes after each iteration.
+ """
+
+ def __init__(self, gen):
+ self._gen = gen
+ self.disable_buffering()
+
def dump(self, fp, encoding=None, errors="strict"):
- """Dump the complete stream into a file or file-like object.
- Per default unicode strings are written, if you want to encode
- before writing specify an `encoding`.
-
- Example usage::
-
- Template('Hello {{ name }}!').stream(name='foo').dump('hello.html')
- """
- close = False
- if isinstance(fp, string_types):
- if encoding is None:
+ """Dump the complete stream into a file or file-like object.
+ Per default unicode strings are written, if you want to encode
+ before writing specify an `encoding`.
+
+ Example usage::
+
+ Template('Hello {{ name }}!').stream(name='foo').dump('hello.html')
+ """
+ close = False
+ if isinstance(fp, string_types):
+ if encoding is None:
encoding = "utf-8"
fp = open(fp, "wb")
- close = True
- try:
- if encoding is not None:
- iterable = (x.encode(encoding, errors) for x in self)
- else:
- iterable = self
+ close = True
+ try:
+ if encoding is not None:
+ iterable = (x.encode(encoding, errors) for x in self)
+ else:
+ iterable = self
if hasattr(fp, "writelines"):
- fp.writelines(iterable)
- else:
- for item in iterable:
- fp.write(item)
- finally:
- if close:
- fp.close()
-
- def disable_buffering(self):
- """Disable the output buffering."""
- self._next = partial(next, self._gen)
- self.buffered = False
-
- def _buffered_generator(self, size):
- buf = []
- c_size = 0
- push = buf.append
-
- while 1:
- try:
- while c_size < size:
- c = next(self._gen)
- push(c)
- if c:
- c_size += 1
- except StopIteration:
- if not c_size:
- return
- yield concat(buf)
- del buf[:]
- c_size = 0
-
- def enable_buffering(self, size=5):
- """Enable buffering. Buffer `size` items before yielding them."""
- if size <= 1:
+ fp.writelines(iterable)
+ else:
+ for item in iterable:
+ fp.write(item)
+ finally:
+ if close:
+ fp.close()
+
+ def disable_buffering(self):
+ """Disable the output buffering."""
+ self._next = partial(next, self._gen)
+ self.buffered = False
+
+ def _buffered_generator(self, size):
+ buf = []
+ c_size = 0
+ push = buf.append
+
+ while 1:
+ try:
+ while c_size < size:
+ c = next(self._gen)
+ push(c)
+ if c:
+ c_size += 1
+ except StopIteration:
+ if not c_size:
+ return
+ yield concat(buf)
+ del buf[:]
+ c_size = 0
+
+ def enable_buffering(self, size=5):
+ """Enable buffering. Buffer `size` items before yielding them."""
+ if size <= 1:
raise ValueError("buffer size too small")
-
- self.buffered = True
- self._next = partial(next, self._buffered_generator(size))
-
- def __iter__(self):
- return self
-
- def __next__(self):
- return self._next()
-
-
-# hook in default template class. if anyone reads this comment: ignore that
-# it's possible to use custom templates ;-)
-Environment.template_class = Template
+
+ self.buffered = True
+ self._next = partial(next, self._buffered_generator(size))
+
+ def __iter__(self):
+ return self
+
+ def __next__(self):
+ return self._next()
+
+
+# hook in default template class. if anyone reads this comment: ignore that
+# it's possible to use custom templates ;-)
+Environment.template_class = Template
diff --git a/contrib/python/Jinja2/py2/jinja2/exceptions.py b/contrib/python/Jinja2/py2/jinja2/exceptions.py
index 0bf2003e30..d8b8456be7 100644
--- a/contrib/python/Jinja2/py2/jinja2/exceptions.py
+++ b/contrib/python/Jinja2/py2/jinja2/exceptions.py
@@ -1,89 +1,89 @@
-# -*- coding: utf-8 -*-
+# -*- coding: utf-8 -*-
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:
+
+
+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")
- Exception.__init__(self, message)
-
- @property
- def message(self):
- if self.args:
- message = self.args[0]
- if message is not None:
+ 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")
-
- def __unicode__(self):
+
+ def __unicode__(self):
return self.message or u""
- else:
-
- def __init__(self, message=None):
- Exception.__init__(self, message)
-
- @property
- def message(self):
- if self.args:
- message = self.args[0]
- if message is not None:
- return message
-
-
-@implements_to_string
-class TemplateNotFound(IOError, LookupError, TemplateError):
+ else:
+
+ def __init__(self, message=None):
+ Exception.__init__(self, message)
+
+ @property
+ def message(self):
+ if self.args:
+ message = self.args[0]
+ if message is not None:
+ return message
+
+
+@implements_to_string
+class TemplateNotFound(IOError, LookupError, TemplateError):
"""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):
+ # 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, name)
- if message is None:
+ 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]
-
- def __str__(self):
- return self.message
-
-
-class TemplatesNotFound(TemplateNotFound):
- """Like :class:`TemplateNotFound` but raised if multiple templates
- are selected. This is a subclass of :class:`TemplateNotFound`
- exception, so just catching the base exception will catch both.
-
+ message = name
+
+ self.message = message
+ self.name = name
+ self.templates = [name]
+
+ def __str__(self):
+ return self.message
+
+
+class TemplatesNotFound(TemplateNotFound):
+ """Like :class:`TemplateNotFound` but raised if multiple templates
+ 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:
+ .. versionadded:: 2.2
+ """
+
+ def __init__(self, names=(), message=None):
+ if message is None:
from .runtime import Undefined
parts = []
@@ -97,81 +97,81 @@ class TemplatesNotFound(TemplateNotFound):
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)
-
-
-@implements_to_string
-class TemplateSyntaxError(TemplateError):
- """Raised to tell the user that there is a problem with the template."""
-
- def __init__(self, message, lineno, name=None, filename=None):
- TemplateError.__init__(self, message)
- self.lineno = lineno
- self.name = name
- self.filename = filename
- self.source = None
-
- # this is set to True if the debug.translate_syntax_error
- # function translated the syntax error into a new traceback
- self.translated = False
-
- def __str__(self):
- # for translated errors we only return the message
- if self.translated:
- return self.message
-
- # otherwise attach some stuff
+ TemplateNotFound.__init__(self, names and names[-1] or None, message)
+ self.templates = list(names)
+
+
+@implements_to_string
+class TemplateSyntaxError(TemplateError):
+ """Raised to tell the user that there is a problem with the template."""
+
+ def __init__(self, message, lineno, name=None, filename=None):
+ TemplateError.__init__(self, message)
+ self.lineno = lineno
+ self.name = name
+ self.filename = filename
+ self.source = None
+
+ # this is set to True if the debug.translate_syntax_error
+ # function translated the syntax error into a new traceback
+ self.translated = False
+
+ def __str__(self):
+ # for translated errors we only return the message
+ if self.translated:
+ return self.message
+
+ # otherwise attach some stuff
location = "line %d" % self.lineno
- name = self.filename or self.name
- if name:
- location = 'File "%s", %s' % (name, location)
+ name = self.filename or self.name
+ if name:
+ location = 'File "%s", %s' % (name, location)
lines = [self.message, " " + location]
-
- # if the source is set, add the line to the output
- if self.source is not None:
- try:
- line = self.source.splitlines()[self.lineno - 1]
- except IndexError:
- line = None
- if line:
+
+ # if the source is set, add the line to the output
+ if self.source is not None:
+ try:
+ line = self.source.splitlines()[self.lineno - 1]
+ except IndexError:
+ line = None
+ if line:
lines.append(" " + line.strip())
-
+
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):
- """Like a template syntax error, but covers cases where something in the
- template caused an error at compile time that wasn't necessarily caused
- by a syntax error. However it's a direct subclass of
- :exc:`TemplateSyntaxError` and has the same attributes.
- """
-
-
-class TemplateRuntimeError(TemplateError):
- """A generic runtime error in the template engine. Under some situations
- Jinja may raise this exception.
- """
-
-
-class UndefinedError(TemplateRuntimeError):
- """Raised if a template tries to operate on :class:`Undefined`."""
-
-
-class SecurityError(TemplateRuntimeError):
- """Raised if a template tries to do something insecure if the
- sandbox is enabled.
- """
-
-
-class FilterArgumentError(TemplateRuntimeError):
- """This error is raised if a filter was called with inappropriate
- arguments
- """
+
+
+class TemplateAssertionError(TemplateSyntaxError):
+ """Like a template syntax error, but covers cases where something in the
+ template caused an error at compile time that wasn't necessarily caused
+ by a syntax error. However it's a direct subclass of
+ :exc:`TemplateSyntaxError` and has the same attributes.
+ """
+
+
+class TemplateRuntimeError(TemplateError):
+ """A generic runtime error in the template engine. Under some situations
+ Jinja may raise this exception.
+ """
+
+
+class UndefinedError(TemplateRuntimeError):
+ """Raised if a template tries to operate on :class:`Undefined`."""
+
+
+class SecurityError(TemplateRuntimeError):
+ """Raised if a template tries to do something insecure if the
+ sandbox is enabled.
+ """
+
+
+class FilterArgumentError(TemplateRuntimeError):
+ """This error is raised if a filter was called with inappropriate
+ arguments
+ """
diff --git a/contrib/python/Jinja2/py2/jinja2/ext.py b/contrib/python/Jinja2/py2/jinja2/ext.py
index 9141be4dac..012093f2ed 100644
--- a/contrib/python/Jinja2/py2/jinja2/ext.py
+++ b/contrib/python/Jinja2/py2/jinja2/ext.py
@@ -1,11 +1,11 @@
-# -*- coding: utf-8 -*-
+# -*- coding: utf-8 -*-
"""Extension API for adding custom tags and behavior."""
import pprint
-import re
+import re
from sys import version_info
-
+
from markupsafe import Markup
-
+
from . import nodes
from ._compat import iteritems
from ._compat import string_types
@@ -29,106 +29,106 @@ from .nodes import ContextReference
from .runtime import concat
from .utils import contextfunction
from .utils import import_string
-
-# the only real useful gettext functions for a Jinja template. Note
-# that ugettext must be assigned to gettext as Jinja doesn't support
-# non unicode strings.
+
+# the only real useful gettext functions for a Jinja template. Note
+# that ugettext must be assigned to gettext as Jinja doesn't support
+# non unicode strings.
GETTEXT_FUNCTIONS = ("_", "gettext", "ngettext")
-
+
_ws_re = re.compile(r"\s*\n\s*")
+
-
-class ExtensionRegistry(type):
- """Gives the extension an unique identifier."""
-
+class ExtensionRegistry(type):
+ """Gives the extension an unique identifier."""
+
def __new__(mcs, name, bases, d):
rv = type.__new__(mcs, name, bases, d)
rv.identifier = rv.__module__ + "." + rv.__name__
- return rv
-
-
-class Extension(with_metaclass(ExtensionRegistry, object)):
- """Extensions can be used to add extra functionality to the Jinja template
- system at the parser level. Custom extensions are bound to an environment
- but may not store environment specific data on `self`. The reason for
- this is that an extension can be bound to another environment (for
- overlays) by creating a copy and reassigning the `environment` attribute.
-
- As extensions are created by the environment they cannot accept any
- arguments for configuration. One may want to work around that by using
- a factory function, but that is not possible as extensions are identified
- by their import name. The correct way to configure the extension is
- storing the configuration values on the environment. Because this way the
- environment ends up acting as central configuration storage the
- attributes may clash which is why extensions have to ensure that the names
- they choose for configuration are not too generic. ``prefix`` for example
- is a terrible name, ``fragment_cache_prefix`` on the other hand is a good
- name as includes the name of the extension (fragment cache).
- """
-
- #: if this extension parses this is the list of tags it's listening to.
- tags = set()
-
- #: the priority of that extension. This is especially useful for
- #: extensions that preprocess values. A lower value means higher
- #: priority.
- #:
- #: .. versionadded:: 2.4
- priority = 100
-
- def __init__(self, environment):
- self.environment = environment
-
- def bind(self, environment):
- """Create a copy of this extension bound to another environment."""
- rv = object.__new__(self.__class__)
- rv.__dict__.update(self.__dict__)
- rv.environment = environment
- return rv
-
- def preprocess(self, source, name, filename=None):
- """This method is called before the actual lexing and can be used to
- preprocess the source. The `filename` is optional. The return value
- must be the preprocessed source.
- """
- return source
-
- def filter_stream(self, stream):
- """It's passed a :class:`~jinja2.lexer.TokenStream` that can be used
- to filter tokens returned. This method has to return an iterable of
- :class:`~jinja2.lexer.Token`\\s, but it doesn't have to return a
- :class:`~jinja2.lexer.TokenStream`.
- """
- return stream
-
- def parse(self, parser):
- """If any of the :attr:`tags` matched this method is called with the
- parser as first argument. The token the parser stream is pointing at
- is the name token that matched. This method has to return one or a
- list of multiple nodes.
- """
- raise NotImplementedError()
-
- def attr(self, name, lineno=None):
- """Return an attribute node for the current extension. This is useful
- to pass constants on extensions to generated template code.
-
- ::
-
- self.attr('_my_attribute', lineno=lineno)
- """
- return nodes.ExtensionAttribute(self.identifier, name, lineno=lineno)
-
+ return rv
+
+
+class Extension(with_metaclass(ExtensionRegistry, object)):
+ """Extensions can be used to add extra functionality to the Jinja template
+ system at the parser level. Custom extensions are bound to an environment
+ but may not store environment specific data on `self`. The reason for
+ this is that an extension can be bound to another environment (for
+ overlays) by creating a copy and reassigning the `environment` attribute.
+
+ As extensions are created by the environment they cannot accept any
+ arguments for configuration. One may want to work around that by using
+ a factory function, but that is not possible as extensions are identified
+ by their import name. The correct way to configure the extension is
+ storing the configuration values on the environment. Because this way the
+ environment ends up acting as central configuration storage the
+ attributes may clash which is why extensions have to ensure that the names
+ they choose for configuration are not too generic. ``prefix`` for example
+ is a terrible name, ``fragment_cache_prefix`` on the other hand is a good
+ name as includes the name of the extension (fragment cache).
+ """
+
+ #: if this extension parses this is the list of tags it's listening to.
+ tags = set()
+
+ #: the priority of that extension. This is especially useful for
+ #: extensions that preprocess values. A lower value means higher
+ #: priority.
+ #:
+ #: .. versionadded:: 2.4
+ priority = 100
+
+ def __init__(self, environment):
+ self.environment = environment
+
+ def bind(self, environment):
+ """Create a copy of this extension bound to another environment."""
+ rv = object.__new__(self.__class__)
+ rv.__dict__.update(self.__dict__)
+ rv.environment = environment
+ return rv
+
+ def preprocess(self, source, name, filename=None):
+ """This method is called before the actual lexing and can be used to
+ preprocess the source. The `filename` is optional. The return value
+ must be the preprocessed source.
+ """
+ return source
+
+ def filter_stream(self, stream):
+ """It's passed a :class:`~jinja2.lexer.TokenStream` that can be used
+ to filter tokens returned. This method has to return an iterable of
+ :class:`~jinja2.lexer.Token`\\s, but it doesn't have to return a
+ :class:`~jinja2.lexer.TokenStream`.
+ """
+ return stream
+
+ def parse(self, parser):
+ """If any of the :attr:`tags` matched this method is called with the
+ parser as first argument. The token the parser stream is pointing at
+ is the name token that matched. This method has to return one or a
+ list of multiple nodes.
+ """
+ raise NotImplementedError()
+
+ def attr(self, name, lineno=None):
+ """Return an attribute node for the current extension. This is useful
+ to pass constants on extensions to generated template code.
+
+ ::
+
+ self.attr('_my_attribute', lineno=lineno)
+ """
+ return nodes.ExtensionAttribute(self.identifier, name, lineno=lineno)
+
def call_method(
self, name, args=None, kwargs=None, dyn_args=None, dyn_kwargs=None, lineno=None
):
- """Call a method of the extension. This is a shortcut for
- :meth:`attr` + :class:`jinja2.nodes.Call`.
- """
- if args is None:
- args = []
- if kwargs is None:
- kwargs = []
+ """Call a method of the extension. This is a shortcut for
+ :meth:`attr` + :class:`jinja2.nodes.Call`.
+ """
+ if args is None:
+ args = []
+ if kwargs is None:
+ kwargs = []
return nodes.Call(
self.attr(name, lineno=lineno),
args,
@@ -137,196 +137,196 @@ class Extension(with_metaclass(ExtensionRegistry, object)):
dyn_kwargs,
lineno=lineno,
)
-
-
-@contextfunction
-def _gettext_alias(__context, *args, **kwargs):
+
+
+@contextfunction
+def _gettext_alias(__context, *args, **kwargs):
return __context.call(__context.resolve("gettext"), *args, **kwargs)
-
-
-def _make_new_gettext(func):
- @contextfunction
- def gettext(__context, __string, **variables):
- rv = __context.call(func, __string)
- if __context.eval_ctx.autoescape:
- rv = Markup(rv)
+
+
+def _make_new_gettext(func):
+ @contextfunction
+ def gettext(__context, __string, **variables):
+ rv = __context.call(func, __string)
+ if __context.eval_ctx.autoescape:
+ rv = Markup(rv)
# Always treat as a format string, even if there are no
# variables. This makes translation strings more consistent
# and predictable. This requires escaping
- return rv % variables
-
- return gettext
-
-
-def _make_new_ngettext(func):
- @contextfunction
- def ngettext(__context, __singular, __plural, __num, **variables):
+ return rv % variables
+
+ return gettext
+
+
+def _make_new_ngettext(func):
+ @contextfunction
+ def ngettext(__context, __singular, __plural, __num, **variables):
variables.setdefault("num", __num)
- rv = __context.call(func, __singular, __plural, __num)
- if __context.eval_ctx.autoescape:
- rv = Markup(rv)
+ rv = __context.call(func, __singular, __plural, __num)
+ if __context.eval_ctx.autoescape:
+ rv = Markup(rv)
# Always treat as a format string, see gettext comment above.
- return rv % variables
-
- return ngettext
+ return rv % variables
-
-class InternationalizationExtension(Extension):
+ return ngettext
+
+
+class InternationalizationExtension(Extension):
"""This extension adds gettext support to Jinja."""
-
+
tags = {"trans"}
- # TODO: the i18n extension is currently reevaluating values in a few
- # situations. Take this example:
- # {% trans count=something() %}{{ count }} foo{% pluralize
- # %}{{ count }} fooss{% endtrans %}
- # something is called twice here. One time for the gettext value and
- # the other time for the n-parameter of the ngettext function.
-
- def __init__(self, environment):
- Extension.__init__(self, environment)
+ # TODO: the i18n extension is currently reevaluating values in a few
+ # situations. Take this example:
+ # {% trans count=something() %}{{ count }} foo{% pluralize
+ # %}{{ count }} fooss{% endtrans %}
+ # something is called twice here. One time for the gettext value and
+ # the other time for the n-parameter of the ngettext function.
+
+ def __init__(self, environment):
+ Extension.__init__(self, environment)
environment.globals["_"] = _gettext_alias
- environment.extend(
- install_gettext_translations=self._install,
- install_null_translations=self._install_null,
- install_gettext_callables=self._install_callables,
- uninstall_gettext_translations=self._uninstall,
- extract_translations=self._extract,
+ environment.extend(
+ install_gettext_translations=self._install,
+ install_null_translations=self._install_null,
+ install_gettext_callables=self._install_callables,
+ uninstall_gettext_translations=self._uninstall,
+ extract_translations=self._extract,
newstyle_gettext=False,
- )
-
- def _install(self, translations, newstyle=None):
+ )
+
+ def _install(self, translations, newstyle=None):
gettext = getattr(translations, "ugettext", None)
- if gettext is None:
- gettext = translations.gettext
+ if gettext is None:
+ gettext = translations.gettext
ngettext = getattr(translations, "ungettext", None)
- if ngettext is None:
- ngettext = translations.ngettext
- self._install_callables(gettext, ngettext, newstyle)
-
- def _install_null(self, newstyle=None):
- self._install_callables(
+ if ngettext is None:
+ ngettext = translations.ngettext
+ self._install_callables(gettext, ngettext, newstyle)
+
+ def _install_null(self, newstyle=None):
+ self._install_callables(
lambda x: x, lambda s, p, n: (n != 1 and (p,) or (s,))[0], newstyle
- )
-
- def _install_callables(self, gettext, ngettext, newstyle=None):
- if newstyle is not None:
- self.environment.newstyle_gettext = newstyle
- if self.environment.newstyle_gettext:
- gettext = _make_new_gettext(gettext)
- ngettext = _make_new_ngettext(ngettext)
+ )
+
+ def _install_callables(self, gettext, ngettext, newstyle=None):
+ if newstyle is not None:
+ self.environment.newstyle_gettext = newstyle
+ if self.environment.newstyle_gettext:
+ gettext = _make_new_gettext(gettext)
+ ngettext = _make_new_ngettext(ngettext)
self.environment.globals.update(gettext=gettext, ngettext=ngettext)
-
- def _uninstall(self, translations):
+
+ def _uninstall(self, translations):
for key in "gettext", "ngettext":
- self.environment.globals.pop(key, None)
-
- def _extract(self, source, gettext_functions=GETTEXT_FUNCTIONS):
- if isinstance(source, string_types):
- source = self.environment.parse(source)
- return extract_from_ast(source, gettext_functions)
-
- def parse(self, parser):
- """Parse a translatable tag."""
- lineno = next(parser.stream).lineno
- num_called_num = False
-
- # find all the variables referenced. Additionally a variable can be
- # defined in the body of the trans block too, but this is checked at
- # a later state.
- plural_expr = None
- plural_expr_assignment = None
- variables = {}
- trimmed = None
+ self.environment.globals.pop(key, None)
+
+ def _extract(self, source, gettext_functions=GETTEXT_FUNCTIONS):
+ if isinstance(source, string_types):
+ source = self.environment.parse(source)
+ return extract_from_ast(source, gettext_functions)
+
+ def parse(self, parser):
+ """Parse a translatable tag."""
+ lineno = next(parser.stream).lineno
+ num_called_num = False
+
+ # find all the variables referenced. Additionally a variable can be
+ # defined in the body of the trans block too, but this is checked at
+ # a later state.
+ plural_expr = None
+ plural_expr_assignment = None
+ variables = {}
+ trimmed = None
while parser.stream.current.type != "block_end":
- if variables:
+ if variables:
parser.stream.expect("comma")
-
- # skip colon for python compatibility
+
+ # skip colon for python compatibility
if parser.stream.skip_if("colon"):
- break
-
+ break
+
name = parser.stream.expect("name")
- if name.value in variables:
+ if name.value in variables:
parser.fail(
"translatable variable %r defined twice." % name.value,
name.lineno,
exc=TemplateAssertionError,
)
-
- # expressions
+
+ # expressions
if parser.stream.current.type == "assign":
- next(parser.stream)
- variables[name.value] = var = parser.parse_expression()
+ next(parser.stream)
+ variables[name.value] = var = parser.parse_expression()
elif trimmed is None and name.value in ("trimmed", "notrimmed"):
trimmed = name.value == "trimmed"
- continue
- else:
+ continue
+ else:
variables[name.value] = var = nodes.Name(name.value, "load")
-
- if plural_expr is None:
- if isinstance(var, nodes.Call):
+
+ if plural_expr is None:
+ if isinstance(var, nodes.Call):
plural_expr = nodes.Name("_trans", "load")
- variables[name.value] = plural_expr
- plural_expr_assignment = nodes.Assign(
+ variables[name.value] = plural_expr
+ plural_expr_assignment = nodes.Assign(
nodes.Name("_trans", "store"), var
)
- else:
- plural_expr = var
+ else:
+ plural_expr = var
num_called_num = name.value == "num"
-
+
parser.stream.expect("block_end")
-
- plural = None
- have_plural = False
- referenced = set()
-
- # now parse until endtrans or pluralize
- singular_names, singular = self._parse_block(parser, True)
- if singular_names:
- referenced.update(singular_names)
- if plural_expr is None:
+
+ plural = None
+ have_plural = False
+ referenced = set()
+
+ # now parse until endtrans or pluralize
+ singular_names, singular = self._parse_block(parser, True)
+ if singular_names:
+ referenced.update(singular_names)
+ if plural_expr is None:
plural_expr = nodes.Name(singular_names[0], "load")
num_called_num = singular_names[0] == "num"
-
- # if we have a pluralize block, we parse that too
+
+ # if we have a pluralize block, we parse that too
if parser.stream.current.test("name:pluralize"):
- have_plural = True
- next(parser.stream)
+ have_plural = True
+ next(parser.stream)
if parser.stream.current.type != "block_end":
name = parser.stream.expect("name")
- if name.value not in variables:
+ if name.value not in variables:
parser.fail(
"unknown variable %r for pluralization" % name.value,
name.lineno,
exc=TemplateAssertionError,
)
- plural_expr = variables[name.value]
+ plural_expr = variables[name.value]
num_called_num = name.value == "num"
parser.stream.expect("block_end")
- plural_names, plural = self._parse_block(parser, False)
- next(parser.stream)
- referenced.update(plural_names)
- else:
- next(parser.stream)
-
- # register free names as simple name expressions
- for var in referenced:
- if var not in variables:
+ plural_names, plural = self._parse_block(parser, False)
+ next(parser.stream)
+ referenced.update(plural_names)
+ else:
+ next(parser.stream)
+
+ # register free names as simple name expressions
+ for var in referenced:
+ if var not in variables:
variables[var] = nodes.Name(var, "load")
-
- if not have_plural:
- plural_expr = None
- elif plural_expr is None:
+
+ if not have_plural:
+ plural_expr = None
+ elif plural_expr is None:
parser.fail("pluralize without variables", lineno)
-
- if trimmed is None:
+
+ if trimmed is None:
trimmed = self.environment.policies["ext.i18n.trimmed"]
- if trimmed:
- singular = self._trim_whitespace(singular)
- if plural:
- plural = self._trim_whitespace(plural)
-
+ if trimmed:
+ singular = self._trim_whitespace(singular)
+ if plural:
+ plural = self._trim_whitespace(plural)
+
node = self._make_node(
singular,
plural,
@@ -335,67 +335,67 @@ class InternationalizationExtension(Extension):
bool(referenced),
num_called_num and have_plural,
)
- node.set_lineno(lineno)
- if plural_expr_assignment is not None:
- return [plural_expr_assignment, node]
- else:
- return node
-
+ node.set_lineno(lineno)
+ if plural_expr_assignment is not None:
+ return [plural_expr_assignment, node]
+ else:
+ return node
+
def _trim_whitespace(self, string, _ws_re=_ws_re):
return _ws_re.sub(" ", string.strip())
-
- def _parse_block(self, parser, allow_pluralize):
- """Parse until the next block tag with a given name."""
- referenced = []
- buf = []
- while 1:
+
+ def _parse_block(self, parser, allow_pluralize):
+ """Parse until the next block tag with a given name."""
+ referenced = []
+ buf = []
+ while 1:
if parser.stream.current.type == "data":
buf.append(parser.stream.current.value.replace("%", "%%"))
- next(parser.stream)
+ next(parser.stream)
elif parser.stream.current.type == "variable_begin":
- next(parser.stream)
+ next(parser.stream)
name = parser.stream.expect("name").value
- referenced.append(name)
+ referenced.append(name)
buf.append("%%(%s)s" % name)
parser.stream.expect("variable_end")
elif parser.stream.current.type == "block_begin":
- next(parser.stream)
+ next(parser.stream)
if parser.stream.current.test("name:endtrans"):
- break
+ break
elif parser.stream.current.test("name:pluralize"):
- if allow_pluralize:
- break
+ if allow_pluralize:
+ break
parser.fail(
"a translatable section can have only one pluralize section"
)
parser.fail(
"control structures in translatable sections are not allowed"
)
- elif parser.stream.eos:
+ elif parser.stream.eos:
parser.fail("unclosed translation block")
- else:
+ else:
raise RuntimeError("internal parser error")
-
- return referenced, concat(buf)
-
+
+ return referenced, concat(buf)
+
def _make_node(
self, singular, plural, variables, plural_expr, vars_referenced, num_called_num
):
- """Generates a useful node from the data provided."""
- # no variables referenced? no need to escape for old style
- # gettext invocations only if there are vars.
- if not vars_referenced and not self.environment.newstyle_gettext:
+ """Generates a useful node from the data provided."""
+ # no variables referenced? no need to escape for old style
+ # gettext invocations only if there are vars.
+ if not vars_referenced and not self.environment.newstyle_gettext:
singular = singular.replace("%%", "%")
- if plural:
+ if plural:
plural = plural.replace("%%", "%")
-
- # singular only:
- if plural_expr is None:
+
+ # singular only:
+ if plural_expr is None:
gettext = nodes.Name("gettext", "load")
node = nodes.Call(gettext, [nodes.Const(singular)], [], None, None)
-
- # singular and plural
- else:
+
+ # singular and plural
+ else:
ngettext = nodes.Name("ngettext", "load")
node = nodes.Call(
ngettext,
@@ -404,24 +404,24 @@ class InternationalizationExtension(Extension):
None,
None,
)
-
- # in case newstyle gettext is used, the method is powerful
- # enough to handle the variable expansion and autoescape
- # handling itself
- if self.environment.newstyle_gettext:
- for key, value in iteritems(variables):
- # the function adds that later anyways in case num was
- # called num, so just skip it.
+
+ # in case newstyle gettext is used, the method is powerful
+ # enough to handle the variable expansion and autoescape
+ # handling itself
+ if self.environment.newstyle_gettext:
+ for key, value in iteritems(variables):
+ # the function adds that later anyways in case num was
+ # called num, so just skip it.
if num_called_num and key == "num":
- continue
- node.kwargs.append(nodes.Keyword(key, value))
-
- # otherwise do that here
- else:
- # mark the return value as safe if we are in an
- # environment with autoescaping turned on
- node = nodes.MarkSafeIfAutoescape(node)
- if variables:
+ continue
+ node.kwargs.append(nodes.Keyword(key, value))
+
+ # otherwise do that here
+ else:
+ # mark the return value as safe if we are in an
+ # environment with autoescaping turned on
+ node = nodes.MarkSafeIfAutoescape(node)
+ if variables:
node = nodes.Mod(
node,
nodes.Dict(
@@ -431,42 +431,42 @@ class InternationalizationExtension(Extension):
]
),
)
- return nodes.Output([node])
-
-
-class ExprStmtExtension(Extension):
+ return nodes.Output([node])
+
+
+class ExprStmtExtension(Extension):
"""Adds a `do` tag to Jinja that works like the print statement just
- that it doesn't print the return value.
- """
-
+ that it doesn't print the return value.
+ """
+
tags = set(["do"])
- def parse(self, parser):
- node = nodes.ExprStmt(lineno=next(parser.stream).lineno)
- node.node = parser.parse_tuple()
- return node
-
-
-class LoopControlExtension(Extension):
- """Adds break and continue to the template engine."""
-
+ def parse(self, parser):
+ node = nodes.ExprStmt(lineno=next(parser.stream).lineno)
+ node.node = parser.parse_tuple()
+ return node
+
+
+class LoopControlExtension(Extension):
+ """Adds break and continue to the template engine."""
+
tags = set(["break", "continue"])
- def parse(self, parser):
- token = next(parser.stream)
+ def parse(self, parser):
+ token = next(parser.stream)
if token.value == "break":
- return nodes.Break(lineno=token.lineno)
- return nodes.Continue(lineno=token.lineno)
-
-
-class WithExtension(Extension):
- pass
-
-
-class AutoEscapeExtension(Extension):
- pass
-
-
+ return nodes.Break(lineno=token.lineno)
+ return nodes.Continue(lineno=token.lineno)
+
+
+class WithExtension(Extension):
+ pass
+
+
+class AutoEscapeExtension(Extension):
+ pass
+
+
class DebugExtension(Extension):
"""A ``{% debug %}`` tag that dumps the available variables,
filters, and tests.
@@ -511,153 +511,153 @@ class DebugExtension(Extension):
def extract_from_ast(node, gettext_functions=GETTEXT_FUNCTIONS, babel_style=True):
- """Extract localizable strings from the given template node. Per
- default this function returns matches in babel style that means non string
- parameters as well as keyword arguments are returned as `None`. This
- allows Babel to figure out what you really meant if you are using
- gettext functions that allow keyword arguments for placeholder expansion.
- If you don't want that behavior set the `babel_style` parameter to `False`
- which causes only strings to be returned and parameters are always stored
- in tuples. As a consequence invalid gettext calls (calls without a single
- string parameter or string parameters after non-string parameters) are
- skipped.
-
- This example explains the behavior:
-
- >>> from jinja2 import Environment
- >>> env = Environment()
- >>> node = env.parse('{{ (_("foo"), _(), ngettext("foo", "bar", 42)) }}')
- >>> list(extract_from_ast(node))
- [(1, '_', 'foo'), (1, '_', ()), (1, 'ngettext', ('foo', 'bar', None))]
- >>> list(extract_from_ast(node, babel_style=False))
- [(1, '_', ('foo',)), (1, 'ngettext', ('foo', 'bar'))]
-
- For every string found this function yields a ``(lineno, function,
- message)`` tuple, where:
-
- * ``lineno`` is the number of the line on which the string was found,
- * ``function`` is the name of the ``gettext`` function used (if the
- string was extracted from embedded Python code), and
- * ``message`` is the string itself (a ``unicode`` object, or a tuple
- of ``unicode`` objects for functions with multiple string arguments).
-
- This extraction function operates on the AST and is because of that unable
- to extract any comments. For comment support you have to use the babel
- extraction interface or extract comments yourself.
- """
- for node in node.find_all(nodes.Call):
+ """Extract localizable strings from the given template node. Per
+ default this function returns matches in babel style that means non string
+ parameters as well as keyword arguments are returned as `None`. This
+ allows Babel to figure out what you really meant if you are using
+ gettext functions that allow keyword arguments for placeholder expansion.
+ If you don't want that behavior set the `babel_style` parameter to `False`
+ which causes only strings to be returned and parameters are always stored
+ in tuples. As a consequence invalid gettext calls (calls without a single
+ string parameter or string parameters after non-string parameters) are
+ skipped.
+
+ This example explains the behavior:
+
+ >>> from jinja2 import Environment
+ >>> env = Environment()
+ >>> node = env.parse('{{ (_("foo"), _(), ngettext("foo", "bar", 42)) }}')
+ >>> list(extract_from_ast(node))
+ [(1, '_', 'foo'), (1, '_', ()), (1, 'ngettext', ('foo', 'bar', None))]
+ >>> list(extract_from_ast(node, babel_style=False))
+ [(1, '_', ('foo',)), (1, 'ngettext', ('foo', 'bar'))]
+
+ For every string found this function yields a ``(lineno, function,
+ message)`` tuple, where:
+
+ * ``lineno`` is the number of the line on which the string was found,
+ * ``function`` is the name of the ``gettext`` function used (if the
+ string was extracted from embedded Python code), and
+ * ``message`` is the string itself (a ``unicode`` object, or a tuple
+ of ``unicode`` objects for functions with multiple string arguments).
+
+ This extraction function operates on the AST and is because of that unable
+ to extract any comments. For comment support you have to use the babel
+ extraction interface or extract comments yourself.
+ """
+ for node in node.find_all(nodes.Call):
if (
not isinstance(node.node, nodes.Name)
or node.node.name not in gettext_functions
):
- continue
-
- strings = []
- for arg in node.args:
+ continue
+
+ strings = []
+ for arg in node.args:
if isinstance(arg, nodes.Const) and isinstance(arg.value, string_types):
- strings.append(arg.value)
- else:
- strings.append(None)
-
+ strings.append(arg.value)
+ else:
+ strings.append(None)
+
for _ in node.kwargs:
- strings.append(None)
- if node.dyn_args is not None:
- strings.append(None)
- if node.dyn_kwargs is not None:
- strings.append(None)
-
- if not babel_style:
- strings = tuple(x for x in strings if x is not None)
- if not strings:
- continue
- else:
- if len(strings) == 1:
- strings = strings[0]
- else:
- strings = tuple(strings)
- yield node.lineno, node.node.name, strings
-
-
-class _CommentFinder(object):
- """Helper class to find comments in a token stream. Can only
- find comments for gettext calls forwards. Once the comment
- from line 4 is found, a comment for line 1 will not return a
- usable value.
- """
-
- def __init__(self, tokens, comment_tags):
- self.tokens = tokens
- self.comment_tags = comment_tags
- self.offset = 0
- self.last_lineno = 0
-
- def find_backwards(self, offset):
- try:
+ strings.append(None)
+ if node.dyn_args is not None:
+ strings.append(None)
+ if node.dyn_kwargs is not None:
+ strings.append(None)
+
+ if not babel_style:
+ strings = tuple(x for x in strings if x is not None)
+ if not strings:
+ continue
+ else:
+ if len(strings) == 1:
+ strings = strings[0]
+ else:
+ strings = tuple(strings)
+ yield node.lineno, node.node.name, strings
+
+
+class _CommentFinder(object):
+ """Helper class to find comments in a token stream. Can only
+ find comments for gettext calls forwards. Once the comment
+ from line 4 is found, a comment for line 1 will not return a
+ usable value.
+ """
+
+ def __init__(self, tokens, comment_tags):
+ self.tokens = tokens
+ self.comment_tags = comment_tags
+ self.offset = 0
+ self.last_lineno = 0
+
+ def find_backwards(self, offset):
+ try:
for _, token_type, token_value in reversed(
self.tokens[self.offset : offset]
):
if token_type in ("comment", "linecomment"):
- try:
- prefix, comment = token_value.split(None, 1)
- except ValueError:
- continue
- if prefix in self.comment_tags:
- return [comment.rstrip()]
- return []
- finally:
- self.offset = offset
-
- def find_comments(self, lineno):
- if not self.comment_tags or self.last_lineno > lineno:
- return []
+ try:
+ prefix, comment = token_value.split(None, 1)
+ except ValueError:
+ continue
+ if prefix in self.comment_tags:
+ return [comment.rstrip()]
+ return []
+ finally:
+ self.offset = offset
+
+ def find_comments(self, lineno):
+ if not self.comment_tags or self.last_lineno > lineno:
+ return []
for idx, (token_lineno, _, _) in enumerate(self.tokens[self.offset :]):
- if token_lineno > lineno:
- return self.find_backwards(self.offset + idx)
- return self.find_backwards(len(self.tokens))
-
-
-def babel_extract(fileobj, keywords, comment_tags, options):
- """Babel extraction method for Jinja templates.
-
- .. versionchanged:: 2.3
- Basic support for translation comments was added. If `comment_tags`
- is now set to a list of keywords for extraction, the extractor will
+ if token_lineno > lineno:
+ return self.find_backwards(self.offset + idx)
+ return self.find_backwards(len(self.tokens))
+
+
+def babel_extract(fileobj, keywords, comment_tags, options):
+ """Babel extraction method for Jinja templates.
+
+ .. versionchanged:: 2.3
+ Basic support for translation comments was added. If `comment_tags`
+ is now set to a list of keywords for extraction, the extractor will
try to find the best preceding comment that begins with one of the
- keywords. For best results, make sure to not have more than one
- gettext call in one line of code and the matching comment in the
- same line or the line before.
-
- .. versionchanged:: 2.5.1
- The `newstyle_gettext` flag can be set to `True` to enable newstyle
- gettext calls.
-
- .. versionchanged:: 2.7
- A `silent` option can now be provided. If set to `False` template
- syntax errors are propagated instead of being ignored.
-
- :param fileobj: the file-like object the messages should be extracted from
- :param keywords: a list of keywords (i.e. function names) that should be
- recognized as translation functions
- :param comment_tags: a list of translator tags to search for and include
- in the results.
- :param options: a dictionary of additional options (optional)
- :return: an iterator over ``(lineno, funcname, message, comments)`` tuples.
- (comments will be empty currently)
- """
- extensions = set()
+ keywords. For best results, make sure to not have more than one
+ gettext call in one line of code and the matching comment in the
+ same line or the line before.
+
+ .. versionchanged:: 2.5.1
+ The `newstyle_gettext` flag can be set to `True` to enable newstyle
+ gettext calls.
+
+ .. versionchanged:: 2.7
+ A `silent` option can now be provided. If set to `False` template
+ syntax errors are propagated instead of being ignored.
+
+ :param fileobj: the file-like object the messages should be extracted from
+ :param keywords: a list of keywords (i.e. function names) that should be
+ recognized as translation functions
+ :param comment_tags: a list of translator tags to search for and include
+ in the results.
+ :param options: a dictionary of additional options (optional)
+ :return: an iterator over ``(lineno, funcname, message, comments)`` tuples.
+ (comments will be empty currently)
+ """
+ extensions = set()
for extension in options.get("extensions", "").split(","):
- extension = extension.strip()
- if not extension:
- continue
- extensions.add(import_string(extension))
- if InternationalizationExtension not in extensions:
- extensions.add(InternationalizationExtension)
-
- def getbool(options, key, default=False):
+ extension = extension.strip()
+ if not extension:
+ continue
+ extensions.add(import_string(extension))
+ if InternationalizationExtension not in extensions:
+ extensions.add(InternationalizationExtension)
+
+ def getbool(options, key, default=False):
return options.get(key, str(default)).lower() in ("1", "on", "yes", "true")
-
+
silent = getbool(options, "silent", True)
- environment = Environment(
+ environment = Environment(
options.get("block_start_string", BLOCK_START_STRING),
options.get("block_end_string", BLOCK_END_STRING),
options.get("variable_start_string", VARIABLE_START_STRING),
@@ -668,37 +668,37 @@ def babel_extract(fileobj, keywords, comment_tags, options):
options.get("line_comment_prefix") or LINE_COMMENT_PREFIX,
getbool(options, "trim_blocks", TRIM_BLOCKS),
getbool(options, "lstrip_blocks", LSTRIP_BLOCKS),
- NEWLINE_SEQUENCE,
+ NEWLINE_SEQUENCE,
getbool(options, "keep_trailing_newline", KEEP_TRAILING_NEWLINE),
- frozenset(extensions),
- cache_size=0,
+ frozenset(extensions),
+ cache_size=0,
auto_reload=False,
- )
-
+ )
+
if getbool(options, "trimmed"):
environment.policies["ext.i18n.trimmed"] = True
if getbool(options, "newstyle_gettext"):
- environment.newstyle_gettext = True
-
+ environment.newstyle_gettext = True
+
source = fileobj.read().decode(options.get("encoding", "utf-8"))
- try:
- node = environment.parse(source)
- tokens = list(environment.lex(environment.preprocess(source)))
+ try:
+ node = environment.parse(source)
+ tokens = list(environment.lex(environment.preprocess(source)))
except TemplateSyntaxError:
- if not silent:
- raise
- # skip templates with syntax errors
- return
-
- finder = _CommentFinder(tokens, comment_tags)
- for lineno, func, message in extract_from_ast(node, keywords):
- yield lineno, func, message, finder.find_comments(lineno)
-
-
-#: nicer import names
-i18n = InternationalizationExtension
-do = ExprStmtExtension
-loopcontrols = LoopControlExtension
-with_ = WithExtension
-autoescape = AutoEscapeExtension
+ if not silent:
+ raise
+ # skip templates with syntax errors
+ return
+
+ finder = _CommentFinder(tokens, comment_tags)
+ for lineno, func, message in extract_from_ast(node, keywords):
+ yield lineno, func, message, finder.find_comments(lineno)
+
+
+#: nicer import names
+i18n = InternationalizationExtension
+do = ExprStmtExtension
+loopcontrols = LoopControlExtension
+with_ = WithExtension
+autoescape = AutoEscapeExtension
debug = DebugExtension
diff --git a/contrib/python/Jinja2/py2/jinja2/filters.py b/contrib/python/Jinja2/py2/jinja2/filters.py
index 74b108dcec..f7c35ab7f2 100644
--- a/contrib/python/Jinja2/py2/jinja2/filters.py
+++ b/contrib/python/Jinja2/py2/jinja2/filters.py
@@ -1,17 +1,17 @@
-# -*- coding: utf-8 -*-
+# -*- coding: utf-8 -*-
"""Built-in template filters used with the ``|`` operator."""
-import math
-import random
+import math
+import random
import re
-import warnings
-from collections import namedtuple
+import warnings
+from collections import namedtuple
from itertools import chain
from itertools import groupby
-
+
from markupsafe import escape
from markupsafe import Markup
from markupsafe import soft_unicode
-
+
from ._compat import abc
from ._compat import imap
from ._compat import iteritems
@@ -23,67 +23,67 @@ from .utils import htmlsafe_json_dumps
from .utils import pformat
from .utils import unicode_urlencode
from .utils import urlize
-
+
_word_re = re.compile(r"\w+", re.UNICODE)
_word_beginning_split_re = re.compile(r"([-\s\(\{\[\<]+)", re.UNICODE)
-
-
-def contextfilter(f):
- """Decorator for marking context dependent filters. The current
- :class:`Context` will be passed as first argument.
- """
- f.contextfilter = True
- return f
-
-
-def evalcontextfilter(f):
- """Decorator for marking eval-context dependent filters. An eval
- context object is passed as first argument. For more information
- about the eval context, see :ref:`eval-context`.
-
- .. versionadded:: 2.4
- """
- f.evalcontextfilter = True
- return f
-
-
-def environmentfilter(f):
- """Decorator for marking environment dependent filters. The current
- :class:`Environment` is passed to the filter as first argument.
- """
- f.environmentfilter = True
- return f
-
-
-def ignore_case(value):
- """For use as a postprocessor for :func:`make_attrgetter`. Converts strings
- to lowercase and returns other types as-is."""
- return value.lower() if isinstance(value, string_types) else value
-
-
+
+
+def contextfilter(f):
+ """Decorator for marking context dependent filters. The current
+ :class:`Context` will be passed as first argument.
+ """
+ f.contextfilter = True
+ return f
+
+
+def evalcontextfilter(f):
+ """Decorator for marking eval-context dependent filters. An eval
+ context object is passed as first argument. For more information
+ about the eval context, see :ref:`eval-context`.
+
+ .. versionadded:: 2.4
+ """
+ f.evalcontextfilter = True
+ return f
+
+
+def environmentfilter(f):
+ """Decorator for marking environment dependent filters. The current
+ :class:`Environment` is passed to the filter as first argument.
+ """
+ f.environmentfilter = True
+ return f
+
+
+def ignore_case(value):
+ """For use as a postprocessor for :func:`make_attrgetter`. Converts strings
+ to lowercase and returns other types as-is."""
+ return value.lower() if isinstance(value, string_types) else value
+
+
def make_attrgetter(environment, attribute, postprocess=None, default=None):
- """Returns a callable that looks up the given attribute from a
- passed object with the rules of the environment. Dots are allowed
- to access attributes of attributes. Integer parts in paths are
- looked up as integers.
- """
+ """Returns a callable that looks up the given attribute from a
+ passed object with the rules of the environment. Dots are allowed
+ to access attributes of attributes. Integer parts in paths are
+ looked up as integers.
+ """
attribute = _prepare_attribute_parts(attribute)
-
- def attrgetter(item):
- for part in attribute:
- item = environment.getitem(item, part)
-
+
+ def attrgetter(item):
+ for part in attribute:
+ item = environment.getitem(item, part)
+
if default and isinstance(item, Undefined):
item = default
- if postprocess is not None:
- item = postprocess(item)
-
- return item
-
- return attrgetter
-
-
+ if postprocess is not None:
+ item = postprocess(item)
+
+ return item
+
+ return attrgetter
+
+
def make_multi_attrgetter(environment, attribute, postprocess=None):
"""Returns a callable that looks up the given comma separated
attributes from a passed object with the rules of the environment.
@@ -127,16 +127,16 @@ def _prepare_attribute_parts(attr):
return [attr]
-def do_forceescape(value):
- """Enforce HTML escaping. This will probably double escape variables."""
+def do_forceescape(value):
+ """Enforce HTML escaping. This will probably double escape variables."""
if hasattr(value, "__html__"):
- value = value.__html__()
- return escape(text_type(value))
-
-
-def do_urlencode(value):
+ value = value.__html__()
+ return escape(text_type(value))
+
+
+def do_urlencode(value):
"""Quote data for use in a URL path or query using UTF-8.
-
+
Basic wrapper around :func:`urllib.parse.quote` when given a
string, or :func:`urllib.parse.urlencode` for a dict or iterable.
@@ -148,110 +148,110 @@ def do_urlencode(value):
"%2F" equivalently in paths. If you need quoted slashes, use the
``|replace("/", "%2F")`` filter.
- .. versionadded:: 2.7
- """
+ .. versionadded:: 2.7
+ """
if isinstance(value, string_types) or not isinstance(value, abc.Iterable):
- return unicode_urlencode(value)
-
+ return unicode_urlencode(value)
+
if isinstance(value, dict):
items = iteritems(value)
else:
items = iter(value)
-
+
return u"&".join(
"%s=%s" % (unicode_urlencode(k, for_qs=True), unicode_urlencode(v, for_qs=True))
for k, v in items
)
-@evalcontextfilter
-def do_replace(eval_ctx, s, old, new, count=None):
- """Return a copy of the value with all occurrences of a substring
- replaced with a new one. The first argument is the substring
- that should be replaced, the second is the replacement string.
- If the optional third argument ``count`` is given, only the first
- ``count`` occurrences are replaced:
-
- .. sourcecode:: jinja
-
- {{ "Hello World"|replace("Hello", "Goodbye") }}
- -> Goodbye World
-
- {{ "aaaaargh"|replace("a", "d'oh, ", 2) }}
- -> d'oh, d'oh, aaargh
- """
- if count is None:
- count = -1
- if not eval_ctx.autoescape:
- return text_type(s).replace(text_type(old), text_type(new), count)
+@evalcontextfilter
+def do_replace(eval_ctx, s, old, new, count=None):
+ """Return a copy of the value with all occurrences of a substring
+ replaced with a new one. The first argument is the substring
+ that should be replaced, the second is the replacement string.
+ If the optional third argument ``count`` is given, only the first
+ ``count`` occurrences are replaced:
+
+ .. sourcecode:: jinja
+
+ {{ "Hello World"|replace("Hello", "Goodbye") }}
+ -> Goodbye World
+
+ {{ "aaaaargh"|replace("a", "d'oh, ", 2) }}
+ -> d'oh, d'oh, aaargh
+ """
+ if count is None:
+ count = -1
+ if not eval_ctx.autoescape:
+ return text_type(s).replace(text_type(old), text_type(new), count)
if (
hasattr(old, "__html__")
or hasattr(new, "__html__")
and not hasattr(s, "__html__")
):
- s = escape(s)
- else:
- s = soft_unicode(s)
- return s.replace(soft_unicode(old), soft_unicode(new), count)
-
-
-def do_upper(s):
- """Convert a value to uppercase."""
- return soft_unicode(s).upper()
-
-
-def do_lower(s):
- """Convert a value to lowercase."""
- return soft_unicode(s).lower()
-
-
-@evalcontextfilter
-def do_xmlattr(_eval_ctx, d, autospace=True):
- """Create an SGML/XML attribute string based on the items in a dict.
- All values that are neither `none` nor `undefined` are automatically
- escaped:
-
- .. sourcecode:: html+jinja
-
- <ul{{ {'class': 'my_list', 'missing': none,
- 'id': 'list-%d'|format(variable)}|xmlattr }}>
- ...
- </ul>
-
- Results in something like this:
-
- .. sourcecode:: html
-
- <ul class="my_list" id="list-42">
- ...
- </ul>
-
- As you can see it automatically prepends a space in front of the item
- if the filter returned something unless the second parameter is false.
- """
+ s = escape(s)
+ else:
+ s = soft_unicode(s)
+ return s.replace(soft_unicode(old), soft_unicode(new), count)
+
+
+def do_upper(s):
+ """Convert a value to uppercase."""
+ return soft_unicode(s).upper()
+
+
+def do_lower(s):
+ """Convert a value to lowercase."""
+ return soft_unicode(s).lower()
+
+
+@evalcontextfilter
+def do_xmlattr(_eval_ctx, d, autospace=True):
+ """Create an SGML/XML attribute string based on the items in a dict.
+ All values that are neither `none` nor `undefined` are automatically
+ escaped:
+
+ .. sourcecode:: html+jinja
+
+ <ul{{ {'class': 'my_list', 'missing': none,
+ 'id': 'list-%d'|format(variable)}|xmlattr }}>
+ ...
+ </ul>
+
+ Results in something like this:
+
+ .. sourcecode:: html
+
+ <ul class="my_list" id="list-42">
+ ...
+ </ul>
+
+ As you can see it automatically prepends a space in front of the item
+ if the filter returned something unless the second parameter is false.
+ """
rv = u" ".join(
- u'%s="%s"' % (escape(key), escape(value))
- for key, value in iteritems(d)
- if value is not None and not isinstance(value, Undefined)
- )
- if autospace and rv:
+ u'%s="%s"' % (escape(key), escape(value))
+ for key, value in iteritems(d)
+ if value is not None and not isinstance(value, Undefined)
+ )
+ if autospace and rv:
rv = u" " + rv
- if _eval_ctx.autoescape:
- rv = Markup(rv)
- return rv
-
-
-def do_capitalize(s):
- """Capitalize a value. The first character will be uppercase, all others
- lowercase.
- """
- return soft_unicode(s).capitalize()
-
-
-def do_title(s):
- """Return a titlecased version of the value. I.e. words will start with
- uppercase letters, all remaining characters are lowercase.
- """
+ if _eval_ctx.autoescape:
+ rv = Markup(rv)
+ return rv
+
+
+def do_capitalize(s):
+ """Capitalize a value. The first character will be uppercase, all others
+ lowercase.
+ """
+ return soft_unicode(s).capitalize()
+
+
+def do_title(s):
+ """Return a titlecased version of the value. I.e. words will start with
+ uppercase letters, all remaining characters are lowercase.
+ """
return "".join(
[
item[0].upper() + item[1:].lower()
@@ -259,51 +259,51 @@ def do_title(s):
if item
]
)
-
-
+
+
def do_dictsort(value, case_sensitive=False, by="key", reverse=False):
- """Sort a dict and yield (key, value) pairs. Because python dicts are
- unsorted you may want to use this function to order them by either
- key or value:
-
- .. sourcecode:: jinja
-
+ """Sort a dict and yield (key, value) pairs. Because python dicts are
+ unsorted you may want to use this function to order them by either
+ key or value:
+
+ .. sourcecode:: jinja
+
{% for key, value in mydict|dictsort %}
- sort the dict by key, case insensitive
-
+ sort the dict by key, case insensitive
+
{% for key, value in mydict|dictsort(reverse=true) %}
- sort the dict by key, case insensitive, reverse order
-
+ sort the dict by key, case insensitive, reverse order
+
{% for key, value in mydict|dictsort(true) %}
- sort the dict by key, case sensitive
-
+ sort the dict by key, case sensitive
+
{% for key, value in mydict|dictsort(false, 'value') %}
- sort the dict by value, case insensitive
- """
+ sort the dict by value, case insensitive
+ """
if by == "key":
- pos = 0
+ pos = 0
elif by == "value":
- pos = 1
- else:
+ pos = 1
+ else:
raise FilterArgumentError('You can only sort by either "key" or "value"')
-
- def sort_func(item):
- value = item[pos]
-
- if not case_sensitive:
- value = ignore_case(value)
-
- return value
-
- return sorted(value.items(), key=sort_func, reverse=reverse)
-
-
-@environmentfilter
+
+ def sort_func(item):
+ value = item[pos]
+
+ if not case_sensitive:
+ value = ignore_case(value)
+
+ return value
+
+ return sorted(value.items(), key=sort_func, reverse=reverse)
+
+
+@environmentfilter
def do_sort(environment, value, reverse=False, case_sensitive=False, attribute=None):
"""Sort an iterable using Python's :func:`sorted`.
-
+
.. sourcecode:: jinja
-
+
{% for city in cities|sort %}
...
{% endfor %}
@@ -319,201 +319,201 @@ def do_sort(environment, value, reverse=False, case_sensitive=False, attribute=N
elements that compare equal. This makes it is possible to chain
sorts on different attributes and ordering.
- .. sourcecode:: jinja
-
+ .. sourcecode:: jinja
+
{% for user in users|sort(attribute="name")
|sort(reverse=true, attribute="age") %}
- ...
- {% endfor %}
-
+ ...
+ {% endfor %}
+
As a shortcut to chaining when the direction is the same for all
attributes, pass a comma separate list of attributes.
-
- .. sourcecode:: jinja
-
+
+ .. sourcecode:: jinja
+
{% for user users|sort(attribute="age,name") %}
- ...
- {% endfor %}
-
+ ...
+ {% endfor %}
+
.. versionchanged:: 2.11.0
The ``attribute`` parameter can be a comma separated list of
attributes, e.g. ``"age,name"``.
- .. versionchanged:: 2.6
+ .. versionchanged:: 2.6
The ``attribute`` parameter was added.
- """
+ """
key_func = make_multi_attrgetter(
environment, attribute, postprocess=ignore_case if not case_sensitive else None
- )
- return sorted(value, key=key_func, reverse=reverse)
-
-
-@environmentfilter
-def do_unique(environment, value, case_sensitive=False, attribute=None):
+ )
+ return sorted(value, key=key_func, reverse=reverse)
+
+
+@environmentfilter
+def do_unique(environment, value, case_sensitive=False, attribute=None):
"""Returns a list of unique items from the given iterable.
-
- .. sourcecode:: jinja
-
+
+ .. sourcecode:: jinja
+
{{ ['foo', 'bar', 'foobar', 'FooBar']|unique|list }}
- -> ['foo', 'bar', 'foobar']
-
- The unique items are yielded in the same order as their first occurrence in
- the iterable passed to the filter.
-
- :param case_sensitive: Treat upper and lower case strings as distinct.
- :param attribute: Filter objects with unique values for this attribute.
- """
- getter = make_attrgetter(
+ -> ['foo', 'bar', 'foobar']
+
+ The unique items are yielded in the same order as their first occurrence in
+ the iterable passed to the filter.
+
+ :param case_sensitive: Treat upper and lower case strings as distinct.
+ :param attribute: Filter objects with unique values for this attribute.
+ """
+ getter = make_attrgetter(
environment, attribute, postprocess=ignore_case if not case_sensitive else None
- )
- seen = set()
-
- for item in value:
- key = getter(item)
-
- if key not in seen:
- seen.add(key)
- yield item
-
-
-def _min_or_max(environment, value, func, case_sensitive, attribute):
- it = iter(value)
-
- try:
- first = next(it)
- except StopIteration:
+ )
+ seen = set()
+
+ for item in value:
+ key = getter(item)
+
+ if key not in seen:
+ seen.add(key)
+ yield item
+
+
+def _min_or_max(environment, value, func, case_sensitive, attribute):
+ it = iter(value)
+
+ try:
+ first = next(it)
+ except StopIteration:
return environment.undefined("No aggregated item, sequence was empty.")
-
- key_func = make_attrgetter(
+
+ key_func = make_attrgetter(
environment, attribute, postprocess=ignore_case if not case_sensitive else None
- )
- return func(chain([first], it), key=key_func)
-
-
-@environmentfilter
-def do_min(environment, value, case_sensitive=False, attribute=None):
- """Return the smallest item from the sequence.
-
- .. sourcecode:: jinja
-
- {{ [1, 2, 3]|min }}
- -> 1
-
- :param case_sensitive: Treat upper and lower case strings as distinct.
+ )
+ return func(chain([first], it), key=key_func)
+
+
+@environmentfilter
+def do_min(environment, value, case_sensitive=False, attribute=None):
+ """Return the smallest item from the sequence.
+
+ .. sourcecode:: jinja
+
+ {{ [1, 2, 3]|min }}
+ -> 1
+
+ :param case_sensitive: Treat upper and lower case strings as distinct.
:param attribute: Get the object with the min value of this attribute.
- """
- return _min_or_max(environment, value, min, case_sensitive, attribute)
-
-
-@environmentfilter
-def do_max(environment, value, case_sensitive=False, attribute=None):
- """Return the largest item from the sequence.
-
- .. sourcecode:: jinja
-
- {{ [1, 2, 3]|max }}
- -> 3
-
- :param case_sensitive: Treat upper and lower case strings as distinct.
- :param attribute: Get the object with the max value of this attribute.
- """
- return _min_or_max(environment, value, max, case_sensitive, attribute)
-
-
+ """
+ return _min_or_max(environment, value, min, case_sensitive, attribute)
+
+
+@environmentfilter
+def do_max(environment, value, case_sensitive=False, attribute=None):
+ """Return the largest item from the sequence.
+
+ .. sourcecode:: jinja
+
+ {{ [1, 2, 3]|max }}
+ -> 3
+
+ :param case_sensitive: Treat upper and lower case strings as distinct.
+ :param attribute: Get the object with the max value of this attribute.
+ """
+ return _min_or_max(environment, value, max, case_sensitive, attribute)
+
+
def do_default(value, default_value=u"", boolean=False):
- """If the value is undefined it will return the passed default value,
- otherwise the value of the variable:
-
- .. sourcecode:: jinja
-
- {{ my_variable|default('my_variable is not defined') }}
-
- This will output the value of ``my_variable`` if the variable was
- defined, otherwise ``'my_variable is not defined'``. If you want
- to use default with variables that evaluate to false you have to
- set the second parameter to `true`:
-
- .. sourcecode:: jinja
-
- {{ ''|default('the string was empty', true) }}
+ """If the value is undefined it will return the passed default value,
+ otherwise the value of the variable:
+
+ .. sourcecode:: jinja
+
+ {{ my_variable|default('my_variable is not defined') }}
+
+ This will output the value of ``my_variable`` if the variable was
+ defined, otherwise ``'my_variable is not defined'``. If you want
+ to use default with variables that evaluate to false you have to
+ set the second parameter to `true`:
+
+ .. sourcecode:: jinja
+
+ {{ ''|default('the string was empty', true) }}
.. versionchanged:: 2.11
It's now possible to configure the :class:`~jinja2.Environment` with
:class:`~jinja2.ChainableUndefined` to make the `default` filter work
on nested elements and attributes that may contain undefined values
in the chain without getting an :exc:`~jinja2.UndefinedError`.
- """
- if isinstance(value, Undefined) or (boolean and not value):
- return default_value
- return value
-
-
-@evalcontextfilter
+ """
+ if isinstance(value, Undefined) or (boolean and not value):
+ return default_value
+ return value
+
+
+@evalcontextfilter
def do_join(eval_ctx, value, d=u"", attribute=None):
- """Return a string which is the concatenation of the strings in the
- sequence. The separator between elements is an empty string per
- default, you can define it with the optional parameter:
-
- .. sourcecode:: jinja
-
- {{ [1, 2, 3]|join('|') }}
- -> 1|2|3
-
- {{ [1, 2, 3]|join }}
- -> 123
-
- It is also possible to join certain attributes of an object:
-
- .. sourcecode:: jinja
-
- {{ users|join(', ', attribute='username') }}
-
- .. versionadded:: 2.6
- The `attribute` parameter was added.
- """
- if attribute is not None:
- value = imap(make_attrgetter(eval_ctx.environment, attribute), value)
-
+ """Return a string which is the concatenation of the strings in the
+ sequence. The separator between elements is an empty string per
+ default, you can define it with the optional parameter:
+
+ .. sourcecode:: jinja
+
+ {{ [1, 2, 3]|join('|') }}
+ -> 1|2|3
+
+ {{ [1, 2, 3]|join }}
+ -> 123
+
+ It is also possible to join certain attributes of an object:
+
+ .. sourcecode:: jinja
+
+ {{ users|join(', ', attribute='username') }}
+
+ .. versionadded:: 2.6
+ The `attribute` parameter was added.
+ """
+ if attribute is not None:
+ value = imap(make_attrgetter(eval_ctx.environment, attribute), value)
+
# no automatic escaping? joining is a lot easier then
- if not eval_ctx.autoescape:
- return text_type(d).join(imap(text_type, value))
-
- # if the delimiter doesn't have an html representation we check
- # if any of the items has. If yes we do a coercion to Markup
+ if not eval_ctx.autoescape:
+ return text_type(d).join(imap(text_type, value))
+
+ # if the delimiter doesn't have an html representation we check
+ # if any of the items has. If yes we do a coercion to Markup
if not hasattr(d, "__html__"):
- value = list(value)
- do_escape = False
- for idx, item in enumerate(value):
+ value = list(value)
+ do_escape = False
+ for idx, item in enumerate(value):
if hasattr(item, "__html__"):
- do_escape = True
- else:
- value[idx] = text_type(item)
- if do_escape:
- d = escape(d)
- else:
- d = text_type(d)
- return d.join(value)
-
- # no html involved, to normal joining
- return soft_unicode(d).join(imap(soft_unicode, value))
-
-
-def do_center(value, width=80):
- """Centers the value in a field of a given width."""
- return text_type(value).center(width)
-
-
-@environmentfilter
-def do_first(environment, seq):
- """Return the first item of a sequence."""
- try:
- return next(iter(seq))
- except StopIteration:
+ do_escape = True
+ else:
+ value[idx] = text_type(item)
+ if do_escape:
+ d = escape(d)
+ else:
+ d = text_type(d)
+ return d.join(value)
+
+ # no html involved, to normal joining
+ return soft_unicode(d).join(imap(soft_unicode, value))
+
+
+def do_center(value, width=80):
+ """Centers the value in a field of a given width."""
+ return text_type(value).center(width)
+
+
+@environmentfilter
+def do_first(environment, seq):
+ """Return the first item of a sequence."""
+ try:
+ return next(iter(seq))
+ except StopIteration:
return environment.undefined("No first item, sequence was empty.")
-
-
-@environmentfilter
-def do_last(environment, seq):
+
+
+@environmentfilter
+def do_last(environment, seq):
"""
Return the last item of a sequence.
@@ -524,30 +524,30 @@ def do_last(environment, seq):
{{ data | selectattr('name', '==', 'Jinja') | list | last }}
"""
- try:
- return next(iter(reversed(seq)))
- except StopIteration:
+ try:
+ return next(iter(reversed(seq)))
+ except StopIteration:
return environment.undefined("No last item, sequence was empty.")
-
-
-@contextfilter
-def do_random(context, seq):
- """Return a random item from the sequence."""
- try:
- return random.choice(seq)
- except IndexError:
+
+
+@contextfilter
+def do_random(context, seq):
+ """Return a random item from the sequence."""
+ try:
+ return random.choice(seq)
+ except IndexError:
return context.environment.undefined("No random item, sequence was empty.")
-
-
-def do_filesizeformat(value, binary=False):
- """Format the value like a 'human-readable' file size (i.e. 13 kB,
- 4.1 MB, 102 Bytes, etc). Per default decimal prefixes are used (Mega,
- Giga, etc.), if the second parameter is set to `True` the binary
- prefixes are used (Mebi, Gibi).
- """
- bytes = float(value)
- base = binary and 1024 or 1000
- prefixes = [
+
+
+def do_filesizeformat(value, binary=False):
+ """Format the value like a 'human-readable' file size (i.e. 13 kB,
+ 4.1 MB, 102 Bytes, etc). Per default decimal prefixes are used (Mega,
+ Giga, etc.), if the second parameter is set to `True` the binary
+ prefixes are used (Mebi, Gibi).
+ """
+ bytes = float(value)
+ base = binary and 1024 or 1000
+ prefixes = [
(binary and "KiB" or "kB"),
(binary and "MiB" or "MB"),
(binary and "GiB" or "GB"),
@@ -556,153 +556,153 @@ def do_filesizeformat(value, binary=False):
(binary and "EiB" or "EB"),
(binary and "ZiB" or "ZB"),
(binary and "YiB" or "YB"),
- ]
- if bytes == 1:
+ ]
+ if bytes == 1:
return "1 Byte"
- elif bytes < base:
+ elif bytes < base:
return "%d Bytes" % bytes
- else:
- for i, prefix in enumerate(prefixes):
- unit = base ** (i + 2)
- if bytes < unit:
+ else:
+ for i, prefix in enumerate(prefixes):
+ unit = base ** (i + 2)
+ if bytes < unit:
return "%.1f %s" % ((base * bytes / unit), prefix)
return "%.1f %s" % ((base * bytes / unit), prefix)
-
-
-def do_pprint(value, verbose=False):
- """Pretty print a variable. Useful for debugging.
-
- With Jinja 1.2 onwards you can pass it a parameter. If this parameter
- is truthy the output will be more verbose (this requires `pretty`)
- """
- return pformat(value, verbose=verbose)
-
-
-@evalcontextfilter
+
+
+def do_pprint(value, verbose=False):
+ """Pretty print a variable. Useful for debugging.
+
+ With Jinja 1.2 onwards you can pass it a parameter. If this parameter
+ is truthy the output will be more verbose (this requires `pretty`)
+ """
+ return pformat(value, verbose=verbose)
+
+
+@evalcontextfilter
def do_urlize(
eval_ctx, value, trim_url_limit=None, nofollow=False, target=None, rel=None
):
- """Converts URLs in plain text into clickable links.
-
- If you pass the filter an additional integer it will shorten the urls
- to that number. Also a third argument exists that makes the urls
- "nofollow":
-
- .. sourcecode:: jinja
-
- {{ mytext|urlize(40, true) }}
- links are shortened to 40 chars and defined with rel="nofollow"
-
- If *target* is specified, the ``target`` attribute will be added to the
- ``<a>`` tag:
-
- .. sourcecode:: jinja
-
- {{ mytext|urlize(40, target='_blank') }}
-
- .. versionchanged:: 2.8+
- The *target* parameter was added.
- """
- policies = eval_ctx.environment.policies
+ """Converts URLs in plain text into clickable links.
+
+ If you pass the filter an additional integer it will shorten the urls
+ to that number. Also a third argument exists that makes the urls
+ "nofollow":
+
+ .. sourcecode:: jinja
+
+ {{ mytext|urlize(40, true) }}
+ links are shortened to 40 chars and defined with rel="nofollow"
+
+ If *target* is specified, the ``target`` attribute will be added to the
+ ``<a>`` tag:
+
+ .. sourcecode:: jinja
+
+ {{ mytext|urlize(40, target='_blank') }}
+
+ .. versionchanged:: 2.8+
+ The *target* parameter was added.
+ """
+ policies = eval_ctx.environment.policies
rel = set((rel or "").split() or [])
- if nofollow:
+ if nofollow:
rel.add("nofollow")
rel.update((policies["urlize.rel"] or "").split())
- if target is None:
+ if target is None:
target = policies["urlize.target"]
rel = " ".join(sorted(rel)) or None
- rv = urlize(value, trim_url_limit, rel=rel, target=target)
- if eval_ctx.autoescape:
- rv = Markup(rv)
- return rv
-
-
+ rv = urlize(value, trim_url_limit, rel=rel, target=target)
+ if eval_ctx.autoescape:
+ rv = Markup(rv)
+ return rv
+
+
def do_indent(s, width=4, first=False, blank=False, indentfirst=None):
- """Return a copy of the string with each line indented by 4 spaces. The
- first line and blank lines are not indented by default.
-
- :param width: Number of spaces to indent by.
- :param first: Don't skip indenting the first line.
- :param blank: Don't skip indenting empty lines.
-
- .. versionchanged:: 2.10
- Blank lines are not indented by default.
-
- Rename the ``indentfirst`` argument to ``first``.
- """
- if indentfirst is not None:
+ """Return a copy of the string with each line indented by 4 spaces. The
+ first line and blank lines are not indented by default.
+
+ :param width: Number of spaces to indent by.
+ :param first: Don't skip indenting the first line.
+ :param blank: Don't skip indenting empty lines.
+
+ .. versionchanged:: 2.10
+ Blank lines are not indented by default.
+
+ Rename the ``indentfirst`` argument to ``first``.
+ """
+ if indentfirst is not None:
warnings.warn(
"The 'indentfirst' argument is renamed to 'first' and will"
" be removed in version 3.0.",
DeprecationWarning,
stacklevel=2,
)
- first = indentfirst
-
+ first = indentfirst
+
indention = u" " * width
newline = u"\n"
-
+
if isinstance(s, Markup):
indention = Markup(indention)
newline = Markup(newline)
s += newline # this quirk is necessary for splitlines method
- if blank:
+ if blank:
rv = (newline + indention).join(s.splitlines())
- else:
- lines = s.splitlines()
- rv = lines.pop(0)
-
- if lines:
+ else:
+ lines = s.splitlines()
+ rv = lines.pop(0)
+
+ if lines:
rv += newline + newline.join(
- indention + line if line else line for line in lines
- )
-
- if first:
- rv = indention + rv
-
- return rv
-
-
-@environmentfilter
+ indention + line if line else line for line in lines
+ )
+
+ if first:
+ rv = indention + rv
+
+ return rv
+
+
+@environmentfilter
def do_truncate(env, s, length=255, killwords=False, end="...", leeway=None):
- """Return a truncated copy of the string. The length is specified
- with the first parameter which defaults to ``255``. If the second
- parameter is ``true`` the filter will cut the text at length. Otherwise
- it will discard the last word. If the text was in fact
- truncated it will append an ellipsis sign (``"..."``). If you want a
- different ellipsis sign than ``"..."`` you can specify it using the
- third parameter. Strings that only exceed the length by the tolerance
- margin given in the fourth parameter will not be truncated.
-
- .. sourcecode:: jinja
-
- {{ "foo bar baz qux"|truncate(9) }}
- -> "foo..."
- {{ "foo bar baz qux"|truncate(9, True) }}
- -> "foo ba..."
- {{ "foo bar baz qux"|truncate(11) }}
- -> "foo bar baz qux"
- {{ "foo bar baz qux"|truncate(11, False, '...', 0) }}
- -> "foo bar..."
-
+ """Return a truncated copy of the string. The length is specified
+ with the first parameter which defaults to ``255``. If the second
+ parameter is ``true`` the filter will cut the text at length. Otherwise
+ it will discard the last word. If the text was in fact
+ truncated it will append an ellipsis sign (``"..."``). If you want a
+ different ellipsis sign than ``"..."`` you can specify it using the
+ third parameter. Strings that only exceed the length by the tolerance
+ margin given in the fourth parameter will not be truncated.
+
+ .. sourcecode:: jinja
+
+ {{ "foo bar baz qux"|truncate(9) }}
+ -> "foo..."
+ {{ "foo bar baz qux"|truncate(9, True) }}
+ -> "foo ba..."
+ {{ "foo bar baz qux"|truncate(11) }}
+ -> "foo bar baz qux"
+ {{ "foo bar baz qux"|truncate(11, False, '...', 0) }}
+ -> "foo bar..."
+
The default leeway on newer Jinja versions is 5 and was 0 before but
- can be reconfigured globally.
- """
- if leeway is None:
+ can be reconfigured globally.
+ """
+ if leeway is None:
leeway = env.policies["truncate.leeway"]
assert length >= len(end), "expected length >= %s, got %s" % (len(end), length)
assert leeway >= 0, "expected leeway >= 0, got %s" % leeway
- if len(s) <= length + leeway:
- return s
- if killwords:
+ if len(s) <= length + leeway:
+ return s
+ if killwords:
return s[: length - len(end)] + end
result = s[: length - len(end)].rsplit(" ", 1)[0]
- return result + end
-
-
-@environmentfilter
+ return result + end
+
+
+@environmentfilter
def do_wordwrap(
environment,
s,
@@ -731,13 +731,13 @@ def do_wordwrap(
.. versionchanged:: 2.7
Added the ``wrapstring`` parameter.
- """
-
+ """
+
import textwrap
- if not wrapstring:
- wrapstring = environment.newline_sequence
-
+ if not wrapstring:
+ wrapstring = environment.newline_sequence
+
# textwrap.wrap doesn't consider existing newlines when wrapping.
# If the string has a newline before width, wrap will still insert
# a newline at width, resulting in a short line. Instead, split and
@@ -757,51 +757,51 @@ def do_wordwrap(
for line in s.splitlines()
]
)
+
-
-def do_wordcount(s):
- """Count the words in that string."""
+def do_wordcount(s):
+ """Count the words in that string."""
return len(_word_re.findall(soft_unicode(s)))
-
-
-def do_int(value, default=0, base=10):
- """Convert the value into an integer. If the
- conversion doesn't work it will return ``0``. You can
- override this default using the first parameter. You
- can also override the default base (10) in the second
- parameter, which handles input with prefixes such as
- 0b, 0o and 0x for bases 2, 8 and 16 respectively.
- The base is ignored for decimal numbers and non-string values.
- """
- try:
- if isinstance(value, string_types):
- return int(value, base)
- return int(value)
- except (TypeError, ValueError):
- # this quirk is necessary so that "42.23"|int gives 42.
- try:
- return int(float(value))
- except (TypeError, ValueError):
- return default
-
-
-def do_float(value, default=0.0):
- """Convert the value into a floating point number. If the
- conversion doesn't work it will return ``0.0``. You can
- override this default using the first parameter.
- """
- try:
- return float(value)
- except (TypeError, ValueError):
- return default
-
-
-def do_format(value, *args, **kwargs):
+
+
+def do_int(value, default=0, base=10):
+ """Convert the value into an integer. If the
+ conversion doesn't work it will return ``0``. You can
+ override this default using the first parameter. You
+ can also override the default base (10) in the second
+ parameter, which handles input with prefixes such as
+ 0b, 0o and 0x for bases 2, 8 and 16 respectively.
+ The base is ignored for decimal numbers and non-string values.
+ """
+ try:
+ if isinstance(value, string_types):
+ return int(value, base)
+ return int(value)
+ except (TypeError, ValueError):
+ # this quirk is necessary so that "42.23"|int gives 42.
+ try:
+ return int(float(value))
+ except (TypeError, ValueError):
+ return default
+
+
+def do_float(value, default=0.0):
+ """Convert the value into a floating point number. If the
+ conversion doesn't work it will return ``0.0``. You can
+ override this default using the first parameter.
+ """
+ try:
+ return float(value)
+ except (TypeError, ValueError):
+ return default
+
+
+def do_format(value, *args, **kwargs):
"""Apply the given values to a `printf-style`_ format string, like
``string % values``.
-
- .. sourcecode:: jinja
-
+
+ .. sourcecode:: jinja
+
{{ "%s, %s!"|format(greeting, name) }}
Hello, World!
@@ -815,151 +815,151 @@ def do_format(value, *args, **kwargs):
.. _printf-style: https://docs.python.org/library/stdtypes.html
#printf-style-string-formatting
- """
- if args and kwargs:
+ """
+ if args and kwargs:
raise FilterArgumentError(
"can't handle positional and keyword arguments at the same time"
)
- return soft_unicode(value) % (kwargs or args)
-
-
+ return soft_unicode(value) % (kwargs or args)
+
+
def do_trim(value, chars=None):
"""Strip leading and trailing characters, by default whitespace."""
return soft_unicode(value).strip(chars)
-
-
-def do_striptags(value):
+
+
+def do_striptags(value):
"""Strip SGML/XML tags and replace adjacent whitespace by one space."""
if hasattr(value, "__html__"):
- value = value.__html__()
- return Markup(text_type(value)).striptags()
-
-
-def do_slice(value, slices, fill_with=None):
- """Slice an iterator and return a list of lists containing
- those items. Useful if you want to create a div containing
- three ul tags that represent columns:
-
- .. sourcecode:: html+jinja
-
+ value = value.__html__()
+ return Markup(text_type(value)).striptags()
+
+
+def do_slice(value, slices, fill_with=None):
+ """Slice an iterator and return a list of lists containing
+ those items. Useful if you want to create a div containing
+ three ul tags that represent columns:
+
+ .. sourcecode:: html+jinja
+
<div class="columnwrapper">
- {%- for column in items|slice(3) %}
- <ul class="column-{{ loop.index }}">
- {%- for item in column %}
- <li>{{ item }}</li>
- {%- endfor %}
- </ul>
- {%- endfor %}
- </div>
-
- If you pass it a second argument it's used to fill missing
- values on the last iteration.
- """
- seq = list(value)
- length = len(seq)
- items_per_slice = length // slices
- slices_with_extra = length % slices
- offset = 0
- for slice_number in range(slices):
- start = offset + slice_number * items_per_slice
- if slice_number < slices_with_extra:
- offset += 1
- end = offset + (slice_number + 1) * items_per_slice
- tmp = seq[start:end]
- if fill_with is not None and slice_number >= slices_with_extra:
- tmp.append(fill_with)
- yield tmp
-
-
-def do_batch(value, linecount, fill_with=None):
- """
- A filter that batches items. It works pretty much like `slice`
- just the other way round. It returns a list of lists with the
- given number of items. If you provide a second parameter this
- is used to fill up missing items. See this example:
-
- .. sourcecode:: html+jinja
-
- <table>
- {%- for row in items|batch(3, '&nbsp;') %}
- <tr>
- {%- for column in row %}
- <td>{{ column }}</td>
- {%- endfor %}
- </tr>
- {%- endfor %}
- </table>
- """
- tmp = []
- for item in value:
- if len(tmp) == linecount:
- yield tmp
- tmp = []
- tmp.append(item)
- if tmp:
- if fill_with is not None and len(tmp) < linecount:
- tmp += [fill_with] * (linecount - len(tmp))
- yield tmp
-
-
+ {%- for column in items|slice(3) %}
+ <ul class="column-{{ loop.index }}">
+ {%- for item in column %}
+ <li>{{ item }}</li>
+ {%- endfor %}
+ </ul>
+ {%- endfor %}
+ </div>
+
+ If you pass it a second argument it's used to fill missing
+ values on the last iteration.
+ """
+ seq = list(value)
+ length = len(seq)
+ items_per_slice = length // slices
+ slices_with_extra = length % slices
+ offset = 0
+ for slice_number in range(slices):
+ start = offset + slice_number * items_per_slice
+ if slice_number < slices_with_extra:
+ offset += 1
+ end = offset + (slice_number + 1) * items_per_slice
+ tmp = seq[start:end]
+ if fill_with is not None and slice_number >= slices_with_extra:
+ tmp.append(fill_with)
+ yield tmp
+
+
+def do_batch(value, linecount, fill_with=None):
+ """
+ A filter that batches items. It works pretty much like `slice`
+ just the other way round. It returns a list of lists with the
+ given number of items. If you provide a second parameter this
+ is used to fill up missing items. See this example:
+
+ .. sourcecode:: html+jinja
+
+ <table>
+ {%- for row in items|batch(3, '&nbsp;') %}
+ <tr>
+ {%- for column in row %}
+ <td>{{ column }}</td>
+ {%- endfor %}
+ </tr>
+ {%- endfor %}
+ </table>
+ """
+ tmp = []
+ for item in value:
+ if len(tmp) == linecount:
+ yield tmp
+ tmp = []
+ tmp.append(item)
+ if tmp:
+ if fill_with is not None and len(tmp) < linecount:
+ tmp += [fill_with] * (linecount - len(tmp))
+ yield tmp
+
+
def do_round(value, precision=0, method="common"):
- """Round the number to a given precision. The first
- parameter specifies the precision (default is ``0``), the
- second the rounding method:
-
- - ``'common'`` rounds either up or down
- - ``'ceil'`` always rounds up
- - ``'floor'`` always rounds down
-
- If you don't specify a method ``'common'`` is used.
-
- .. sourcecode:: jinja
-
- {{ 42.55|round }}
- -> 43.0
- {{ 42.55|round(1, 'floor') }}
- -> 42.5
-
- Note that even if rounded to 0 precision, a float is returned. If
- you need a real integer, pipe it through `int`:
-
- .. sourcecode:: jinja
-
- {{ 42.55|round|int }}
- -> 43
- """
+ """Round the number to a given precision. The first
+ parameter specifies the precision (default is ``0``), the
+ second the rounding method:
+
+ - ``'common'`` rounds either up or down
+ - ``'ceil'`` always rounds up
+ - ``'floor'`` always rounds down
+
+ If you don't specify a method ``'common'`` is used.
+
+ .. sourcecode:: jinja
+
+ {{ 42.55|round }}
+ -> 43.0
+ {{ 42.55|round(1, 'floor') }}
+ -> 42.5
+
+ Note that even if rounded to 0 precision, a float is returned. If
+ you need a real integer, pipe it through `int`:
+
+ .. sourcecode:: jinja
+
+ {{ 42.55|round|int }}
+ -> 43
+ """
if method not in {"common", "ceil", "floor"}:
raise FilterArgumentError("method must be common, ceil or floor")
if method == "common":
- return round(value, precision)
- func = getattr(math, method)
- return func(value * (10 ** precision)) / (10 ** precision)
-
-
-# Use a regular tuple repr here. This is what we did in the past and we
-# really want to hide this custom type as much as possible. In particular
-# we do not want to accidentally expose an auto generated repr in case
-# people start to print this out in comments or something similar for
-# debugging.
+ return round(value, precision)
+ func = getattr(math, method)
+ return func(value * (10 ** precision)) / (10 ** precision)
+
+
+# Use a regular tuple repr here. This is what we did in the past and we
+# really want to hide this custom type as much as possible. In particular
+# we do not want to accidentally expose an auto generated repr in case
+# people start to print this out in comments or something similar for
+# debugging.
_GroupTuple = namedtuple("_GroupTuple", ["grouper", "list"])
-_GroupTuple.__repr__ = tuple.__repr__
-_GroupTuple.__str__ = tuple.__str__
-
+_GroupTuple.__repr__ = tuple.__repr__
+_GroupTuple.__str__ = tuple.__str__
+
-@environmentfilter
-def do_groupby(environment, value, attribute):
+@environmentfilter
+def do_groupby(environment, value, attribute):
"""Group a sequence of objects by an attribute using Python's
:func:`itertools.groupby`. The attribute can use dot notation for
nested access, like ``"address.city"``. Unlike Python's ``groupby``,
the values are sorted first so only one group is returned for each
unique value.
-
+
For example, a list of ``User`` objects with a ``city`` attribute
can be rendered in groups. In this example, ``grouper`` refers to
the ``city`` value of the group.
-
- .. sourcecode:: html+jinja
-
+
+ .. sourcecode:: html+jinja
+
<ul>{% for city, items in users|groupby("city") %}
<li>{{ city }}
<ul>{% for user in items %}
@@ -967,123 +967,123 @@ def do_groupby(environment, value, attribute):
{% endfor %}</ul>
</li>
{% endfor %}</ul>
-
+
``groupby`` yields namedtuples of ``(grouper, list)``, which
can be used instead of the tuple unpacking above. ``grouper`` is the
value of the attribute, and ``list`` is the items with that value.
-
- .. sourcecode:: html+jinja
-
+
+ .. sourcecode:: html+jinja
+
<ul>{% for group in users|groupby("city") %}
<li>{{ group.grouper }}: {{ group.list|join(", ") }}
{% endfor %}</ul>
-
- .. versionchanged:: 2.6
+
+ .. versionchanged:: 2.6
The attribute supports dot notation for nested access.
- """
- expr = make_attrgetter(environment, attribute)
+ """
+ expr = make_attrgetter(environment, attribute)
return [
_GroupTuple(key, list(values))
for key, values in groupby(sorted(value, key=expr), expr)
]
-
-
-@environmentfilter
-def do_sum(environment, iterable, attribute=None, start=0):
- """Returns the sum of a sequence of numbers plus the value of parameter
- 'start' (which defaults to 0). When the sequence is empty it returns
- start.
-
- It is also possible to sum up only certain attributes:
-
- .. sourcecode:: jinja
-
- Total: {{ items|sum(attribute='price') }}
-
- .. versionchanged:: 2.6
- The `attribute` parameter was added to allow suming up over
- attributes. Also the `start` parameter was moved on to the right.
- """
- if attribute is not None:
- iterable = imap(make_attrgetter(environment, attribute), iterable)
- return sum(iterable, start)
-
-
-def do_list(value):
- """Convert the value into a list. If it was a string the returned list
- will be a list of characters.
- """
- return list(value)
-
-
-def do_mark_safe(value):
- """Mark the value as safe which means that in an environment with automatic
- escaping enabled this variable will not be escaped.
- """
- return Markup(value)
-
-
-def do_mark_unsafe(value):
- """Mark a value as unsafe. This is the reverse operation for :func:`safe`."""
- return text_type(value)
-
-
-def do_reverse(value):
- """Reverse the object or return an iterator that iterates over it the other
- way round.
- """
- if isinstance(value, string_types):
- return value[::-1]
- try:
- return reversed(value)
- except TypeError:
- try:
- rv = list(value)
- rv.reverse()
- return rv
- except TypeError:
+
+
+@environmentfilter
+def do_sum(environment, iterable, attribute=None, start=0):
+ """Returns the sum of a sequence of numbers plus the value of parameter
+ 'start' (which defaults to 0). When the sequence is empty it returns
+ start.
+
+ It is also possible to sum up only certain attributes:
+
+ .. sourcecode:: jinja
+
+ Total: {{ items|sum(attribute='price') }}
+
+ .. versionchanged:: 2.6
+ The `attribute` parameter was added to allow suming up over
+ attributes. Also the `start` parameter was moved on to the right.
+ """
+ if attribute is not None:
+ iterable = imap(make_attrgetter(environment, attribute), iterable)
+ return sum(iterable, start)
+
+
+def do_list(value):
+ """Convert the value into a list. If it was a string the returned list
+ will be a list of characters.
+ """
+ return list(value)
+
+
+def do_mark_safe(value):
+ """Mark the value as safe which means that in an environment with automatic
+ escaping enabled this variable will not be escaped.
+ """
+ return Markup(value)
+
+
+def do_mark_unsafe(value):
+ """Mark a value as unsafe. This is the reverse operation for :func:`safe`."""
+ return text_type(value)
+
+
+def do_reverse(value):
+ """Reverse the object or return an iterator that iterates over it the other
+ way round.
+ """
+ if isinstance(value, string_types):
+ return value[::-1]
+ try:
+ return reversed(value)
+ except TypeError:
+ try:
+ rv = list(value)
+ rv.reverse()
+ return rv
+ except TypeError:
raise FilterArgumentError("argument must be iterable")
-
-
-@environmentfilter
-def do_attr(environment, obj, name):
- """Get an attribute of an object. ``foo|attr("bar")`` works like
- ``foo.bar`` just that always an attribute is returned and items are not
- looked up.
-
- See :ref:`Notes on subscriptions <notes-on-subscriptions>` for more details.
- """
- try:
- name = str(name)
- except UnicodeError:
- pass
- else:
- try:
- value = getattr(obj, name)
- except AttributeError:
- pass
- else:
+
+
+@environmentfilter
+def do_attr(environment, obj, name):
+ """Get an attribute of an object. ``foo|attr("bar")`` works like
+ ``foo.bar`` just that always an attribute is returned and items are not
+ looked up.
+
+ See :ref:`Notes on subscriptions <notes-on-subscriptions>` for more details.
+ """
+ try:
+ name = str(name)
+ except UnicodeError:
+ pass
+ else:
+ try:
+ value = getattr(obj, name)
+ except AttributeError:
+ pass
+ else:
if environment.sandboxed and not environment.is_safe_attribute(
obj, name, value
):
- return environment.unsafe_undefined(obj, name)
- return value
- return environment.undefined(obj=obj, name=name)
-
-
-@contextfilter
-def do_map(*args, **kwargs):
- """Applies a filter on a sequence of objects or looks up an attribute.
- This is useful when dealing with lists of objects but you are really
- only interested in a certain value of it.
-
- The basic usage is mapping on an attribute. Imagine you have a list
- of users but you are only interested in a list of usernames:
-
- .. sourcecode:: jinja
-
- Users on this page: {{ users|map(attribute='username')|join(', ') }}
-
+ return environment.unsafe_undefined(obj, name)
+ return value
+ return environment.undefined(obj=obj, name=name)
+
+
+@contextfilter
+def do_map(*args, **kwargs):
+ """Applies a filter on a sequence of objects or looks up an attribute.
+ This is useful when dealing with lists of objects but you are really
+ only interested in a certain value of it.
+
+ The basic usage is mapping on an attribute. Imagine you have a list
+ of users but you are only interested in a list of usernames:
+
+ .. sourcecode:: jinja
+
+ Users on this page: {{ users|map(attribute='username')|join(', ') }}
+
You can specify a ``default`` value to use if an object in the list
does not have the given attribute.
@@ -1091,14 +1091,14 @@ def do_map(*args, **kwargs):
{{ users|map(attribute="username", default="Anonymous")|join(", ") }}
- Alternatively you can let it invoke a filter by passing the name of the
- filter and the arguments afterwards. A good example would be applying a
- text conversion filter on a sequence:
-
- .. sourcecode:: jinja
-
- Users on this page: {{ titles|map('lower')|join(', ') }}
-
+ Alternatively you can let it invoke a filter by passing the name of the
+ filter and the arguments afterwards. A good example would be applying a
+ text conversion filter on a sequence:
+
+ .. sourcecode:: jinja
+
+ Users on this page: {{ titles|map('lower')|join(', ') }}
+
Similar to a generator comprehension such as:
.. code-block:: python
@@ -1110,31 +1110,31 @@ def do_map(*args, **kwargs):
.. versionchanged:: 2.11.0
Added the ``default`` parameter.
- .. versionadded:: 2.7
- """
- seq, func = prepare_map(args, kwargs)
- if seq:
- for item in seq:
- yield func(item)
-
-
-@contextfilter
-def do_select(*args, **kwargs):
- """Filters a sequence of objects by applying a test to each object,
- and only selecting the objects with the test succeeding.
-
- If no test is specified, each object will be evaluated as a boolean.
-
- Example usage:
-
- .. sourcecode:: jinja
-
- {{ numbers|select("odd") }}
- {{ numbers|select("odd") }}
- {{ numbers|select("divisibleby", 3) }}
- {{ numbers|select("lessthan", 42) }}
- {{ strings|select("equalto", "mystring") }}
-
+ .. versionadded:: 2.7
+ """
+ seq, func = prepare_map(args, kwargs)
+ if seq:
+ for item in seq:
+ yield func(item)
+
+
+@contextfilter
+def do_select(*args, **kwargs):
+ """Filters a sequence of objects by applying a test to each object,
+ and only selecting the objects with the test succeeding.
+
+ If no test is specified, each object will be evaluated as a boolean.
+
+ Example usage:
+
+ .. sourcecode:: jinja
+
+ {{ numbers|select("odd") }}
+ {{ numbers|select("odd") }}
+ {{ numbers|select("divisibleby", 3) }}
+ {{ numbers|select("lessthan", 42) }}
+ {{ strings|select("equalto", "mystring") }}
+
Similar to a generator comprehension such as:
.. code-block:: python
@@ -1142,51 +1142,51 @@ def do_select(*args, **kwargs):
(n for n in numbers if test_odd(n))
(n for n in numbers if test_divisibleby(n, 3))
- .. versionadded:: 2.7
- """
- return select_or_reject(args, kwargs, lambda x: x, False)
-
-
-@contextfilter
-def do_reject(*args, **kwargs):
- """Filters a sequence of objects by applying a test to each object,
- and rejecting the objects with the test succeeding.
-
- If no test is specified, each object will be evaluated as a boolean.
-
- Example usage:
-
- .. sourcecode:: jinja
-
- {{ numbers|reject("odd") }}
-
+ .. versionadded:: 2.7
+ """
+ return select_or_reject(args, kwargs, lambda x: x, False)
+
+
+@contextfilter
+def do_reject(*args, **kwargs):
+ """Filters a sequence of objects by applying a test to each object,
+ and rejecting the objects with the test succeeding.
+
+ If no test is specified, each object will be evaluated as a boolean.
+
+ Example usage:
+
+ .. sourcecode:: jinja
+
+ {{ numbers|reject("odd") }}
+
Similar to a generator comprehension such as:
.. code-block:: python
(n for n in numbers if not test_odd(n))
- .. versionadded:: 2.7
- """
- return select_or_reject(args, kwargs, lambda x: not x, False)
-
-
-@contextfilter
-def do_selectattr(*args, **kwargs):
- """Filters a sequence of objects by applying a test to the specified
- attribute of each object, and only selecting the objects with the
- test succeeding.
-
- If no test is specified, the attribute's value will be evaluated as
- a boolean.
-
- Example usage:
-
- .. sourcecode:: jinja
-
- {{ users|selectattr("is_active") }}
- {{ users|selectattr("email", "none") }}
-
+ .. versionadded:: 2.7
+ """
+ return select_or_reject(args, kwargs, lambda x: not x, False)
+
+
+@contextfilter
+def do_selectattr(*args, **kwargs):
+ """Filters a sequence of objects by applying a test to the specified
+ attribute of each object, and only selecting the objects with the
+ test succeeding.
+
+ If no test is specified, the attribute's value will be evaluated as
+ a boolean.
+
+ Example usage:
+
+ .. sourcecode:: jinja
+
+ {{ users|selectattr("is_active") }}
+ {{ users|selectattr("email", "none") }}
+
Similar to a generator comprehension such as:
.. code-block:: python
@@ -1194,25 +1194,25 @@ def do_selectattr(*args, **kwargs):
(u for user in users if user.is_active)
(u for user in users if test_none(user.email))
- .. versionadded:: 2.7
- """
- return select_or_reject(args, kwargs, lambda x: x, True)
-
-
-@contextfilter
-def do_rejectattr(*args, **kwargs):
- """Filters a sequence of objects by applying a test to the specified
- attribute of each object, and rejecting the objects with the test
- succeeding.
-
- If no test is specified, the attribute's value will be evaluated as
- a boolean.
-
- .. sourcecode:: jinja
-
- {{ users|rejectattr("is_active") }}
- {{ users|rejectattr("email", "none") }}
-
+ .. versionadded:: 2.7
+ """
+ return select_or_reject(args, kwargs, lambda x: x, True)
+
+
+@contextfilter
+def do_rejectattr(*args, **kwargs):
+ """Filters a sequence of objects by applying a test to the specified
+ attribute of each object, and rejecting the objects with the test
+ succeeding.
+
+ If no test is specified, the attribute's value will be evaluated as
+ a boolean.
+
+ .. sourcecode:: jinja
+
+ {{ users|rejectattr("is_active") }}
+ {{ users|rejectattr("email", "none") }}
+
Similar to a generator comprehension such as:
.. code-block:: python
@@ -1220,112 +1220,112 @@ def do_rejectattr(*args, **kwargs):
(u for user in users if not user.is_active)
(u for user in users if not test_none(user.email))
- .. versionadded:: 2.7
- """
- return select_or_reject(args, kwargs, lambda x: not x, True)
-
-
-@evalcontextfilter
-def do_tojson(eval_ctx, value, indent=None):
- """Dumps a structure to JSON so that it's safe to use in ``<script>``
- tags. It accepts the same arguments and returns a JSON string. Note that
- this is available in templates through the ``|tojson`` filter which will
- also mark the result as safe. Due to how this function escapes certain
- characters this is safe even if used outside of ``<script>`` tags.
-
- The following characters are escaped in strings:
-
- - ``<``
- - ``>``
- - ``&``
- - ``'``
-
- This makes it safe to embed such strings in any place in HTML with the
- notable exception of double quoted attributes. In that case single
- quote your attributes or HTML escape it in addition.
-
- The indent parameter can be used to enable pretty printing. Set it to
- the number of spaces that the structures should be indented with.
-
- Note that this filter is for use in HTML contexts only.
-
- .. versionadded:: 2.9
- """
- policies = eval_ctx.environment.policies
+ .. versionadded:: 2.7
+ """
+ return select_or_reject(args, kwargs, lambda x: not x, True)
+
+
+@evalcontextfilter
+def do_tojson(eval_ctx, value, indent=None):
+ """Dumps a structure to JSON so that it's safe to use in ``<script>``
+ tags. It accepts the same arguments and returns a JSON string. Note that
+ this is available in templates through the ``|tojson`` filter which will
+ also mark the result as safe. Due to how this function escapes certain
+ characters this is safe even if used outside of ``<script>`` tags.
+
+ The following characters are escaped in strings:
+
+ - ``<``
+ - ``>``
+ - ``&``
+ - ``'``
+
+ This makes it safe to embed such strings in any place in HTML with the
+ notable exception of double quoted attributes. In that case single
+ quote your attributes or HTML escape it in addition.
+
+ The indent parameter can be used to enable pretty printing. Set it to
+ the number of spaces that the structures should be indented with.
+
+ Note that this filter is for use in HTML contexts only.
+
+ .. versionadded:: 2.9
+ """
+ policies = eval_ctx.environment.policies
dumper = policies["json.dumps_function"]
options = policies["json.dumps_kwargs"]
- if indent is not None:
- options = dict(options)
+ if indent is not None:
+ options = dict(options)
options["indent"] = indent
- return htmlsafe_json_dumps(value, dumper=dumper, **options)
-
-
-def prepare_map(args, kwargs):
- context = args[0]
- seq = args[1]
+ return htmlsafe_json_dumps(value, dumper=dumper, **options)
+
+
+def prepare_map(args, kwargs):
+ context = args[0]
+ seq = args[1]
default = None
-
+
if len(args) == 2 and "attribute" in kwargs:
attribute = kwargs.pop("attribute")
default = kwargs.pop("default", None)
- if kwargs:
+ if kwargs:
raise FilterArgumentError(
"Unexpected keyword argument %r" % next(iter(kwargs))
)
func = make_attrgetter(context.environment, attribute, default=default)
- else:
- try:
- name = args[2]
- args = args[3:]
- except LookupError:
+ else:
+ try:
+ name = args[2]
+ args = args[3:]
+ except LookupError:
raise FilterArgumentError("map requires a filter argument")
-
+
def func(item):
return context.environment.call_filter(
name, item, args, kwargs, context=context
)
- return seq, func
-
-
-def prepare_select_or_reject(args, kwargs, modfunc, lookup_attr):
- context = args[0]
- seq = args[1]
- if lookup_attr:
- try:
- attr = args[2]
- except LookupError:
+ return seq, func
+
+
+def prepare_select_or_reject(args, kwargs, modfunc, lookup_attr):
+ context = args[0]
+ seq = args[1]
+ if lookup_attr:
+ try:
+ attr = args[2]
+ except LookupError:
raise FilterArgumentError("Missing parameter for attribute name")
- transfunc = make_attrgetter(context.environment, attr)
- off = 1
- else:
- off = 0
-
+ transfunc = make_attrgetter(context.environment, attr)
+ off = 1
+ else:
+ off = 0
+
def transfunc(x):
return x
- try:
- name = args[2 + off]
+ try:
+ name = args[2 + off]
args = args[3 + off :]
def func(item):
return context.environment.call_test(name, item, args, kwargs)
- except LookupError:
- func = bool
-
- return seq, lambda item: modfunc(func(transfunc(item)))
-
-
-def select_or_reject(args, kwargs, modfunc, lookup_attr):
- seq, func = prepare_select_or_reject(args, kwargs, modfunc, lookup_attr)
- if seq:
- for item in seq:
- if func(item):
- yield item
-
-
-FILTERS = {
+ except LookupError:
+ func = bool
+
+ return seq, lambda item: modfunc(func(transfunc(item)))
+
+
+def select_or_reject(args, kwargs, modfunc, lookup_attr):
+ seq, func = prepare_select_or_reject(args, kwargs, modfunc, lookup_attr)
+ if seq:
+ for item in seq:
+ if func(item):
+ yield item
+
+
+FILTERS = {
"abs": abs,
"attr": do_attr,
"batch": do_batch,
@@ -1379,4 +1379,4 @@ FILTERS = {
"wordwrap": do_wordwrap,
"xmlattr": do_xmlattr,
"tojson": do_tojson,
-}
+}
diff --git a/contrib/python/Jinja2/py2/jinja2/idtracking.py b/contrib/python/Jinja2/py2/jinja2/idtracking.py
index 9a0d838017..059b1fad0c 100644
--- a/contrib/python/Jinja2/py2/jinja2/idtracking.py
+++ b/contrib/python/Jinja2/py2/jinja2/idtracking.py
@@ -1,161 +1,161 @@
from ._compat import iteritems
from .visitor import NodeVisitor
-
+
VAR_LOAD_PARAMETER = "param"
VAR_LOAD_RESOLVE = "resolve"
VAR_LOAD_ALIAS = "alias"
VAR_LOAD_UNDEFINED = "undefined"
-
-
-def find_symbols(nodes, parent_symbols=None):
- sym = Symbols(parent=parent_symbols)
- visitor = FrameSymbolVisitor(sym)
- for node in nodes:
- visitor.visit(node)
- return sym
-
-
-def symbols_for_node(node, parent_symbols=None):
- sym = Symbols(parent=parent_symbols)
- sym.analyze_node(node)
- return sym
-
-
-class Symbols(object):
- def __init__(self, parent=None, level=None):
- if level is None:
- if parent is None:
- level = 0
- else:
- level = parent.level + 1
- self.level = level
- self.parent = parent
- self.refs = {}
- self.loads = {}
- self.stores = set()
-
- def analyze_node(self, node, **kwargs):
- visitor = RootVisitor(self)
- visitor.visit(node, **kwargs)
-
- def _define_ref(self, name, load=None):
+
+
+def find_symbols(nodes, parent_symbols=None):
+ sym = Symbols(parent=parent_symbols)
+ visitor = FrameSymbolVisitor(sym)
+ for node in nodes:
+ visitor.visit(node)
+ return sym
+
+
+def symbols_for_node(node, parent_symbols=None):
+ sym = Symbols(parent=parent_symbols)
+ sym.analyze_node(node)
+ return sym
+
+
+class Symbols(object):
+ def __init__(self, parent=None, level=None):
+ if level is None:
+ if parent is None:
+ level = 0
+ else:
+ level = parent.level + 1
+ self.level = level
+ self.parent = parent
+ self.refs = {}
+ self.loads = {}
+ self.stores = set()
+
+ def analyze_node(self, node, **kwargs):
+ visitor = RootVisitor(self)
+ visitor.visit(node, **kwargs)
+
+ def _define_ref(self, name, load=None):
ident = "l_%d_%s" % (self.level, name)
- self.refs[name] = ident
- if load is not None:
- self.loads[ident] = load
- return ident
-
- def find_load(self, target):
- if target in self.loads:
- return self.loads[target]
- if self.parent is not None:
- return self.parent.find_load(target)
-
- def find_ref(self, name):
- if name in self.refs:
- return self.refs[name]
- if self.parent is not None:
- return self.parent.find_ref(name)
-
- def ref(self, name):
- rv = self.find_ref(name)
- if rv is None:
+ self.refs[name] = ident
+ if load is not None:
+ self.loads[ident] = load
+ return ident
+
+ def find_load(self, target):
+ if target in self.loads:
+ return self.loads[target]
+ if self.parent is not None:
+ return self.parent.find_load(target)
+
+ def find_ref(self, name):
+ if name in self.refs:
+ return self.refs[name]
+ if self.parent is not None:
+ return self.parent.find_ref(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
)
- return rv
-
- def copy(self):
- rv = object.__new__(self.__class__)
- rv.__dict__.update(self.__dict__)
- rv.refs = self.refs.copy()
- rv.loads = self.loads.copy()
- rv.stores = self.stores.copy()
- return rv
-
- def store(self, name):
- self.stores.add(name)
-
- # If we have not see the name referenced yet, we need to figure
- # out what to set it to.
- if name not in self.refs:
- # If there is a parent scope we check if the name has a
- # reference there. If it does it means we might have to alias
- # to a variable there.
- if self.parent is not None:
- outer_ref = self.parent.find_ref(name)
- if outer_ref is not None:
- self._define_ref(name, load=(VAR_LOAD_ALIAS, outer_ref))
- return
-
- # Otherwise we can just set it to undefined.
- self._define_ref(name, load=(VAR_LOAD_UNDEFINED, None))
-
- def declare_parameter(self, name):
- self.stores.add(name)
- return self._define_ref(name, load=(VAR_LOAD_PARAMETER, None))
-
- def load(self, name):
- target = self.find_ref(name)
- if target is None:
- self._define_ref(name, load=(VAR_LOAD_RESOLVE, name))
-
- def branch_update(self, branch_symbols):
- stores = {}
- for branch in branch_symbols:
- for target in branch.stores:
- if target in self.stores:
- continue
- stores[target] = stores.get(target, 0) + 1
-
- for sym in branch_symbols:
- self.refs.update(sym.refs)
- self.loads.update(sym.loads)
- self.stores.update(sym.stores)
-
- for name, branch_count in iteritems(stores):
- if branch_count == len(branch_symbols):
- continue
- target = self.find_ref(name)
+ return rv
+
+ def copy(self):
+ rv = object.__new__(self.__class__)
+ rv.__dict__.update(self.__dict__)
+ rv.refs = self.refs.copy()
+ rv.loads = self.loads.copy()
+ rv.stores = self.stores.copy()
+ return rv
+
+ def store(self, name):
+ self.stores.add(name)
+
+ # If we have not see the name referenced yet, we need to figure
+ # out what to set it to.
+ if name not in self.refs:
+ # If there is a parent scope we check if the name has a
+ # reference there. If it does it means we might have to alias
+ # to a variable there.
+ if self.parent is not None:
+ outer_ref = self.parent.find_ref(name)
+ if outer_ref is not None:
+ self._define_ref(name, load=(VAR_LOAD_ALIAS, outer_ref))
+ return
+
+ # Otherwise we can just set it to undefined.
+ self._define_ref(name, load=(VAR_LOAD_UNDEFINED, None))
+
+ def declare_parameter(self, name):
+ self.stores.add(name)
+ return self._define_ref(name, load=(VAR_LOAD_PARAMETER, None))
+
+ def load(self, name):
+ target = self.find_ref(name)
+ if target is None:
+ self._define_ref(name, load=(VAR_LOAD_RESOLVE, name))
+
+ def branch_update(self, branch_symbols):
+ stores = {}
+ for branch in branch_symbols:
+ for target in branch.stores:
+ if target in self.stores:
+ continue
+ stores[target] = stores.get(target, 0) + 1
+
+ for sym in branch_symbols:
+ self.refs.update(sym.refs)
+ self.loads.update(sym.loads)
+ self.stores.update(sym.stores)
+
+ for name, branch_count in iteritems(stores):
+ if branch_count == len(branch_symbols):
+ continue
+ target = self.find_ref(name)
assert target is not None, "should not happen"
-
- if self.parent is not None:
- outer_target = self.parent.find_ref(name)
- if outer_target is not None:
- self.loads[target] = (VAR_LOAD_ALIAS, outer_target)
- continue
- self.loads[target] = (VAR_LOAD_RESOLVE, name)
-
- def dump_stores(self):
- rv = {}
- node = self
- while node is not None:
- for name in node.stores:
- if name not in rv:
- rv[name] = self.find_ref(name)
- node = node.parent
- return rv
-
- def dump_param_targets(self):
- rv = set()
- node = self
- while node is not None:
- for target, (instr, _) in iteritems(self.loads):
- if instr == VAR_LOAD_PARAMETER:
- rv.add(target)
- node = node.parent
- return rv
-
-
-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)
-
+
+ if self.parent is not None:
+ outer_target = self.parent.find_ref(name)
+ if outer_target is not None:
+ self.loads[target] = (VAR_LOAD_ALIAS, outer_target)
+ continue
+ self.loads[target] = (VAR_LOAD_RESOLVE, name)
+
+ def dump_stores(self):
+ rv = {}
+ node = self
+ while node is not None:
+ for name in node.stores:
+ if name not in rv:
+ rv[name] = self.find_ref(name)
+ node = node.parent
+ return rv
+
+ def dump_param_targets(self):
+ rv = set()
+ node = self
+ while node is not None:
+ for target, (instr, _) in iteritems(self.loads):
+ if instr == VAR_LOAD_PARAMETER:
+ rv.add(target)
+ node = node.parent
+ return rv
+
+
+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
) = (
@@ -163,128 +163,128 @@ class RootVisitor(NodeVisitor):
) = (
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):
+
+ 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",)):
- self.sym_visitor.visit(child)
-
- def visit_OverlayScope(self, node, **kwargs):
- for child in node.body:
- self.sym_visitor.visit(child)
-
+ 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":
- self.sym_visitor.visit(node.target, store_as_param=True)
- branch = node.body
+ self.sym_visitor.visit(node.target, store_as_param=True)
+ branch = node.body
elif for_branch == "else":
- branch = node.else_
+ branch = node.else_
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:
+ 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")
- for item in branch or ():
- self.sym_visitor.visit(item)
-
- def visit_With(self, node, **kwargs):
- for target in node.targets:
- self.sym_visitor.visit(target)
- for child in node.body:
- self.sym_visitor.visit(child)
-
- def generic_visit(self, node, *args, **kwargs):
+ for item in branch or ():
+ self.sym_visitor.visit(item)
+
+ def visit_With(self, node, **kwargs):
+ for target in node.targets:
+ self.sym_visitor.visit(target)
+ for child in node.body:
+ self.sym_visitor.visit(child)
+
+ def generic_visit(self, node, *args, **kwargs):
raise NotImplementedError(
"Cannot find symbols for %r" % node.__class__.__name__
)
-
-
-class FrameSymbolVisitor(NodeVisitor):
- """A visitor for `Frame.inspect`."""
-
- def __init__(self, symbols):
- self.symbols = symbols
-
- def visit_Name(self, node, store_as_param=False, **kwargs):
- """All assignments to names go through this function."""
+
+
+class FrameSymbolVisitor(NodeVisitor):
+ """A visitor for `Frame.inspect`."""
+
+ def __init__(self, symbols):
+ self.symbols = 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":
- self.symbols.declare_parameter(node.name)
+ self.symbols.declare_parameter(node.name)
elif node.ctx == "store":
- self.symbols.store(node.name)
+ self.symbols.store(node.name)
elif node.ctx == "load":
- self.symbols.load(node.name)
-
- def visit_NSRef(self, node, **kwargs):
- self.symbols.load(node.name)
-
- def visit_If(self, node, **kwargs):
- self.visit(node.test, **kwargs)
-
- original_symbols = self.symbols
-
- def inner_visit(nodes):
- self.symbols = rv = original_symbols.copy()
- for subnode in nodes:
- self.visit(subnode, **kwargs)
- self.symbols = original_symbols
- return rv
-
- body_symbols = inner_visit(node.body)
- elif_symbols = inner_visit(node.elif_)
- else_symbols = inner_visit(node.else_ or ())
-
- self.symbols.branch_update([body_symbols, elif_symbols, else_symbols])
-
- def visit_Macro(self, node, **kwargs):
- self.symbols.store(node.name)
-
- def visit_Import(self, node, **kwargs):
- self.generic_visit(node, **kwargs)
- self.symbols.store(node.target)
-
- def visit_FromImport(self, node, **kwargs):
- self.generic_visit(node, **kwargs)
- for name in node.names:
- if isinstance(name, tuple):
- self.symbols.store(name[1])
- else:
- self.symbols.store(name)
-
- def visit_Assign(self, node, **kwargs):
- """Visit assignments in the correct order."""
- self.visit(node.node, **kwargs)
- self.visit(node.target, **kwargs)
-
- def visit_For(self, node, **kwargs):
- """Visiting stops at for blocks. However the block sequence
- is visited as part of the outer scope.
- """
- self.visit(node.iter, **kwargs)
-
- def visit_CallBlock(self, node, **kwargs):
- self.visit(node.call, **kwargs)
-
- def visit_FilterBlock(self, node, **kwargs):
- self.visit(node.filter, **kwargs)
-
- def visit_With(self, node, **kwargs):
- for target in node.values:
- self.visit(target)
-
- def visit_AssignBlock(self, node, **kwargs):
- """Stop visiting at block assigns."""
- self.visit(node.target, **kwargs)
-
- def visit_Scope(self, node, **kwargs):
- """Stop visiting at scopes."""
-
- def visit_Block(self, node, **kwargs):
- """Stop visiting at blocks."""
-
- def visit_OverlayScope(self, node, **kwargs):
- """Do not visit into overlay scopes."""
+ self.symbols.load(node.name)
+
+ def visit_NSRef(self, node, **kwargs):
+ self.symbols.load(node.name)
+
+ def visit_If(self, node, **kwargs):
+ self.visit(node.test, **kwargs)
+
+ original_symbols = self.symbols
+
+ def inner_visit(nodes):
+ self.symbols = rv = original_symbols.copy()
+ for subnode in nodes:
+ self.visit(subnode, **kwargs)
+ self.symbols = original_symbols
+ return rv
+
+ body_symbols = inner_visit(node.body)
+ elif_symbols = inner_visit(node.elif_)
+ else_symbols = inner_visit(node.else_ or ())
+
+ self.symbols.branch_update([body_symbols, elif_symbols, else_symbols])
+
+ def visit_Macro(self, node, **kwargs):
+ self.symbols.store(node.name)
+
+ def visit_Import(self, node, **kwargs):
+ self.generic_visit(node, **kwargs)
+ self.symbols.store(node.target)
+
+ def visit_FromImport(self, node, **kwargs):
+ self.generic_visit(node, **kwargs)
+ for name in node.names:
+ if isinstance(name, tuple):
+ self.symbols.store(name[1])
+ else:
+ self.symbols.store(name)
+
+ def visit_Assign(self, node, **kwargs):
+ """Visit assignments in the correct order."""
+ self.visit(node.node, **kwargs)
+ self.visit(node.target, **kwargs)
+
+ def visit_For(self, node, **kwargs):
+ """Visiting stops at for blocks. However the block sequence
+ is visited as part of the outer scope.
+ """
+ self.visit(node.iter, **kwargs)
+
+ def visit_CallBlock(self, node, **kwargs):
+ self.visit(node.call, **kwargs)
+
+ def visit_FilterBlock(self, node, **kwargs):
+ self.visit(node.filter, **kwargs)
+
+ def visit_With(self, node, **kwargs):
+ for target in node.values:
+ self.visit(target)
+
+ def visit_AssignBlock(self, node, **kwargs):
+ """Stop visiting at block assigns."""
+ self.visit(node.target, **kwargs)
+
+ def visit_Scope(self, node, **kwargs):
+ """Stop visiting at scopes."""
+
+ def visit_Block(self, node, **kwargs):
+ """Stop visiting at blocks."""
+
+ def visit_OverlayScope(self, node, **kwargs):
+ """Do not visit into overlay scopes."""
diff --git a/contrib/python/Jinja2/py2/jinja2/lexer.py b/contrib/python/Jinja2/py2/jinja2/lexer.py
index 552356a12d..075484b88b 100644
--- a/contrib/python/Jinja2/py2/jinja2/lexer.py
+++ b/contrib/python/Jinja2/py2/jinja2/lexer.py
@@ -1,26 +1,26 @@
-# -*- coding: utf-8 -*-
+# -*- coding: utf-8 -*-
"""Implements a Jinja / Python combination lexer. The ``Lexer`` class
is used to do some preprocessing. It filters out invalid operators like
the bitshift operators we don't allow in templates. It separates
template code and python code in expressions.
-"""
-import re
+"""
+import re
from ast import literal_eval
-from collections import deque
-from operator import itemgetter
-
+from collections import deque
+from operator import itemgetter
+
from ._compat import implements_iterator
from ._compat import intern
from ._compat import iteritems
from ._compat import text_type
from .exceptions import TemplateSyntaxError
from .utils import LRUCache
-
-# cache for the lexers. Exists in order to be able to have multiple
-# environments with the same lexer
-_lexer_cache = LRUCache(50)
-
-# static regular expressions
+
+# cache for the lexers. Exists in order to be able to have multiple
+# environments with the same lexer
+_lexer_cache = LRUCache(50)
+
+# static regular expressions
whitespace_re = re.compile(r"\s+", re.U)
newline_re = re.compile(r"(\r\n|\r|\n)")
string_re = re.compile(
@@ -40,22 +40,22 @@ float_re = re.compile(
""",
re.IGNORECASE | re.VERBOSE,
)
-
-try:
- # check if this Python supports Unicode identifiers
+
+try:
+ # check if this Python supports Unicode identifiers
compile("föö", "<unknown>", "eval")
-except SyntaxError:
+except SyntaxError:
# Python 2, no Unicode support, use ASCII identifiers
name_re = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*")
- check_ident = False
-else:
+ check_ident = False
+else:
# Unicode support, import generated re pattern and set flag to use
# str.isidentifier to validate during lexing.
from ._identifier import pattern as name_re
- check_ident = True
-
-# internal the tokens and keep references to them
+ check_ident = True
+
+# internal the tokens and keep references to them
TOKEN_ADD = intern("add")
TOKEN_ASSIGN = intern("assign")
TOKEN_COLON = intern("colon")
@@ -105,9 +105,9 @@ TOKEN_LINECOMMENT = intern("linecomment")
TOKEN_DATA = intern("data")
TOKEN_INITIAL = intern("initial")
TOKEN_EOF = intern("eof")
-
-# bind operators to token types
-operators = {
+
+# bind operators to token types
+operators = {
"+": TOKEN_ADD,
"-": TOKEN_SUB,
"/": TOKEN_DIV,
@@ -134,14 +134,14 @@ operators = {
"|": TOKEN_PIPE,
",": TOKEN_COMMA,
";": TOKEN_SEMICOLON,
-}
-
-reverse_operators = dict([(v, k) for k, v in iteritems(operators)])
+}
+
+reverse_operators = dict([(v, k) for k, v in iteritems(operators)])
assert len(operators) == len(reverse_operators), "operators dropped"
operator_re = re.compile(
"(%s)" % "|".join(re.escape(x) for x in sorted(operators, key=lambda x: -len(x)))
)
-
+
ignored_tokens = frozenset(
[
TOKEN_COMMENT_BEGIN,
@@ -156,12 +156,12 @@ ignored_tokens = frozenset(
ignore_if_empty = frozenset(
[TOKEN_WHITESPACE, TOKEN_DATA, TOKEN_COMMENT, TOKEN_LINECOMMENT]
)
-
-
-def _describe_token_type(token_type):
- if token_type in reverse_operators:
- return reverse_operators[token_type]
- return {
+
+
+def _describe_token_type(token_type):
+ if token_type in reverse_operators:
+ return reverse_operators[token_type]
+ return {
TOKEN_COMMENT_BEGIN: "begin of comment",
TOKEN_COMMENT_END: "end of comment",
TOKEN_COMMENT: "comment",
@@ -174,38 +174,38 @@ def _describe_token_type(token_type):
TOKEN_LINESTATEMENT_END: "end of line statement",
TOKEN_DATA: "template data / text",
TOKEN_EOF: "end of template",
- }.get(token_type, token_type)
-
-
-def describe_token(token):
- """Returns a description of the token."""
+ }.get(token_type, token_type)
+
+
+def describe_token(token):
+ """Returns a description of the token."""
if token.type == TOKEN_NAME:
- return token.value
- return _describe_token_type(token.type)
-
-
-def describe_token_expr(expr):
- """Like `describe_token` but for token expressions."""
+ return token.value
+ return _describe_token_type(token.type)
+
+
+def describe_token_expr(expr):
+ """Like `describe_token` but for token expressions."""
if ":" in expr:
type, value = expr.split(":", 1)
if type == TOKEN_NAME:
- return value
- else:
- type = expr
- return _describe_token_type(type)
-
-
-def count_newlines(value):
- """Count the number of newline characters in the string. This is
- useful for extensions that filter a stream.
- """
- return len(newline_re.findall(value))
-
-
-def compile_rules(environment):
- """Compiles all the rules from the environment into a list of rules."""
- e = re.escape
- rules = [
+ return value
+ else:
+ type = expr
+ return _describe_token_type(type)
+
+
+def count_newlines(value):
+ """Count the number of newline characters in the string. This is
+ useful for extensions that filter a stream.
+ """
+ return len(newline_re.findall(value))
+
+
+def compile_rules(environment):
+ """Compiles all the rules from the environment into a list of rules."""
+ e = re.escape
+ rules = [
(
len(environment.comment_start_string),
TOKEN_COMMENT_BEGIN,
@@ -221,9 +221,9 @@ def compile_rules(environment):
TOKEN_VARIABLE_BEGIN,
e(environment.variable_start_string),
),
- ]
-
- if environment.line_statement_prefix is not None:
+ ]
+
+ if environment.line_statement_prefix is not None:
rules.append(
(
len(environment.line_statement_prefix),
@@ -231,7 +231,7 @@ def compile_rules(environment):
r"^[ \t\v]*" + e(environment.line_statement_prefix),
)
)
- if environment.line_comment_prefix is not None:
+ if environment.line_comment_prefix is not None:
rules.append(
(
len(environment.line_comment_prefix),
@@ -239,169 +239,169 @@ def compile_rules(environment):
r"(?:^|(?<=\S))[^\S\r\n]*" + e(environment.line_comment_prefix),
)
)
-
- return [x[1:] for x in sorted(rules, reverse=True)]
-
-
-class Failure(object):
- """Class that raises a `TemplateSyntaxError` if called.
- Used by the `Lexer` to specify known errors.
- """
-
- def __init__(self, message, cls=TemplateSyntaxError):
- self.message = message
- self.error_class = cls
-
- def __call__(self, lineno, filename):
- raise self.error_class(self.message, lineno, filename)
-
-
-class Token(tuple):
- """Token class."""
-
- __slots__ = ()
- lineno, type, value = (property(itemgetter(x)) for x in range(3))
-
- def __new__(cls, lineno, type, value):
- return tuple.__new__(cls, (lineno, intern(str(type)), value))
-
- def __str__(self):
- if self.type in reverse_operators:
- return reverse_operators[self.type]
+
+ return [x[1:] for x in sorted(rules, reverse=True)]
+
+
+class Failure(object):
+ """Class that raises a `TemplateSyntaxError` if called.
+ Used by the `Lexer` to specify known errors.
+ """
+
+ def __init__(self, message, cls=TemplateSyntaxError):
+ self.message = message
+ self.error_class = cls
+
+ def __call__(self, lineno, filename):
+ raise self.error_class(self.message, lineno, filename)
+
+
+class Token(tuple):
+ """Token class."""
+
+ __slots__ = ()
+ lineno, type, value = (property(itemgetter(x)) for x in range(3))
+
+ def __new__(cls, lineno, type, value):
+ return tuple.__new__(cls, (lineno, intern(str(type)), value))
+
+ def __str__(self):
+ if self.type in reverse_operators:
+ return reverse_operators[self.type]
elif self.type == "name":
- return self.value
- return self.type
-
- def test(self, expr):
- """Test a token against a token expression. This can either be a
- token type or ``'token_type:token_value'``. This can only test
- against string values and types.
- """
- # here we do a regular string equality check as test_any is usually
- # passed an iterable of not interned strings.
- if self.type == expr:
- return True
+ return self.value
+ return self.type
+
+ def test(self, expr):
+ """Test a token against a token expression. This can either be a
+ token type or ``'token_type:token_value'``. This can only test
+ against string values and types.
+ """
+ # here we do a regular string equality check as test_any is usually
+ # passed an iterable of not interned strings.
+ if self.type == expr:
+ return True
elif ":" in expr:
return expr.split(":", 1) == [self.type, self.value]
- return False
-
- def test_any(self, *iterable):
- """Test against multiple token expressions."""
- for expr in iterable:
- if self.test(expr):
- return True
- return False
-
- def __repr__(self):
+ return False
+
+ def test_any(self, *iterable):
+ """Test against multiple token expressions."""
+ for expr in iterable:
+ if self.test(expr):
+ return True
+ return False
+
+ def __repr__(self):
return "Token(%r, %r, %r)" % (self.lineno, self.type, self.value)
-
-
-@implements_iterator
-class TokenStreamIterator(object):
- """The iterator for tokenstreams. Iterate over the stream
- until the eof token is reached.
- """
-
- def __init__(self, stream):
- self.stream = stream
-
- def __iter__(self):
- return self
-
- def __next__(self):
- token = self.stream.current
- if token.type is TOKEN_EOF:
- self.stream.close()
- raise StopIteration()
- next(self.stream)
- return token
-
-
-@implements_iterator
-class TokenStream(object):
- """A token stream is an iterable that yields :class:`Token`\\s. The
- parser however does not iterate over it but calls :meth:`next` to go
- one token ahead. The current active token is stored as :attr:`current`.
- """
-
- def __init__(self, generator, name, filename):
- self._iter = iter(generator)
- self._pushed = deque()
- self.name = name
- self.filename = filename
- self.closed = False
+
+
+@implements_iterator
+class TokenStreamIterator(object):
+ """The iterator for tokenstreams. Iterate over the stream
+ until the eof token is reached.
+ """
+
+ def __init__(self, stream):
+ self.stream = stream
+
+ def __iter__(self):
+ return self
+
+ def __next__(self):
+ token = self.stream.current
+ if token.type is TOKEN_EOF:
+ self.stream.close()
+ raise StopIteration()
+ next(self.stream)
+ return token
+
+
+@implements_iterator
+class TokenStream(object):
+ """A token stream is an iterable that yields :class:`Token`\\s. The
+ parser however does not iterate over it but calls :meth:`next` to go
+ one token ahead. The current active token is stored as :attr:`current`.
+ """
+
+ def __init__(self, generator, name, filename):
+ self._iter = iter(generator)
+ self._pushed = deque()
+ self.name = name
+ self.filename = filename
+ self.closed = False
self.current = Token(1, TOKEN_INITIAL, "")
- next(self)
-
- def __iter__(self):
- return TokenStreamIterator(self)
-
- def __bool__(self):
- return bool(self._pushed) or self.current.type is not TOKEN_EOF
-
- __nonzero__ = __bool__ # py2
-
+ next(self)
+
+ def __iter__(self):
+ return TokenStreamIterator(self)
+
+ def __bool__(self):
+ return bool(self._pushed) or self.current.type is not TOKEN_EOF
+
+ __nonzero__ = __bool__ # py2
+
@property
def eos(self):
"""Are we at the end of the stream?"""
return not self
-
- def push(self, token):
- """Push a token back to the stream."""
- self._pushed.append(token)
-
- def look(self):
- """Look at the next token."""
- old_token = next(self)
- result = self.current
- self.push(result)
- self.current = old_token
- return result
-
- def skip(self, n=1):
- """Got n tokens ahead."""
+
+ def push(self, token):
+ """Push a token back to the stream."""
+ self._pushed.append(token)
+
+ def look(self):
+ """Look at the next token."""
+ old_token = next(self)
+ result = self.current
+ self.push(result)
+ self.current = old_token
+ return result
+
+ def skip(self, n=1):
+ """Got n tokens ahead."""
for _ in range(n):
- next(self)
-
- def next_if(self, expr):
- """Perform the token test and return the token if it matched.
- Otherwise the return value is `None`.
- """
- if self.current.test(expr):
- return next(self)
-
- def skip_if(self, expr):
- """Like :meth:`next_if` but only returns `True` or `False`."""
- return self.next_if(expr) is not None
-
- def __next__(self):
- """Go one token ahead and return the old one.
-
- Use the built-in :func:`next` instead of calling this directly.
- """
- rv = self.current
- if self._pushed:
- self.current = self._pushed.popleft()
- elif self.current.type is not TOKEN_EOF:
- try:
- self.current = next(self._iter)
- except StopIteration:
- self.close()
- return rv
-
- def close(self):
- """Close the stream."""
+ next(self)
+
+ def next_if(self, expr):
+ """Perform the token test and return the token if it matched.
+ Otherwise the return value is `None`.
+ """
+ if self.current.test(expr):
+ return next(self)
+
+ def skip_if(self, expr):
+ """Like :meth:`next_if` but only returns `True` or `False`."""
+ return self.next_if(expr) is not None
+
+ def __next__(self):
+ """Go one token ahead and return the old one.
+
+ Use the built-in :func:`next` instead of calling this directly.
+ """
+ rv = self.current
+ if self._pushed:
+ self.current = self._pushed.popleft()
+ elif self.current.type is not TOKEN_EOF:
+ try:
+ self.current = next(self._iter)
+ except StopIteration:
+ self.close()
+ return rv
+
+ def close(self):
+ """Close the stream."""
self.current = Token(self.current.lineno, TOKEN_EOF, "")
- self._iter = None
- self.closed = True
-
- def expect(self, expr):
- """Expect a given token type and return it. This accepts the same
- argument as :meth:`jinja2.lexer.Token.test`.
- """
- if not self.current.test(expr):
- expr = describe_token_expr(expr)
- if self.current.type is TOKEN_EOF:
+ self._iter = None
+ self.closed = True
+
+ def expect(self, expr):
+ """Expect a given token type and return it. This accepts the same
+ argument as :meth:`jinja2.lexer.Token.test`.
+ """
+ if not self.current.test(expr):
+ expr = describe_token_expr(expr)
+ if self.current.type is TOKEN_EOF:
raise TemplateSyntaxError(
"unexpected end of template, expected %r." % expr,
self.current.lineno,
@@ -414,14 +414,14 @@ class TokenStream(object):
self.name,
self.filename,
)
- try:
- return self.current
- finally:
- next(self)
-
-
-def get_lexer(environment):
- """Return a lexer which is probably cached."""
+ try:
+ return self.current
+ finally:
+ next(self)
+
+
+def get_lexer(environment):
+ """Return a lexer which is probably cached."""
key = (
environment.block_start_string,
environment.block_end_string,
@@ -436,13 +436,13 @@ def get_lexer(environment):
environment.newline_sequence,
environment.keep_trailing_newline,
)
- lexer = _lexer_cache.get(key)
- if lexer is None:
- lexer = Lexer(environment)
- _lexer_cache[key] = lexer
- return lexer
-
-
+ lexer = _lexer_cache.get(key)
+ if lexer is None:
+ lexer = Lexer(environment)
+ _lexer_cache[key] = lexer
+ return lexer
+
+
class OptionalLStrip(tuple):
"""A special tuple for marking a point in the state that can have
lstrip applied.
@@ -456,53 +456,53 @@ class OptionalLStrip(tuple):
return super(OptionalLStrip, cls).__new__(cls, members)
-class Lexer(object):
- """Class that implements a lexer for a given environment. Automatically
- created by the environment class, usually you don't have to do that.
-
- Note that the lexer is not automatically bound to an environment.
- Multiple environments can share the same lexer.
- """
-
- def __init__(self, environment):
- # shortcuts
- e = re.escape
-
+class Lexer(object):
+ """Class that implements a lexer for a given environment. Automatically
+ created by the environment class, usually you don't have to do that.
+
+ Note that the lexer is not automatically bound to an environment.
+ Multiple environments can share the same lexer.
+ """
+
+ def __init__(self, environment):
+ # shortcuts
+ e = re.escape
+
def c(x):
return re.compile(x, re.M | re.S)
- # lexing rules for tags
- tag_rules = [
- (whitespace_re, TOKEN_WHITESPACE, None),
- (float_re, TOKEN_FLOAT, None),
- (integer_re, TOKEN_INTEGER, None),
- (name_re, TOKEN_NAME, None),
- (string_re, TOKEN_STRING, None),
+ # lexing rules for tags
+ tag_rules = [
+ (whitespace_re, TOKEN_WHITESPACE, None),
+ (float_re, TOKEN_FLOAT, None),
+ (integer_re, TOKEN_INTEGER, None),
+ (name_re, TOKEN_NAME, None),
+ (string_re, TOKEN_STRING, None),
(operator_re, TOKEN_OPERATOR, None),
- ]
-
- # assemble the root lexing rule. because "|" is ungreedy
- # we have to sort by length so that the lexer continues working
- # as expected when we have parsing rules like <% for block and
- # <%= for variables. (if someone wants asp like syntax)
- # variables are just part of the rules if variable processing
- # is required.
- root_tag_rules = compile_rules(environment)
-
- # block suffix if trimming is enabled
+ ]
+
+ # assemble the root lexing rule. because "|" is ungreedy
+ # we have to sort by length so that the lexer continues working
+ # as expected when we have parsing rules like <% for block and
+ # <%= for variables. (if someone wants asp like syntax)
+ # variables are just part of the rules if variable processing
+ # is required.
+ root_tag_rules = compile_rules(environment)
+
+ # block suffix if trimming is enabled
block_suffix_re = environment.trim_blocks and "\\n?" or ""
-
+
# If lstrip is enabled, it should not be applied if there is any
# non-whitespace between the newline and block.
self.lstrip_unless_re = c(r"[^ \t]") if environment.lstrip_blocks else None
-
- self.newline_sequence = environment.newline_sequence
- self.keep_trailing_newline = environment.keep_trailing_newline
-
- # global lexing rules
- self.rules = {
+
+ self.newline_sequence = environment.newline_sequence
+ self.keep_trailing_newline = environment.keep_trailing_newline
+
+ # global lexing rules
+ self.rules = {
"root": [
- # directives
+ # directives
(
c(
"(.*?)(?:%s)"
@@ -524,11 +524,11 @@ class Lexer(object):
OptionalLStrip(TOKEN_DATA, "#bygroup"),
"#bygroup",
),
- # data
+ # data
(c(".+"), TOKEN_DATA, None),
- ],
- # comments
- TOKEN_COMMENT_BEGIN: [
+ ],
+ # comments
+ TOKEN_COMMENT_BEGIN: [
(
c(
r"(.*?)((?:\-%s\s*|%s)%s)"
@@ -542,9 +542,9 @@ class Lexer(object):
"#pop",
),
(c("(.)"), (Failure("Missing end of comment tag"),), None),
- ],
- # blocks
- TOKEN_BLOCK_BEGIN: [
+ ],
+ # blocks
+ TOKEN_BLOCK_BEGIN: [
(
c(
r"(?:\-%s\s*|%s)%s"
@@ -559,8 +559,8 @@ class Lexer(object):
),
]
+ tag_rules,
- # variables
- TOKEN_VARIABLE_BEGIN: [
+ # variables
+ TOKEN_VARIABLE_BEGIN: [
(
c(
r"\-%s\s*|%s"
@@ -574,8 +574,8 @@ class Lexer(object):
)
]
+ tag_rules,
- # raw block
- TOKEN_RAW_BEGIN: [
+ # raw block
+ TOKEN_RAW_BEGIN: [
(
c(
r"(.*?)((?:%s(\-|\+|))\s*endraw\s*(?:\-%s\s*|%s%s))"
@@ -590,121 +590,121 @@ class Lexer(object):
"#pop",
),
(c("(.)"), (Failure("Missing end of raw directive"),), None),
- ],
- # line statements
- TOKEN_LINESTATEMENT_BEGIN: [
+ ],
+ # line statements
+ TOKEN_LINESTATEMENT_BEGIN: [
(c(r"\s*(\n|$)"), TOKEN_LINESTATEMENT_END, "#pop")
]
+ tag_rules,
- # line comments
- TOKEN_LINECOMMENT_BEGIN: [
+ # line comments
+ TOKEN_LINECOMMENT_BEGIN: [
(
c(r"(.*?)()(?=\n|$)"),
(TOKEN_LINECOMMENT, TOKEN_LINECOMMENT_END),
"#pop",
)
],
- }
-
- def _normalize_newlines(self, value):
- """Called for strings and template data to normalize it to unicode."""
- return newline_re.sub(self.newline_sequence, value)
-
- def tokenize(self, source, name=None, filename=None, state=None):
+ }
+
+ def _normalize_newlines(self, value):
+ """Called for strings and template data to normalize it to unicode."""
+ return newline_re.sub(self.newline_sequence, value)
+
+ def tokenize(self, source, name=None, filename=None, state=None):
"""Calls tokeniter + tokenize and wraps it in a token stream."""
- stream = self.tokeniter(source, name, filename, state)
- return TokenStream(self.wrap(stream, name, filename), name, filename)
-
- def wrap(self, stream, name=None, filename=None):
- """This is called with the stream as returned by `tokenize` and wraps
- every token in a :class:`Token` and converts the value.
- """
- for lineno, token, value in stream:
- if token in ignored_tokens:
- continue
+ stream = self.tokeniter(source, name, filename, state)
+ return TokenStream(self.wrap(stream, name, filename), name, filename)
+
+ def wrap(self, stream, name=None, filename=None):
+ """This is called with the stream as returned by `tokenize` and wraps
+ every token in a :class:`Token` and converts the value.
+ """
+ for lineno, token, value in stream:
+ if token in ignored_tokens:
+ continue
elif token == TOKEN_LINESTATEMENT_BEGIN:
token = TOKEN_BLOCK_BEGIN
elif token == TOKEN_LINESTATEMENT_END:
token = TOKEN_BLOCK_END
- # we are not interested in those tokens in the parser
+ # we are not interested in those tokens in the parser
elif token in (TOKEN_RAW_BEGIN, TOKEN_RAW_END):
- continue
+ continue
elif token == TOKEN_DATA:
- value = self._normalize_newlines(value)
+ value = self._normalize_newlines(value)
elif token == "keyword":
- token = value
+ token = value
elif token == TOKEN_NAME:
- value = str(value)
- if check_ident and not value.isidentifier():
- raise TemplateSyntaxError(
+ value = str(value)
+ if check_ident and not value.isidentifier():
+ raise TemplateSyntaxError(
"Invalid character in identifier", lineno, name, filename
)
elif token == TOKEN_STRING:
- # try to unescape string
- try:
+ # try to unescape string
+ try:
value = (
self._normalize_newlines(value[1:-1])
.encode("ascii", "backslashreplace")
.decode("unicode-escape")
)
- except Exception as e:
+ except Exception as e:
msg = str(e).split(":")[-1].strip()
- raise TemplateSyntaxError(msg, lineno, name, filename)
+ raise TemplateSyntaxError(msg, lineno, name, filename)
elif token == TOKEN_INTEGER:
value = int(value.replace("_", ""))
elif token == TOKEN_FLOAT:
# remove all "_" first to support more Python versions
value = literal_eval(value.replace("_", ""))
elif token == TOKEN_OPERATOR:
- token = operators[value]
- yield Token(lineno, token, value)
-
- def tokeniter(self, source, name, filename=None, state=None):
- """This method tokenizes the text and returns the tokens in a
- generator. Use this method if you just want to tokenize a template.
- """
- source = text_type(source)
- lines = source.splitlines()
- if self.keep_trailing_newline and source:
+ token = operators[value]
+ yield Token(lineno, token, value)
+
+ def tokeniter(self, source, name, filename=None, state=None):
+ """This method tokenizes the text and returns the tokens in a
+ generator. Use this method if you just want to tokenize a template.
+ """
+ source = text_type(source)
+ lines = source.splitlines()
+ if self.keep_trailing_newline and source:
for newline in ("\r\n", "\r", "\n"):
- if source.endswith(newline):
+ if source.endswith(newline):
lines.append("")
- break
+ break
source = "\n".join(lines)
- pos = 0
- lineno = 1
+ pos = 0
+ lineno = 1
stack = ["root"]
if state is not None and state != "root":
assert state in ("variable", "block"), "invalid state"
stack.append(state + "_begin")
- statetokens = self.rules[stack[-1]]
- source_length = len(source)
- balancing_stack = []
+ statetokens = self.rules[stack[-1]]
+ source_length = len(source)
+ balancing_stack = []
lstrip_unless_re = self.lstrip_unless_re
newlines_stripped = 0
line_starting = True
-
- while 1:
- # tokenizer loop
- for regex, tokens, new_state in statetokens:
- m = regex.match(source, pos)
- # if no match we try again with the next rule
- if m is None:
- continue
-
- # we only match blocks and variables if braces / parentheses
- # are balanced. continue parsing with the lower rule which
- # is the operator rule. do this only if the end tags look
- # like operators
+
+ while 1:
+ # tokenizer loop
+ for regex, tokens, new_state in statetokens:
+ m = regex.match(source, pos)
+ # if no match we try again with the next rule
+ if m is None:
+ continue
+
+ # we only match blocks and variables if braces / parentheses
+ # are balanced. continue parsing with the lower rule which
+ # is the operator rule. do this only if the end tags look
+ # like operators
if balancing_stack and tokens in (
TOKEN_VARIABLE_END,
TOKEN_BLOCK_END,
TOKEN_LINESTATEMENT_END,
):
- continue
-
- # tuples support more options
- if isinstance(tokens, tuple):
+ continue
+
+ # tuples support more options
+ if isinstance(tokens, tuple):
groups = m.groups()
if isinstance(tokens, OptionalLStrip):
@@ -738,37 +738,37 @@ class Lexer(object):
if not lstrip_unless_re.search(text, l_pos):
groups = (text[:l_pos],) + groups[1:]
- for idx, token in enumerate(tokens):
- # failure group
- if token.__class__ is Failure:
- raise token(lineno, filename)
- # bygroup is a bit more complex, in that case we
- # yield for the current token the first named
- # group that matched
+ for idx, token in enumerate(tokens):
+ # failure group
+ if token.__class__ is Failure:
+ raise token(lineno, filename)
+ # bygroup is a bit more complex, in that case we
+ # yield for the current token the first named
+ # group that matched
elif token == "#bygroup":
- for key, value in iteritems(m.groupdict()):
- if value is not None:
- yield lineno, key, value
+ for key, value in iteritems(m.groupdict()):
+ if value is not None:
+ yield lineno, key, value
lineno += value.count("\n")
- break
- else:
+ break
+ else:
raise RuntimeError(
"%r wanted to resolve "
"the token dynamically"
" but no group matched" % regex
)
- # normal group
- else:
+ # normal group
+ else:
data = groups[idx]
- if data or token not in ignore_if_empty:
- yield lineno, token, data
+ if data or token not in ignore_if_empty:
+ yield lineno, token, data
lineno += data.count("\n") + newlines_stripped
newlines_stripped = 0
-
- # strings as token just are yielded as it.
- else:
- data = m.group()
- # update brace/parentheses balance
+
+ # strings as token just are yielded as it.
+ else:
+ data = m.group()
+ # update brace/parentheses balance
if tokens == TOKEN_OPERATOR:
if data == "{":
balancing_stack.append("}")
@@ -777,12 +777,12 @@ class Lexer(object):
elif data == "[":
balancing_stack.append("]")
elif data in ("}", ")", "]"):
- if not balancing_stack:
+ if not balancing_stack:
raise TemplateSyntaxError(
"unexpected '%s'" % data, lineno, name, filename
)
- expected_op = balancing_stack.pop()
- if expected_op != data:
+ expected_op = balancing_stack.pop()
+ if expected_op != data:
raise TemplateSyntaxError(
"unexpected '%s', "
"expected '%s'" % (data, expected_op),
@@ -790,56 +790,56 @@ class Lexer(object):
name,
filename,
)
- # yield items
- if data or tokens not in ignore_if_empty:
- yield lineno, tokens, data
+ # yield items
+ if data or tokens not in ignore_if_empty:
+ 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
- pos2 = m.end()
-
- # handle state changes
- if new_state is not None:
- # remove the uppermost state
+ # 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
+ pos2 = m.end()
+
+ # handle state changes
+ if new_state is not None:
+ # remove the uppermost state
if new_state == "#pop":
- stack.pop()
- # resolve the new state by group checking
+ stack.pop()
+ # resolve the new state by group checking
elif new_state == "#bygroup":
- for key, value in iteritems(m.groupdict()):
- if value is not None:
- stack.append(key)
- break
- else:
+ for key, value in iteritems(m.groupdict()):
+ if value is not None:
+ stack.append(key)
+ break
+ else:
raise RuntimeError(
"%r wanted to resolve the "
"new state dynamically but"
" no group matched" % regex
)
- # direct state name given
- else:
- stack.append(new_state)
- statetokens = self.rules[stack[-1]]
- # we are still at the same position and no stack change.
- # this means a loop without break condition, avoid that and
- # raise error
- elif pos2 == pos:
+ # direct state name given
+ else:
+ stack.append(new_state)
+ statetokens = self.rules[stack[-1]]
+ # we are still at the same position and no stack change.
+ # this means a loop without break condition, avoid that and
+ # raise error
+ elif pos2 == pos:
raise RuntimeError(
"%r yielded empty string without stack change" % regex
)
- # publish new function and start again
- pos = pos2
- break
- # if loop terminated without break we haven't found a single match
- # either we are at the end of the file or we have a problem
- else:
- # end of text
- if pos >= source_length:
- return
- # something went wrong
+ # publish new function and start again
+ pos = pos2
+ break
+ # if loop terminated without break we haven't found a single match
+ # either we are at the end of the file or we have a problem
+ else:
+ # end of text
+ if pos >= source_length:
+ return
+ # something went wrong
raise TemplateSyntaxError(
"unexpected char %r at %d" % (source[pos], pos),
lineno,
diff --git a/contrib/python/Jinja2/py2/jinja2/loaders.py b/contrib/python/Jinja2/py2/jinja2/loaders.py
index bad1774ab0..8bd29db208 100644
--- a/contrib/python/Jinja2/py2/jinja2/loaders.py
+++ b/contrib/python/Jinja2/py2/jinja2/loaders.py
@@ -1,14 +1,14 @@
-# -*- coding: utf-8 -*-
+# -*- coding: utf-8 -*-
"""API and implementations for loading templates from different data
sources.
-"""
-import os
-import sys
-import weakref
+"""
+import os
+import sys
+import weakref
from hashlib import sha1
from os import path
-from types import ModuleType
-
+from types import ModuleType
+
from ._compat import abc
from ._compat import fspath
from ._compat import iteritems
@@ -16,503 +16,503 @@ 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 = []
+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
):
- raise TemplateNotFound(template)
+ raise TemplateNotFound(template)
elif piece and piece != ".":
- pieces.append(piece)
- return pieces
-
-
-class BaseLoader(object):
- """Baseclass for all loaders. Subclass this and override `get_source` to
- implement a custom loading mechanism. The environment provides a
- `get_template` method that calls the loader's `load` method to get the
- :class:`Template` object.
-
- A very basic example for a loader that looks up templates on the file
- system could look like this::
-
- from jinja2 import BaseLoader, TemplateNotFound
- from os.path import join, exists, getmtime
-
- class MyLoader(BaseLoader):
-
- def __init__(self, path):
- self.path = path
-
- def get_source(self, environment, template):
- path = join(self.path, template)
- if not exists(path):
- raise TemplateNotFound(template)
- mtime = getmtime(path)
- with file(path) as f:
- source = f.read().decode('utf-8')
- return source, path, lambda: mtime == getmtime(path)
- """
-
- #: if set to `False` it indicates that the loader cannot provide access
- #: to the source of templates.
- #:
- #: .. versionadded:: 2.4
- has_source_access = True
-
- def get_source(self, environment, template):
- """Get the template source, filename and reload helper for a template.
- It's passed the environment and template name and has to return a
- tuple in the form ``(source, filename, uptodate)`` or raise a
- `TemplateNotFound` error if it can't locate the template.
-
- The source part of the returned tuple must be the source of the
- template as unicode string or a ASCII bytestring. The filename should
- be the name of the file on the filesystem if it was loaded from there,
- otherwise `None`. The filename is used by python for the tracebacks
- if no loader extension is used.
-
- The last item in the tuple is the `uptodate` function. If auto
- reloading is enabled it's always called to check if the template
- changed. No arguments are passed so the function must store the
- old state somewhere (for example in a closure). If it returns `False`
- the template will be reloaded.
- """
- if not self.has_source_access:
+ pieces.append(piece)
+ return pieces
+
+
+class BaseLoader(object):
+ """Baseclass for all loaders. Subclass this and override `get_source` to
+ implement a custom loading mechanism. The environment provides a
+ `get_template` method that calls the loader's `load` method to get the
+ :class:`Template` object.
+
+ A very basic example for a loader that looks up templates on the file
+ system could look like this::
+
+ from jinja2 import BaseLoader, TemplateNotFound
+ from os.path import join, exists, getmtime
+
+ class MyLoader(BaseLoader):
+
+ def __init__(self, path):
+ self.path = path
+
+ def get_source(self, environment, template):
+ path = join(self.path, template)
+ if not exists(path):
+ raise TemplateNotFound(template)
+ mtime = getmtime(path)
+ with file(path) as f:
+ source = f.read().decode('utf-8')
+ return source, path, lambda: mtime == getmtime(path)
+ """
+
+ #: if set to `False` it indicates that the loader cannot provide access
+ #: to the source of templates.
+ #:
+ #: .. versionadded:: 2.4
+ has_source_access = True
+
+ def get_source(self, environment, template):
+ """Get the template source, filename and reload helper for a template.
+ It's passed the environment and template name and has to return a
+ tuple in the form ``(source, filename, uptodate)`` or raise a
+ `TemplateNotFound` error if it can't locate the template.
+
+ The source part of the returned tuple must be the source of the
+ template as unicode string or a ASCII bytestring. The filename should
+ be the name of the file on the filesystem if it was loaded from there,
+ otherwise `None`. The filename is used by python for the tracebacks
+ if no loader extension is used.
+
+ The last item in the tuple is the `uptodate` function. If auto
+ reloading is enabled it's always called to check if the template
+ changed. No arguments are passed so the function must store the
+ old state somewhere (for example in a closure). If it returns `False`
+ the template will be reloaded.
+ """
+ if not self.has_source_access:
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 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")
-
- @internalcode
- def load(self, environment, name, globals=None):
- """Loads a template. This method looks up the template in the cache
- or loads one by calling :meth:`get_source`. Subclasses should not
- override this method as loaders working on collections of other
- loaders (such as :class:`PrefixLoader` or :class:`ChoiceLoader`)
- will not call this method but `get_source` directly.
- """
- code = None
- if globals is None:
- globals = {}
-
- # first we try to get the source for this template together
- # with the filename and the uptodate function.
- source, filename, uptodate = self.get_source(environment, name)
-
- # try to load the code from the bytecode cache if there is a
- # bytecode cache configured.
- bcc = environment.bytecode_cache
- if bcc is not None:
- bucket = bcc.get_bucket(environment, name, filename, source)
- code = bucket.code
-
- # if we don't have code so far (not cached, no longer up to
- # date) etc. we compile the template
- if code is None:
- code = environment.compile(source, name, filename)
-
- # if the bytecode cache is available and the bucket doesn't
- # have a code so far, we give the bucket the new code and put
- # it back to the bytecode cache.
- if bcc is not None and bucket.code is None:
- bucket.code = code
- bcc.set_bucket(bucket)
-
+
+ @internalcode
+ def load(self, environment, name, globals=None):
+ """Loads a template. This method looks up the template in the cache
+ or loads one by calling :meth:`get_source`. Subclasses should not
+ override this method as loaders working on collections of other
+ loaders (such as :class:`PrefixLoader` or :class:`ChoiceLoader`)
+ will not call this method but `get_source` directly.
+ """
+ code = None
+ if globals is None:
+ globals = {}
+
+ # first we try to get the source for this template together
+ # with the filename and the uptodate function.
+ source, filename, uptodate = self.get_source(environment, name)
+
+ # try to load the code from the bytecode cache if there is a
+ # bytecode cache configured.
+ bcc = environment.bytecode_cache
+ if bcc is not None:
+ bucket = bcc.get_bucket(environment, name, filename, source)
+ code = bucket.code
+
+ # if we don't have code so far (not cached, no longer up to
+ # date) etc. we compile the template
+ if code is None:
+ code = environment.compile(source, name, filename)
+
+ # if the bytecode cache is available and the bucket doesn't
+ # have a code so far, we give the bucket the new code and put
+ # it back to the bytecode cache.
+ if bcc is not None and bucket.code is None:
+ bucket.code = code
+ bcc.set_bucket(bucket)
+
return environment.template_class.from_code(
environment, code, globals, uptodate
)
-
-
-class FileSystemLoader(BaseLoader):
- """Loads templates from the file system. This loader can find templates
- in folders on the file system and is the preferred way to load them.
-
- The loader takes the path to the templates as string, or if multiple
- locations are wanted a list of them which is then looked up in the
- given order::
-
- >>> loader = FileSystemLoader('/path/to/templates')
- >>> loader = FileSystemLoader(['/path/to/templates', '/other/path'])
-
- Per default the template encoding is ``'utf-8'`` which can be changed
- by setting the `encoding` parameter to something else.
-
- To follow symbolic links, set the *followlinks* parameter to ``True``::
-
- >>> loader = FileSystemLoader('/path/to/templates', followlinks=True)
-
+
+
+class FileSystemLoader(BaseLoader):
+ """Loads templates from the file system. This loader can find templates
+ in folders on the file system and is the preferred way to load them.
+
+ The loader takes the path to the templates as string, or if multiple
+ locations are wanted a list of them which is then looked up in the
+ given order::
+
+ >>> loader = FileSystemLoader('/path/to/templates')
+ >>> loader = FileSystemLoader(['/path/to/templates', '/other/path'])
+
+ Per default the template encoding is ``'utf-8'`` which can be changed
+ by setting the `encoding` parameter to something else.
+
+ To follow symbolic links, set the *followlinks* parameter to ``True``::
+
+ >>> loader = FileSystemLoader('/path/to/templates', followlinks=True)
+
.. versionchanged:: 2.8
The ``followlinks`` parameter was added.
- """
-
+ """
+
def __init__(self, searchpath, encoding="utf-8", followlinks=False):
if not isinstance(searchpath, abc.Iterable) or isinstance(
searchpath, string_types
):
- searchpath = [searchpath]
+ searchpath = [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
-
- def get_source(self, environment, template):
- pieces = split_template_path(template)
- for searchpath in self.searchpath:
- filename = path.join(searchpath, *pieces)
- f = open_if_exists(filename)
- if f is None:
- continue
- try:
- contents = f.read().decode(self.encoding)
- finally:
- f.close()
-
- mtime = path.getmtime(filename)
-
- def uptodate():
- try:
- 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)
+ self.encoding = encoding
+ self.followlinks = followlinks
+
+ def get_source(self, environment, template):
+ pieces = split_template_path(template)
+ for searchpath in self.searchpath:
+ filename = path.join(searchpath, *pieces)
+ f = open_if_exists(filename)
+ if f is None:
+ continue
+ try:
+ contents = f.read().decode(self.encoding)
+ finally:
+ f.close()
+
+ mtime = path.getmtime(filename)
+
+ def uptodate():
+ try:
+ 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, _, filenames in walk_dir:
- for filename in filenames:
+ for filename in filenames:
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)
- return sorted(found)
-
-
-class PackageLoader(BaseLoader):
- """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::
-
- loader = PackageLoader('mypackage', 'views')
-
- If the package path is not given, ``'templates'`` is assumed.
-
- 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.
- """
-
+ template = template[2:]
+ if template not in found:
+ found.add(template)
+ return sorted(found)
+
+
+class PackageLoader(BaseLoader):
+ """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::
+
+ loader = PackageLoader('mypackage', 'views')
+
+ If the package path is not given, ``'templates'`` is assumed.
+
+ 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"):
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()
- self.filesystem_bound = isinstance(provider, DefaultProvider)
- self.provider = provider
- self.package_path = package_path
-
- def get_source(self, environment, template):
- pieces = split_template_path(template)
+ self.encoding = encoding
+ self.manager = ResourceManager()
+ self.filesystem_bound = isinstance(provider, DefaultProvider)
+ self.provider = provider
+ self.package_path = package_path
+
+ def get_source(self, environment, template):
+ pieces = split_template_path(template)
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
- except OSError:
- return False
-
- source = self.provider.get_resource_string(self.manager, p)
- return source.decode(self.encoding), filename, uptodate
-
- def list_templates(self):
- path = self.package_path
+ if 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
+ except OSError:
+ return False
+
+ source = self.provider.get_resource_string(self.manager, p)
+ return source.decode(self.encoding), filename, uptodate
+
+ def list_templates(self):
+ path = self.package_path
if path[:2] == "./":
- path = path[2:]
+ path = path[2:]
elif path == ".":
path = ""
- offset = len(path)
- results = []
+ offset = len(path)
+ results = []
- def _walk(path):
- for filename in self.provider.resource_listdir(path):
+ def _walk(path):
+ for filename in self.provider.resource_listdir(path):
fullname = path + "/" + filename
- if self.provider.resource_isdir(fullname):
- _walk(fullname)
- else:
+ if self.provider.resource_isdir(fullname):
+ _walk(fullname)
+ else:
results.append(fullname[offset:].lstrip("/"))
- _walk(path)
- results.sort()
- return results
-
-
-class DictLoader(BaseLoader):
- """Loads a template from a python dict. It's passed a dict of unicode
- strings bound to template names. This loader is useful for unittesting:
-
- >>> loader = DictLoader({'index.html': 'source here'})
-
- Because auto reloading is rarely useful this is disabled per default.
- """
-
- def __init__(self, mapping):
- self.mapping = mapping
-
- def get_source(self, environment, template):
- if template in self.mapping:
- source = self.mapping[template]
- return source, None, lambda: source == self.mapping.get(template)
- raise TemplateNotFound(template)
-
- def list_templates(self):
- return sorted(self.mapping)
-
-
-class FunctionLoader(BaseLoader):
- """A loader that is passed a function which does the loading. The
- function receives the name of the template and has to return either
- an unicode string with the template source, a tuple in the form ``(source,
- filename, uptodatefunc)`` or `None` if the template does not exist.
-
- >>> def load_template(name):
- ... if name == 'index.html':
- ... return '...'
- ...
- >>> loader = FunctionLoader(load_template)
-
- The `uptodatefunc` is a function that is called if autoreload is enabled
- and has to return `True` if the template is still up to date. For more
- details have a look at :meth:`BaseLoader.get_source` which has the same
- return value.
- """
-
- def __init__(self, load_func):
- self.load_func = load_func
-
- def get_source(self, environment, template):
- rv = self.load_func(template)
- if rv is None:
- raise TemplateNotFound(template)
- elif isinstance(rv, string_types):
- return rv, None, None
- return rv
-
-
-class PrefixLoader(BaseLoader):
- """A loader that is passed a dict of loaders where each loader is bound
- to a prefix. The prefix is delimited from the template by a slash per
- default, which can be changed by setting the `delimiter` argument to
- something else::
-
- loader = PrefixLoader({
- 'app1': PackageLoader('mypackage.app1'),
- 'app2': PackageLoader('mypackage.app2')
- })
-
- By loading ``'app1/index.html'`` the file from the app1 package is loaded,
- by loading ``'app2/index.html'`` the file from the second.
- """
-
+ _walk(path)
+ results.sort()
+ return results
+
+
+class DictLoader(BaseLoader):
+ """Loads a template from a python dict. It's passed a dict of unicode
+ strings bound to template names. This loader is useful for unittesting:
+
+ >>> loader = DictLoader({'index.html': 'source here'})
+
+ Because auto reloading is rarely useful this is disabled per default.
+ """
+
+ def __init__(self, mapping):
+ self.mapping = mapping
+
+ def get_source(self, environment, template):
+ if template in self.mapping:
+ source = self.mapping[template]
+ return source, None, lambda: source == self.mapping.get(template)
+ raise TemplateNotFound(template)
+
+ def list_templates(self):
+ return sorted(self.mapping)
+
+
+class FunctionLoader(BaseLoader):
+ """A loader that is passed a function which does the loading. The
+ function receives the name of the template and has to return either
+ an unicode string with the template source, a tuple in the form ``(source,
+ filename, uptodatefunc)`` or `None` if the template does not exist.
+
+ >>> def load_template(name):
+ ... if name == 'index.html':
+ ... return '...'
+ ...
+ >>> loader = FunctionLoader(load_template)
+
+ The `uptodatefunc` is a function that is called if autoreload is enabled
+ and has to return `True` if the template is still up to date. For more
+ details have a look at :meth:`BaseLoader.get_source` which has the same
+ return value.
+ """
+
+ def __init__(self, load_func):
+ self.load_func = load_func
+
+ def get_source(self, environment, template):
+ rv = self.load_func(template)
+ if rv is None:
+ raise TemplateNotFound(template)
+ elif isinstance(rv, string_types):
+ return rv, None, None
+ return rv
+
+
+class PrefixLoader(BaseLoader):
+ """A loader that is passed a dict of loaders where each loader is bound
+ to a prefix. The prefix is delimited from the template by a slash per
+ default, which can be changed by setting the `delimiter` argument to
+ something else::
+
+ loader = PrefixLoader({
+ 'app1': PackageLoader('mypackage.app1'),
+ 'app2': PackageLoader('mypackage.app2')
+ })
+
+ By loading ``'app1/index.html'`` the file from the app1 package is loaded,
+ by loading ``'app2/index.html'`` the file from the second.
+ """
+
def __init__(self, mapping, delimiter="/"):
- self.mapping = mapping
- self.delimiter = delimiter
-
- def get_loader(self, template):
- try:
- prefix, name = template.split(self.delimiter, 1)
- loader = self.mapping[prefix]
- except (ValueError, KeyError):
- raise TemplateNotFound(template)
- return loader, name
-
- def get_source(self, environment, template):
- loader, name = self.get_loader(template)
- try:
- return loader.get_source(environment, name)
- except TemplateNotFound:
- # re-raise the exception with the correct filename here.
- # (the one that includes the prefix)
- raise TemplateNotFound(template)
-
- @internalcode
- def load(self, environment, name, globals=None):
- loader, local_name = self.get_loader(name)
- try:
- return loader.load(environment, local_name, globals)
- except TemplateNotFound:
- # re-raise the exception with the correct filename here.
- # (the one that includes the prefix)
- raise TemplateNotFound(name)
-
- def list_templates(self):
- result = []
- for prefix, loader in iteritems(self.mapping):
- for template in loader.list_templates():
- result.append(prefix + self.delimiter + template)
- return result
-
-
-class ChoiceLoader(BaseLoader):
- """This loader works like the `PrefixLoader` just that no prefix is
- specified. If a template could not be found by one loader the next one
- is tried.
-
- >>> loader = ChoiceLoader([
- ... FileSystemLoader('/path/to/user/templates'),
- ... FileSystemLoader('/path/to/system/templates')
- ... ])
-
- This is useful if you want to allow users to override builtin templates
- from a different location.
- """
-
- def __init__(self, loaders):
- self.loaders = loaders
-
- def get_source(self, environment, template):
- for loader in self.loaders:
- try:
- return loader.get_source(environment, template)
- except TemplateNotFound:
- pass
- raise TemplateNotFound(template)
-
- @internalcode
- def load(self, environment, name, globals=None):
- for loader in self.loaders:
- try:
- return loader.load(environment, name, globals)
- except TemplateNotFound:
- pass
- raise TemplateNotFound(name)
-
- def list_templates(self):
- found = set()
- for loader in self.loaders:
- found.update(loader.list_templates())
- return sorted(found)
-
-
-class _TemplateModule(ModuleType):
- """Like a normal module but with support for weak references"""
-
-
-class ModuleLoader(BaseLoader):
- """This loader loads templates from precompiled templates.
-
- Example usage:
-
- >>> loader = ChoiceLoader([
- ... ModuleLoader('/path/to/compiled/templates'),
- ... FileSystemLoader('/path/to/templates')
- ... ])
-
- Templates can be precompiled with :meth:`Environment.compile_templates`.
- """
-
- has_source_access = False
-
- def __init__(self, path):
+ self.mapping = mapping
+ self.delimiter = delimiter
+
+ def get_loader(self, template):
+ try:
+ prefix, name = template.split(self.delimiter, 1)
+ loader = self.mapping[prefix]
+ except (ValueError, KeyError):
+ raise TemplateNotFound(template)
+ return loader, name
+
+ def get_source(self, environment, template):
+ loader, name = self.get_loader(template)
+ try:
+ return loader.get_source(environment, name)
+ except TemplateNotFound:
+ # re-raise the exception with the correct filename here.
+ # (the one that includes the prefix)
+ raise TemplateNotFound(template)
+
+ @internalcode
+ def load(self, environment, name, globals=None):
+ loader, local_name = self.get_loader(name)
+ try:
+ return loader.load(environment, local_name, globals)
+ except TemplateNotFound:
+ # re-raise the exception with the correct filename here.
+ # (the one that includes the prefix)
+ raise TemplateNotFound(name)
+
+ def list_templates(self):
+ result = []
+ for prefix, loader in iteritems(self.mapping):
+ for template in loader.list_templates():
+ result.append(prefix + self.delimiter + template)
+ return result
+
+
+class ChoiceLoader(BaseLoader):
+ """This loader works like the `PrefixLoader` just that no prefix is
+ specified. If a template could not be found by one loader the next one
+ is tried.
+
+ >>> loader = ChoiceLoader([
+ ... FileSystemLoader('/path/to/user/templates'),
+ ... FileSystemLoader('/path/to/system/templates')
+ ... ])
+
+ This is useful if you want to allow users to override builtin templates
+ from a different location.
+ """
+
+ def __init__(self, loaders):
+ self.loaders = loaders
+
+ def get_source(self, environment, template):
+ for loader in self.loaders:
+ try:
+ return loader.get_source(environment, template)
+ except TemplateNotFound:
+ pass
+ raise TemplateNotFound(template)
+
+ @internalcode
+ def load(self, environment, name, globals=None):
+ for loader in self.loaders:
+ try:
+ return loader.load(environment, name, globals)
+ except TemplateNotFound:
+ pass
+ raise TemplateNotFound(name)
+
+ def list_templates(self):
+ found = set()
+ for loader in self.loaders:
+ found.update(loader.list_templates())
+ return sorted(found)
+
+
+class _TemplateModule(ModuleType):
+ """Like a normal module but with support for weak references"""
+
+
+class ModuleLoader(BaseLoader):
+ """This loader loads templates from precompiled templates.
+
+ Example usage:
+
+ >>> loader = ChoiceLoader([
+ ... ModuleLoader('/path/to/compiled/templates'),
+ ... FileSystemLoader('/path/to/templates')
+ ... ])
+
+ Templates can be precompiled with :meth:`Environment.compile_templates`.
+ """
+
+ has_source_access = False
+
+ def __init__(self, path):
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)
+
+ # create a fake module that looks for the templates in the
+ # path given.
+ mod = _TemplateModule(package_name)
if not isinstance(path, abc.Iterable) or isinstance(path, string_types):
- path = [path]
-
+ path = [path]
+
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
- # loader that created it goes out of business.
- self.module = mod
- self.package_name = package_name
-
- @staticmethod
- def get_template_key(name):
+ # the only strong reference, the sys.modules entry is weak
+ # so that the garbage collector can remove it once the
+ # loader that created it goes out of business.
+ self.module = mod
+ self.package_name = package_name
+
+ @staticmethod
+ def get_template_key(name):
return "tmpl_" + sha1(name.encode("utf-8")).hexdigest()
-
- @staticmethod
- def get_module_filename(name):
+
+ @staticmethod
+ def get_module_filename(name):
return ModuleLoader.get_template_key(name) + ".py"
-
- @internalcode
- def load(self, environment, name, globals=None):
- key = self.get_template_key(name)
+
+ @internalcode
+ def load(self, environment, name, globals=None):
+ key = self.get_template_key(name)
module = "%s.%s" % (self.package_name, key)
- mod = getattr(self.module, module, None)
- if mod is None:
- try:
+ mod = getattr(self.module, module, None)
+ if mod is None:
+ try:
mod = __import__(module, None, None, ["root"])
- except ImportError:
- raise TemplateNotFound(name)
-
- # remove the entry from sys.modules, we only want the attribute
- # on the module object we have stored on the loader.
- sys.modules.pop(module, None)
-
- return environment.template_class.from_module_dict(
+ except ImportError:
+ raise TemplateNotFound(name)
+
+ # remove the entry from sys.modules, we only want the attribute
+ # on the module object we have stored on the loader.
+ sys.modules.pop(module, None)
+
+ return environment.template_class.from_module_dict(
environment, mod.__dict__, globals
)
-
-
-class ResourceLoader(BaseLoader):
- def __init__(self, prefix, module_loader):
- self.prefix = prefix
- self.module_loader = module_loader
-
- def get_source(self, environment, template):
- if self.module_loader is None:
- raise TemplateNotFound(template)
- try:
+
+
+class ResourceLoader(BaseLoader):
+ def __init__(self, prefix, module_loader):
+ self.prefix = prefix
+ self.module_loader = module_loader
+
+ def get_source(self, environment, template):
+ if self.module_loader is None:
+ raise TemplateNotFound(template)
+ try:
return self.module_loader.get_data(os.path.join(self.prefix, template)).decode('utf-8'), None, None
- except IOError:
+ except IOError:
raise TemplateNotFound(template)
diff --git a/contrib/python/Jinja2/py2/jinja2/meta.py b/contrib/python/Jinja2/py2/jinja2/meta.py
index 3795aace59..17144c65fa 100644
--- a/contrib/python/Jinja2/py2/jinja2/meta.py
+++ b/contrib/python/Jinja2/py2/jinja2/meta.py
@@ -1,101 +1,101 @@
-# -*- coding: utf-8 -*-
+# -*- coding: utf-8 -*-
"""Functions that expose information about templates that might be
interesting for introspection.
-"""
+"""
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):
+
+
+class TrackingCodeGenerator(CodeGenerator):
+ """We abuse the code generator for introspection."""
+
+ def __init__(self, environment):
CodeGenerator.__init__(self, environment, "<introspection>", "<introspection>")
- self.undeclared_identifiers = set()
-
- def write(self, x):
- """Don't write."""
-
- def enter_frame(self, frame):
- """Remember all undeclared identifiers."""
- CodeGenerator.enter_frame(self, frame)
- for _, (action, param) in iteritems(frame.symbols.loads):
+ self.undeclared_identifiers = set()
+
+ def write(self, x):
+ """Don't write."""
+
+ 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" and param not in self.environment.globals:
- self.undeclared_identifiers.add(param)
-
-
-def find_undeclared_variables(ast):
- """Returns a set of all variables in the AST that will be looked up from
- the context at runtime. Because at compile time it's not known which
- variables will be used depending on the path the execution takes at
- runtime, all variables are returned.
-
- >>> from jinja2 import Environment, meta
- >>> env = Environment()
- >>> ast = env.parse('{% set foo = 42 %}{{ bar + foo }}')
- >>> meta.find_undeclared_variables(ast) == set(['bar'])
- True
-
- .. admonition:: Implementation
-
- Internally the code generator is used for finding undeclared variables.
- This is good to know because the code generator might raise a
- :exc:`TemplateAssertionError` during compilation and as a matter of
- fact this function can currently raise that exception as well.
- """
- codegen = TrackingCodeGenerator(ast.environment)
- codegen.visit(ast)
- return codegen.undeclared_identifiers
-
-
-def find_referenced_templates(ast):
- """Finds all the referenced templates from the AST. This will return an
- iterator over all the hardcoded template extensions, inclusions and
- imports. If dynamic inheritance or inclusion is used, `None` will be
- yielded.
-
- >>> from jinja2 import Environment, meta
- >>> env = Environment()
- >>> ast = env.parse('{% extends "layout.html" %}{% include helper %}')
- >>> list(meta.find_referenced_templates(ast))
- ['layout.html', None]
-
- This function is useful for dependency tracking. For example if you want
- to rebuild parts of the website after a layout template has changed.
- """
+ self.undeclared_identifiers.add(param)
+
+
+def find_undeclared_variables(ast):
+ """Returns a set of all variables in the AST that will be looked up from
+ the context at runtime. Because at compile time it's not known which
+ variables will be used depending on the path the execution takes at
+ runtime, all variables are returned.
+
+ >>> from jinja2 import Environment, meta
+ >>> env = Environment()
+ >>> ast = env.parse('{% set foo = 42 %}{{ bar + foo }}')
+ >>> meta.find_undeclared_variables(ast) == set(['bar'])
+ True
+
+ .. admonition:: Implementation
+
+ Internally the code generator is used for finding undeclared variables.
+ This is good to know because the code generator might raise a
+ :exc:`TemplateAssertionError` during compilation and as a matter of
+ fact this function can currently raise that exception as well.
+ """
+ codegen = TrackingCodeGenerator(ast.environment)
+ codegen.visit(ast)
+ return codegen.undeclared_identifiers
+
+
+def find_referenced_templates(ast):
+ """Finds all the referenced templates from the AST. This will return an
+ iterator over all the hardcoded template extensions, inclusions and
+ imports. If dynamic inheritance or inclusion is used, `None` will be
+ yielded.
+
+ >>> from jinja2 import Environment, meta
+ >>> env = Environment()
+ >>> ast = env.parse('{% extends "layout.html" %}{% include helper %}')
+ >>> list(meta.find_referenced_templates(ast))
+ ['layout.html', None]
+
+ 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)
):
- if not isinstance(node.template, nodes.Const):
- # a tuple with some non consts in there
- if isinstance(node.template, (nodes.Tuple, nodes.List)):
- for template_name in node.template.items:
- # something const, only yield the strings and ignore
- # non-string consts that really just make no sense
- if isinstance(template_name, nodes.Const):
- if isinstance(template_name.value, string_types):
- yield template_name.value
- # something dynamic in there
- else:
- yield None
- # something dynamic we don't know about here
- else:
- yield None
- continue
- # constant is a basestring, direct template name
- if isinstance(node.template.value, string_types):
- yield node.template.value
- # 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
+ if not isinstance(node.template, nodes.Const):
+ # a tuple with some non consts in there
+ if isinstance(node.template, (nodes.Tuple, nodes.List)):
+ for template_name in node.template.items:
+ # something const, only yield the strings and ignore
+ # non-string consts that really just make no sense
+ if isinstance(template_name, nodes.Const):
+ if isinstance(template_name.value, string_types):
+ yield template_name.value
+ # something dynamic in there
+ else:
+ yield None
+ # something dynamic we don't know about here
+ else:
+ yield None
+ continue
+ # constant is a basestring, direct template name
+ if isinstance(node.template.value, string_types):
+ yield node.template.value
+ # 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)
):
- for template_name in node.template.value:
- if isinstance(template_name, string_types):
- yield template_name
- # something else we don't care about, we could warn here
- else:
- yield None
+ for template_name in node.template.value:
+ if isinstance(template_name, string_types):
+ yield template_name
+ # something else we don't care about, we could warn here
+ else:
+ yield None
diff --git a/contrib/python/Jinja2/py2/jinja2/nativetypes.py b/contrib/python/Jinja2/py2/jinja2/nativetypes.py
index 9f0d39cd98..1ce92ad4c4 100644
--- a/contrib/python/Jinja2/py2/jinja2/nativetypes.py
+++ b/contrib/python/Jinja2/py2/jinja2/nativetypes.py
@@ -1,16 +1,16 @@
-from ast import literal_eval
+from ast import literal_eval
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):
+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
@@ -18,77 +18,77 @@ def native_concat(nodes):
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:
+ """
+ head = list(islice(nodes, 2))
+
+ if not head:
+ return None
+
+ if len(head) == 1:
raw = head[0]
- else:
+ else:
raw = u"".join([text_type(v) for v in chain(head, nodes)])
-
- try:
+
+ try:
return literal_eval(raw)
- except (ValueError, SyntaxError, MemoryError):
+ except (ValueError, SyntaxError, MemoryError):
return raw
-
-
-class NativeCodeGenerator(CodeGenerator):
+
+
+class NativeCodeGenerator(CodeGenerator):
"""A code generator which renders Python types by not adding
``to_string()`` around output nodes.
- """
-
+ """
+
@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 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):
+
+ 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.
- """
- vars = dict(*args, **kwargs)
-
- try:
- return native_concat(self.root_render_func(self.new_context(vars)))
- except Exception:
+ """
+ vars = dict(*args, **kwargs)
+
+ try:
+ return native_concat(self.root_render_func(self.new_context(vars)))
+ except Exception:
return self.environment.handle_exception()
-
-
+
+
NativeEnvironment.template_class = NativeTemplate # type: ignore
diff --git a/contrib/python/Jinja2/py2/jinja2/nodes.py b/contrib/python/Jinja2/py2/jinja2/nodes.py
index 95bd614a14..6466f7bb6d 100644
--- a/contrib/python/Jinja2/py2/jinja2/nodes.py
+++ b/contrib/python/Jinja2/py2/jinja2/nodes.py
@@ -1,19 +1,19 @@
-# -*- coding: utf-8 -*-
+# -*- coding: utf-8 -*-
"""AST nodes generated by the parser for the compiler. Also provides
some node tree helper functions used by the parser and compiler in order
to normalize nodes.
-"""
-import operator
-from collections import deque
-
+"""
+import operator
+from collections import deque
+
from markupsafe import Markup
-
+
from ._compat import izip
from ._compat import PY2
from ._compat import text_type
from ._compat import with_metaclass
-
-_binop_to_func = {
+
+_binop_to_func = {
"*": operator.mul,
"/": operator.truediv,
"//": operator.floordiv,
@@ -21,11 +21,11 @@ _binop_to_func = {
"%": operator.mod,
"+": operator.add,
"-": operator.sub,
-}
-
+}
+
_uaop_to_func = {"not": operator.not_, "+": operator.pos, "-": operator.neg}
-
-_cmpop_to_func = {
+
+_cmpop_to_func = {
"eq": operator.eq,
"ne": operator.ne,
"gt": operator.gt,
@@ -34,90 +34,90 @@ _cmpop_to_func = {
"lteq": operator.le,
"in": lambda a, b: a in b,
"notin": lambda a, b: a not in b,
-}
-
-
-class Impossible(Exception):
- """Raised if the node could not perform a requested action."""
-
-
-class NodeType(type):
- """A metaclass for nodes that handles the field and attribute
- inheritance. fields and attributes from the parent class are
- automatically forwarded to the child."""
-
+}
+
+
+class Impossible(Exception):
+ """Raised if the node could not perform a requested action."""
+
+
+class NodeType(type):
+ """A metaclass for nodes that handles the field and attribute
+ inheritance. fields and attributes from the parent class are
+ automatically forwarded to the child."""
+
def __new__(mcs, name, bases, d):
for attr in "fields", "attributes":
- storage = []
- storage.extend(getattr(bases[0], attr, ()))
- storage.extend(d.get(attr, ()))
+ storage = []
+ storage.extend(getattr(bases[0], attr, ()))
+ storage.extend(d.get(attr, ()))
assert len(bases) == 1, "multiple inheritance not allowed"
assert len(storage) == len(set(storage)), "layout conflict"
- d[attr] = tuple(storage)
+ d[attr] = tuple(storage)
d.setdefault("abstract", False)
return type.__new__(mcs, name, bases, d)
-
-
-class EvalContext(object):
- """Holds evaluation time information. Custom attributes can be attached
- to it in extensions.
- """
-
- def __init__(self, environment, template_name=None):
- self.environment = environment
- if callable(environment.autoescape):
- self.autoescape = environment.autoescape(template_name)
- else:
- self.autoescape = environment.autoescape
- self.volatile = False
-
- def save(self):
- return self.__dict__.copy()
-
- def revert(self, old):
- self.__dict__.clear()
- self.__dict__.update(old)
-
-
-def get_eval_context(node, ctx):
- if ctx is None:
- if node.environment is None:
+
+
+class EvalContext(object):
+ """Holds evaluation time information. Custom attributes can be attached
+ to it in extensions.
+ """
+
+ def __init__(self, environment, template_name=None):
+ self.environment = environment
+ if callable(environment.autoescape):
+ self.autoescape = environment.autoescape(template_name)
+ else:
+ self.autoescape = environment.autoescape
+ self.volatile = False
+
+ def save(self):
+ return self.__dict__.copy()
+
+ def revert(self, old):
+ self.__dict__.clear()
+ self.__dict__.update(old)
+
+
+def get_eval_context(node, ctx):
+ if ctx is None:
+ if node.environment is None:
raise RuntimeError(
"if no eval context is passed, the "
"node must have an attached "
"environment."
)
- return EvalContext(node.environment)
- return ctx
-
-
-class Node(with_metaclass(NodeType, object)):
+ return EvalContext(node.environment)
+ return ctx
+
+
+class Node(with_metaclass(NodeType, object)):
"""Baseclass for all Jinja nodes. There are a number of nodes available
- of different types. There are four major types:
-
- - :class:`Stmt`: statements
- - :class:`Expr`: expressions
- - :class:`Helper`: helper nodes
- - :class:`Template`: the outermost wrapper node
-
- All nodes have fields and attributes. Fields may be other nodes, lists,
- or arbitrary values. Fields are passed to the constructor as regular
- positional arguments, attributes as keyword arguments. Each node has
- two attributes: `lineno` (the line number of the node) and `environment`.
- The `environment` attribute is set at the end of the parsing process for
- all nodes automatically.
- """
-
- fields = ()
+ of different types. There are four major types:
+
+ - :class:`Stmt`: statements
+ - :class:`Expr`: expressions
+ - :class:`Helper`: helper nodes
+ - :class:`Template`: the outermost wrapper node
+
+ All nodes have fields and attributes. Fields may be other nodes, lists,
+ or arbitrary values. Fields are passed to the constructor as regular
+ positional arguments, attributes as keyword arguments. Each node has
+ two attributes: `lineno` (the line number of the node) and `environment`.
+ The `environment` attribute is set at the end of the parsing process for
+ all nodes automatically.
+ """
+
+ fields = ()
attributes = ("lineno", "environment")
- abstract = True
-
- def __init__(self, *fields, **attributes):
- if self.abstract:
+ abstract = True
+
+ def __init__(self, *fields, **attributes):
+ if self.abstract:
raise TypeError("abstract nodes are not instantiable")
- if fields:
- if len(fields) != len(self.fields):
- if not self.fields:
+ if fields:
+ if len(fields) != len(self.fields):
+ if not self.fields:
raise TypeError("%r takes 0 arguments" % self.__class__.__name__)
raise TypeError(
"%r takes 0 or %d argument%s"
@@ -127,897 +127,897 @@ class Node(with_metaclass(NodeType, object)):
len(self.fields) != 1 and "s" or "",
)
)
- for name, arg in izip(self.fields, fields):
- setattr(self, name, arg)
- for attr in self.attributes:
- setattr(self, attr, attributes.pop(attr, None))
- if attributes:
+ for name, arg in izip(self.fields, fields):
+ setattr(self, name, arg)
+ for attr in self.attributes:
+ setattr(self, attr, attributes.pop(attr, None))
+ if attributes:
raise TypeError("unknown attribute %r" % next(iter(attributes)))
-
- def iter_fields(self, exclude=None, only=None):
- """This method iterates over all fields that are defined and yields
- ``(key, value)`` tuples. Per default all fields are returned, but
- it's possible to limit that to some fields by providing the `only`
- parameter or to exclude some using the `exclude` parameter. Both
- should be sets or tuples of field names.
- """
- for name in self.fields:
+
+ def iter_fields(self, exclude=None, only=None):
+ """This method iterates over all fields that are defined and yields
+ ``(key, value)`` tuples. Per default all fields are returned, but
+ it's possible to limit that to some fields by providing the `only`
+ parameter or to exclude some using the `exclude` parameter. Both
+ should be sets or tuples of field names.
+ """
+ for name in self.fields:
if (
(exclude is only is None)
or (exclude is not None and name not in exclude)
or (only is not None and name in only)
):
- try:
- yield name, getattr(self, name)
- except AttributeError:
- pass
-
- def iter_child_nodes(self, exclude=None, only=None):
- """Iterates over all direct child nodes of the node. This iterates
- over all fields and yields the values of they are nodes. If the value
- of a field is a list all the nodes in that list are returned.
- """
+ try:
+ yield name, getattr(self, name)
+ except AttributeError:
+ pass
+
+ def iter_child_nodes(self, exclude=None, only=None):
+ """Iterates over all direct child nodes of the node. This iterates
+ over all fields and yields the values of they are nodes. If the value
+ of a field is a list all the nodes in that list are returned.
+ """
for _, item in self.iter_fields(exclude, only):
- if isinstance(item, list):
- for n in item:
- if isinstance(n, Node):
- yield n
- elif isinstance(item, Node):
- yield item
-
- def find(self, node_type):
- """Find the first node of a given type. If no such node exists the
- return value is `None`.
- """
- for result in self.find_all(node_type):
- return result
-
- def find_all(self, node_type):
- """Find all the nodes of a given type. If the type is a tuple,
- the check is performed for any of the tuple items.
- """
- for child in self.iter_child_nodes():
- if isinstance(child, node_type):
- yield child
- for result in child.find_all(node_type):
- yield result
-
- def set_ctx(self, ctx):
- """Reset the context of a node and all child nodes. Per default the
- parser will all generate nodes that have a 'load' context as it's the
- most common one. This method is used in the parser to set assignment
- targets and other nodes to a store context.
- """
- todo = deque([self])
- while todo:
- node = todo.popleft()
+ if isinstance(item, list):
+ for n in item:
+ if isinstance(n, Node):
+ yield n
+ elif isinstance(item, Node):
+ yield item
+
+ def find(self, node_type):
+ """Find the first node of a given type. If no such node exists the
+ return value is `None`.
+ """
+ for result in self.find_all(node_type):
+ return result
+
+ def find_all(self, node_type):
+ """Find all the nodes of a given type. If the type is a tuple,
+ the check is performed for any of the tuple items.
+ """
+ for child in self.iter_child_nodes():
+ if isinstance(child, node_type):
+ yield child
+ for result in child.find_all(node_type):
+ yield result
+
+ def set_ctx(self, ctx):
+ """Reset the context of a node and all child nodes. Per default the
+ parser will all generate nodes that have a 'load' context as it's the
+ most common one. This method is used in the parser to set assignment
+ targets and other nodes to a store context.
+ """
+ todo = deque([self])
+ while todo:
+ node = todo.popleft()
if "ctx" in node.fields:
- node.ctx = ctx
- todo.extend(node.iter_child_nodes())
- return self
-
- def set_lineno(self, lineno, override=False):
- """Set the line numbers of the node and children."""
- todo = deque([self])
- while todo:
- node = todo.popleft()
+ node.ctx = ctx
+ todo.extend(node.iter_child_nodes())
+ return self
+
+ def set_lineno(self, lineno, override=False):
+ """Set the line numbers of the node and children."""
+ todo = deque([self])
+ while todo:
+ node = todo.popleft()
if "lineno" in node.attributes:
- if node.lineno is None or override:
- node.lineno = lineno
- todo.extend(node.iter_child_nodes())
- return self
-
- def set_environment(self, environment):
- """Set the environment for all nodes."""
- todo = deque([self])
- while todo:
- node = todo.popleft()
- node.environment = environment
- todo.extend(node.iter_child_nodes())
- return self
-
- def __eq__(self, other):
+ if node.lineno is None or override:
+ node.lineno = lineno
+ todo.extend(node.iter_child_nodes())
+ return self
+
+ def set_environment(self, environment):
+ """Set the environment for all nodes."""
+ todo = deque([self])
+ while todo:
+ node = todo.popleft()
+ node.environment = environment
+ todo.extend(node.iter_child_nodes())
+ return self
+
+ def __eq__(self, other):
return type(self) is type(other) and tuple(self.iter_fields()) == tuple(
other.iter_fields()
)
-
- def __ne__(self, other):
- return not self.__eq__(other)
-
- # Restore Python 2 hashing behavior on Python 3
- __hash__ = object.__hash__
-
- def __repr__(self):
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
+ # Restore Python 2 hashing behavior on Python 3
+ __hash__ = object.__hash__
+
+ def __repr__(self):
return "%s(%s)" % (
- self.__class__.__name__,
+ self.__class__.__name__,
", ".join("%s=%r" % (arg, getattr(self, arg, None)) for arg in self.fields),
- )
-
- def dump(self):
- def _dump(node):
- if not isinstance(node, Node):
- buf.append(repr(node))
- return
-
+ )
+
+ def dump(self):
+ def _dump(node):
+ if not isinstance(node, Node):
+ buf.append(repr(node))
+ return
+
buf.append("nodes.%s(" % node.__class__.__name__)
- if not node.fields:
+ if not node.fields:
buf.append(")")
- return
- for idx, field in enumerate(node.fields):
- if idx:
+ return
+ for idx, field in enumerate(node.fields):
+ if idx:
buf.append(", ")
- value = getattr(node, field)
- if isinstance(value, list):
+ value = getattr(node, field)
+ if isinstance(value, list):
buf.append("[")
- for idx, item in enumerate(value):
- if idx:
+ for idx, item in enumerate(value):
+ if idx:
buf.append(", ")
- _dump(item)
+ _dump(item)
buf.append("]")
- else:
- _dump(value)
+ else:
+ _dump(value)
buf.append(")")
- buf = []
- _dump(self)
+ buf = []
+ _dump(self)
return "".join(buf)
-
-
-class Stmt(Node):
- """Base node for all statements."""
-
- abstract = True
-
-
-class Helper(Node):
- """Nodes that exist in a specific context only."""
-
- abstract = True
-
-
-class Template(Node):
- """Node that represents a template. This must be the outermost node that
- is passed to the compiler.
- """
-
+
+
+class Stmt(Node):
+ """Base node for all statements."""
+
+ abstract = True
+
+
+class Helper(Node):
+ """Nodes that exist in a specific context only."""
+
+ abstract = True
+
+
+class Template(Node):
+ """Node that represents a template. This must be the outermost node that
+ is passed to the compiler.
+ """
+
fields = ("body",)
+
-
-class Output(Stmt):
- """A node that holds multiple expressions which are then printed out.
- This is used both for the `print` statement and the regular template data.
- """
-
+class Output(Stmt):
+ """A node that holds multiple expressions which are then printed out.
+ This is used both for the `print` statement and the regular template data.
+ """
+
fields = ("nodes",)
+
-
-class Extends(Stmt):
- """Represents an extends statement."""
-
+class Extends(Stmt):
+ """Represents an extends statement."""
+
fields = ("template",)
-
-
-class For(Stmt):
- """The for loop. `target` is the target for the iteration (usually a
- :class:`Name` or :class:`Tuple`), `iter` the iterable. `body` is a list
- of nodes that are used as loop-body, and `else_` a list of nodes for the
- `else` block. If no else node exists it has to be an empty list.
-
- For filtered nodes an expression can be stored as `test`, otherwise `None`.
- """
-
+
+
+class For(Stmt):
+ """The for loop. `target` is the target for the iteration (usually a
+ :class:`Name` or :class:`Tuple`), `iter` the iterable. `body` is a list
+ of nodes that are used as loop-body, and `else_` a list of nodes for the
+ `else` block. If no else node exists it has to be an empty list.
+
+ For filtered nodes an expression can be stored as `test`, otherwise `None`.
+ """
+
fields = ("target", "iter", "body", "else_", "test", "recursive")
+
-
-class If(Stmt):
- """If `test` is true, `body` is rendered, else `else_`."""
-
+class If(Stmt):
+ """If `test` is true, `body` is rendered, else `else_`."""
+
fields = ("test", "body", "elif_", "else_")
-
-
-class Macro(Stmt):
- """A macro definition. `name` is the name of the macro, `args` a list of
- arguments and `defaults` a list of defaults if there are any. `body` is
- a list of nodes for the macro body.
- """
-
+
+
+class Macro(Stmt):
+ """A macro definition. `name` is the name of the macro, `args` a list of
+ arguments and `defaults` a list of defaults if there are any. `body` is
+ a list of nodes for the macro body.
+ """
+
fields = ("name", "args", "defaults", "body")
+
-
-class CallBlock(Stmt):
- """Like a macro without a name but a call instead. `call` is called with
- the unnamed macro as `caller` argument this node holds.
- """
-
+class CallBlock(Stmt):
+ """Like a macro without a name but a call instead. `call` is called with
+ the unnamed macro as `caller` argument this node holds.
+ """
+
fields = ("call", "args", "defaults", "body")
+
-
-class FilterBlock(Stmt):
- """Node for filter sections."""
-
+class FilterBlock(Stmt):
+ """Node for filter sections."""
+
fields = ("body", "filter")
-
-
-class With(Stmt):
- """Specific node for with statements. In older versions of Jinja the
- with statement was implemented on the base of the `Scope` node instead.
-
- .. versionadded:: 2.9.3
- """
-
+
+
+class With(Stmt):
+ """Specific node for with statements. In older versions of Jinja the
+ with statement was implemented on the base of the `Scope` node instead.
+
+ .. versionadded:: 2.9.3
+ """
+
fields = ("targets", "values", "body")
+
-
-class Block(Stmt):
- """A node that represents a block."""
-
+class Block(Stmt):
+ """A node that represents a block."""
+
fields = ("name", "body", "scoped")
+
-
-class Include(Stmt):
- """A node that represents the include tag."""
-
+class Include(Stmt):
+ """A node that represents the include tag."""
+
fields = ("template", "with_context", "ignore_missing")
+
-
-class Import(Stmt):
- """A node that represents the import tag."""
-
+class Import(Stmt):
+ """A node that represents the import tag."""
+
fields = ("template", "target", "with_context")
-
-
-class FromImport(Stmt):
- """A node that represents the from import tag. It's important to not
- pass unsafe names to the name attribute. The compiler translates the
- attribute lookups directly into getattr calls and does *not* use the
- subscript callback of the interface. As exported variables may not
- start with double underscores (which the parser asserts) this is not a
- problem for regular Jinja code, but if this node is used in an extension
- extra care must be taken.
-
- The list of names may contain tuples if aliases are wanted.
- """
-
+
+
+class FromImport(Stmt):
+ """A node that represents the from import tag. It's important to not
+ pass unsafe names to the name attribute. The compiler translates the
+ attribute lookups directly into getattr calls and does *not* use the
+ subscript callback of the interface. As exported variables may not
+ start with double underscores (which the parser asserts) this is not a
+ problem for regular Jinja code, but if this node is used in an extension
+ extra care must be taken.
+
+ The list of names may contain tuples if aliases are wanted.
+ """
+
fields = ("template", "names", "with_context")
+
-
-class ExprStmt(Stmt):
- """A statement that evaluates an expression and discards the result."""
-
+class ExprStmt(Stmt):
+ """A statement that evaluates an expression and discards the result."""
+
fields = ("node",)
+
-
-class Assign(Stmt):
- """Assigns an expression to a target."""
-
+class Assign(Stmt):
+ """Assigns an expression to a target."""
+
fields = ("target", "node")
+
-
-class AssignBlock(Stmt):
- """Assigns a block to a target."""
-
+class AssignBlock(Stmt):
+ """Assigns a block to a target."""
+
fields = ("target", "filter", "body")
-
-
-class Expr(Node):
- """Baseclass for all expressions."""
-
- abstract = True
-
- def as_const(self, eval_ctx=None):
- """Return the value of the expression as constant or raise
- :exc:`Impossible` if this was not possible.
-
- An :class:`EvalContext` can be provided, if none is given
- a default context is created which requires the nodes to have
- an attached environment.
-
- .. versionchanged:: 2.4
- the `eval_ctx` parameter was added.
- """
- raise Impossible()
-
- def can_assign(self):
- """Check if it's possible to assign something to this node."""
- return False
-
-
-class BinExpr(Expr):
- """Baseclass for all binary expressions."""
+
+
+class Expr(Node):
+ """Baseclass for all expressions."""
+
+ abstract = True
+
+ def as_const(self, eval_ctx=None):
+ """Return the value of the expression as constant or raise
+ :exc:`Impossible` if this was not possible.
+
+ An :class:`EvalContext` can be provided, if none is given
+ a default context is created which requires the nodes to have
+ an attached environment.
+
+ .. versionchanged:: 2.4
+ the `eval_ctx` parameter was added.
+ """
+ raise Impossible()
+
+ def can_assign(self):
+ """Check if it's possible to assign something to this node."""
+ return False
+
+
+class BinExpr(Expr):
+ """Baseclass for all binary expressions."""
fields = ("left", "right")
- operator = None
- abstract = True
-
- def as_const(self, eval_ctx=None):
- eval_ctx = get_eval_context(self, eval_ctx)
- # intercepted operators cannot be folded at compile time
+ operator = None
+ abstract = True
+
+ def as_const(self, eval_ctx=None):
+ eval_ctx = get_eval_context(self, eval_ctx)
+ # intercepted operators cannot be folded at compile time
if (
self.environment.sandboxed
and self.operator in self.environment.intercepted_binops
):
- raise Impossible()
- f = _binop_to_func[self.operator]
- try:
- return f(self.left.as_const(eval_ctx), self.right.as_const(eval_ctx))
- except Exception:
- raise Impossible()
-
-
-class UnaryExpr(Expr):
- """Baseclass for all unary expressions."""
+ raise Impossible()
+ f = _binop_to_func[self.operator]
+ try:
+ return f(self.left.as_const(eval_ctx), self.right.as_const(eval_ctx))
+ except Exception:
+ raise Impossible()
+
+
+class UnaryExpr(Expr):
+ """Baseclass for all unary expressions."""
fields = ("node",)
- operator = None
- abstract = True
-
- def as_const(self, eval_ctx=None):
- eval_ctx = get_eval_context(self, eval_ctx)
- # intercepted operators cannot be folded at compile time
+ operator = None
+ abstract = True
+
+ def as_const(self, eval_ctx=None):
+ eval_ctx = get_eval_context(self, eval_ctx)
+ # intercepted operators cannot be folded at compile time
if (
self.environment.sandboxed
and self.operator in self.environment.intercepted_unops
):
- raise Impossible()
- f = _uaop_to_func[self.operator]
- try:
- return f(self.node.as_const(eval_ctx))
- except Exception:
- raise Impossible()
-
-
-class Name(Expr):
- """Looks up a name or stores a value in a name.
- The `ctx` of the node can be one of the following values:
-
- - `store`: store a value in the name
- - `load`: load that name
- - `param`: like `store` but if the name was defined as function parameter.
- """
-
+ raise Impossible()
+ f = _uaop_to_func[self.operator]
+ try:
+ return f(self.node.as_const(eval_ctx))
+ except Exception:
+ raise Impossible()
+
+
+class Name(Expr):
+ """Looks up a name or stores a value in a name.
+ The `ctx` of the node can be one of the following values:
+
+ - `store`: store a value in the name
+ - `load`: load that name
+ - `param`: like `store` but if the name was defined as function parameter.
+ """
+
fields = ("name", "ctx")
- def can_assign(self):
+ def can_assign(self):
return self.name not in ("true", "false", "none", "True", "False", "None")
-
-
-class NSRef(Expr):
- """Reference to a namespace value assignment"""
-
+
+
+class NSRef(Expr):
+ """Reference to a namespace value assignment"""
+
fields = ("name", "attr")
- def can_assign(self):
- # We don't need any special checks here; NSRef assignments have a
- # runtime check to ensure the target is a namespace object which will
- # have been checked already as it is created using a normal assignment
- # which goes through a `Name` node.
- return True
-
-
-class Literal(Expr):
- """Baseclass for literals."""
-
- abstract = True
-
-
-class Const(Literal):
- """All constant values. The parser will return this node for simple
- constants such as ``42`` or ``"foo"`` but it can be used to store more
- complex values such as lists too. Only constants with a safe
- representation (objects where ``eval(repr(x)) == x`` is true).
- """
-
+ def can_assign(self):
+ # We don't need any special checks here; NSRef assignments have a
+ # runtime check to ensure the target is a namespace object which will
+ # have been checked already as it is created using a normal assignment
+ # which goes through a `Name` node.
+ return True
+
+
+class Literal(Expr):
+ """Baseclass for literals."""
+
+ abstract = True
+
+
+class Const(Literal):
+ """All constant values. The parser will return this node for simple
+ constants such as ``42`` or ``"foo"`` but it can be used to store more
+ complex values such as lists too. Only constants with a safe
+ representation (objects where ``eval(repr(x)) == x`` is true).
+ """
+
fields = ("value",)
- def as_const(self, eval_ctx=None):
- rv = self.value
+ def as_const(self, eval_ctx=None):
+ rv = self.value
if (
PY2
and type(rv) is text_type
and self.environment.policies["compiler.ascii_str"]
):
- try:
+ try:
rv = rv.encode("ascii")
- except UnicodeError:
- pass
- return rv
-
- @classmethod
- def from_untrusted(cls, value, lineno=None, environment=None):
- """Return a const object if the value is representable as
- constant value in the generated code, otherwise it will raise
- an `Impossible` exception.
- """
- from .compiler import has_safe_repr
-
- if not has_safe_repr(value):
- raise Impossible()
- return cls(value, lineno=lineno, environment=environment)
-
-
-class TemplateData(Literal):
- """A constant template string."""
-
+ except UnicodeError:
+ pass
+ return rv
+
+ @classmethod
+ def from_untrusted(cls, value, lineno=None, environment=None):
+ """Return a const object if the value is representable as
+ constant value in the generated code, otherwise it will raise
+ an `Impossible` exception.
+ """
+ from .compiler import has_safe_repr
+
+ if not has_safe_repr(value):
+ raise Impossible()
+ return cls(value, lineno=lineno, environment=environment)
+
+
+class TemplateData(Literal):
+ """A constant template string."""
+
fields = ("data",)
- def as_const(self, eval_ctx=None):
- eval_ctx = get_eval_context(self, eval_ctx)
- if eval_ctx.volatile:
- raise Impossible()
- if eval_ctx.autoescape:
- return Markup(self.data)
- return self.data
-
-
-class Tuple(Literal):
- """For loop unpacking and some other things like multiple arguments
- for subscripts. Like for :class:`Name` `ctx` specifies if the tuple
- is used for loading the names or storing.
- """
-
+ def as_const(self, eval_ctx=None):
+ eval_ctx = get_eval_context(self, eval_ctx)
+ if eval_ctx.volatile:
+ raise Impossible()
+ if eval_ctx.autoescape:
+ return Markup(self.data)
+ return self.data
+
+
+class Tuple(Literal):
+ """For loop unpacking and some other things like multiple arguments
+ for subscripts. Like for :class:`Name` `ctx` specifies if the tuple
+ is used for loading the names or storing.
+ """
+
fields = ("items", "ctx")
- def as_const(self, eval_ctx=None):
- eval_ctx = get_eval_context(self, eval_ctx)
- return tuple(x.as_const(eval_ctx) for x in self.items)
-
- def can_assign(self):
- for item in self.items:
- if not item.can_assign():
- return False
- return True
-
-
-class List(Literal):
- """Any list literal such as ``[1, 2, 3]``"""
-
+ def as_const(self, eval_ctx=None):
+ eval_ctx = get_eval_context(self, eval_ctx)
+ return tuple(x.as_const(eval_ctx) for x in self.items)
+
+ def can_assign(self):
+ for item in self.items:
+ if not item.can_assign():
+ return False
+ return True
+
+
+class List(Literal):
+ """Any list literal such as ``[1, 2, 3]``"""
+
fields = ("items",)
- def as_const(self, eval_ctx=None):
- eval_ctx = get_eval_context(self, eval_ctx)
- return [x.as_const(eval_ctx) for x in self.items]
-
-
-class Dict(Literal):
- """Any dict literal such as ``{1: 2, 3: 4}``. The items must be a list of
- :class:`Pair` nodes.
- """
-
+ def as_const(self, eval_ctx=None):
+ eval_ctx = get_eval_context(self, eval_ctx)
+ return [x.as_const(eval_ctx) for x in self.items]
+
+
+class Dict(Literal):
+ """Any dict literal such as ``{1: 2, 3: 4}``. The items must be a list of
+ :class:`Pair` nodes.
+ """
+
fields = ("items",)
- def as_const(self, eval_ctx=None):
- eval_ctx = get_eval_context(self, eval_ctx)
- return dict(x.as_const(eval_ctx) for x in self.items)
-
-
-class Pair(Helper):
- """A key, value pair for dicts."""
-
+ def as_const(self, eval_ctx=None):
+ eval_ctx = get_eval_context(self, eval_ctx)
+ return dict(x.as_const(eval_ctx) for x in self.items)
+
+
+class Pair(Helper):
+ """A key, value pair for dicts."""
+
fields = ("key", "value")
- def as_const(self, eval_ctx=None):
- eval_ctx = get_eval_context(self, eval_ctx)
- return self.key.as_const(eval_ctx), self.value.as_const(eval_ctx)
-
-
-class Keyword(Helper):
- """A key, value pair for keyword arguments where key is a string."""
-
+ def as_const(self, eval_ctx=None):
+ eval_ctx = get_eval_context(self, eval_ctx)
+ return self.key.as_const(eval_ctx), self.value.as_const(eval_ctx)
+
+
+class Keyword(Helper):
+ """A key, value pair for keyword arguments where key is a string."""
+
fields = ("key", "value")
- def as_const(self, eval_ctx=None):
- eval_ctx = get_eval_context(self, eval_ctx)
- return self.key, self.value.as_const(eval_ctx)
-
-
-class CondExpr(Expr):
- """A conditional expression (inline if expression). (``{{
- foo if bar else baz }}``)
- """
-
+ def as_const(self, eval_ctx=None):
+ eval_ctx = get_eval_context(self, eval_ctx)
+ return self.key, self.value.as_const(eval_ctx)
+
+
+class CondExpr(Expr):
+ """A conditional expression (inline if expression). (``{{
+ foo if bar else baz }}``)
+ """
+
fields = ("test", "expr1", "expr2")
- def as_const(self, eval_ctx=None):
- eval_ctx = get_eval_context(self, eval_ctx)
- if self.test.as_const(eval_ctx):
- return self.expr1.as_const(eval_ctx)
-
- # if we evaluate to an undefined object, we better do that at runtime
- if self.expr2 is None:
- raise Impossible()
-
- return self.expr2.as_const(eval_ctx)
-
-
-def args_as_const(node, eval_ctx):
- args = [x.as_const(eval_ctx) for x in node.args]
- kwargs = dict(x.as_const(eval_ctx) for x in node.kwargs)
-
- if node.dyn_args is not None:
- try:
- args.extend(node.dyn_args.as_const(eval_ctx))
- except Exception:
- raise Impossible()
-
- if node.dyn_kwargs is not None:
- try:
- kwargs.update(node.dyn_kwargs.as_const(eval_ctx))
- except Exception:
- raise Impossible()
-
- return args, kwargs
-
-
-class Filter(Expr):
- """This node applies a filter on an expression. `name` is the name of
- the filter, the rest of the fields are the same as for :class:`Call`.
-
- If the `node` of a filter is `None` the contents of the last buffer are
- filtered. Buffers are created by macros and filter blocks.
- """
-
+ def as_const(self, eval_ctx=None):
+ eval_ctx = get_eval_context(self, eval_ctx)
+ if self.test.as_const(eval_ctx):
+ return self.expr1.as_const(eval_ctx)
+
+ # if we evaluate to an undefined object, we better do that at runtime
+ if self.expr2 is None:
+ raise Impossible()
+
+ return self.expr2.as_const(eval_ctx)
+
+
+def args_as_const(node, eval_ctx):
+ args = [x.as_const(eval_ctx) for x in node.args]
+ kwargs = dict(x.as_const(eval_ctx) for x in node.kwargs)
+
+ if node.dyn_args is not None:
+ try:
+ args.extend(node.dyn_args.as_const(eval_ctx))
+ except Exception:
+ raise Impossible()
+
+ if node.dyn_kwargs is not None:
+ try:
+ kwargs.update(node.dyn_kwargs.as_const(eval_ctx))
+ except Exception:
+ raise Impossible()
+
+ return args, kwargs
+
+
+class Filter(Expr):
+ """This node applies a filter on an expression. `name` is the name of
+ the filter, the rest of the fields are the same as for :class:`Call`.
+
+ If the `node` of a filter is `None` the contents of the last buffer are
+ filtered. Buffers are created by macros and filter blocks.
+ """
+
fields = ("node", "name", "args", "kwargs", "dyn_args", "dyn_kwargs")
-
- def as_const(self, eval_ctx=None):
- eval_ctx = get_eval_context(self, eval_ctx)
-
- if eval_ctx.volatile or self.node is None:
- raise Impossible()
-
- # we have to be careful here because we call filter_ below.
- # if this variable would be called filter, 2to3 would wrap the
+
+ def as_const(self, eval_ctx=None):
+ eval_ctx = get_eval_context(self, eval_ctx)
+
+ if eval_ctx.volatile or self.node is None:
+ raise Impossible()
+
+ # we have to be careful here because we call filter_ below.
+ # if this variable would be called filter, 2to3 would wrap the
# call in a list because it is assuming we are talking about the
- # builtin filter function here which no longer returns a list in
- # python 3. because of that, do not rename filter_ to filter!
- filter_ = self.environment.filters.get(self.name)
-
+ # builtin filter function here which no longer returns a list in
+ # python 3. because of that, do not rename filter_ to filter!
+ filter_ = self.environment.filters.get(self.name)
+
if filter_ is None or getattr(filter_, "contextfilter", False) is True:
- raise Impossible()
-
- # We cannot constant handle async filters, so we need to make sure
- # to not go down this path.
+ raise Impossible()
+
+ # We cannot constant handle async filters, so we need to make sure
+ # to not go down this path.
if eval_ctx.environment.is_async and getattr(
filter_, "asyncfiltervariant", False
- ):
- raise Impossible()
-
- args, kwargs = args_as_const(self, eval_ctx)
- args.insert(0, self.node.as_const(eval_ctx))
-
+ ):
+ raise Impossible()
+
+ args, kwargs = args_as_const(self, eval_ctx)
+ args.insert(0, self.node.as_const(eval_ctx))
+
if getattr(filter_, "evalcontextfilter", False) is True:
- args.insert(0, eval_ctx)
+ args.insert(0, eval_ctx)
elif getattr(filter_, "environmentfilter", False) is True:
- args.insert(0, self.environment)
-
- try:
- return filter_(*args, **kwargs)
- except Exception:
- raise Impossible()
-
-
-class Test(Expr):
- """Applies a test on an expression. `name` is the name of the test, the
- rest of the fields are the same as for :class:`Call`.
- """
-
+ args.insert(0, self.environment)
+
+ try:
+ return filter_(*args, **kwargs)
+ except Exception:
+ raise Impossible()
+
+
+class Test(Expr):
+ """Applies a test on an expression. `name` is the name of the test, the
+ rest of the fields are the same as for :class:`Call`.
+ """
+
fields = ("node", "name", "args", "kwargs", "dyn_args", "dyn_kwargs")
-
- def as_const(self, eval_ctx=None):
- test = self.environment.tests.get(self.name)
-
- if test is None:
- raise Impossible()
-
- eval_ctx = get_eval_context(self, eval_ctx)
- args, kwargs = args_as_const(self, eval_ctx)
- args.insert(0, self.node.as_const(eval_ctx))
-
- try:
- return test(*args, **kwargs)
- except Exception:
- raise Impossible()
-
-
-class Call(Expr):
- """Calls an expression. `args` is a list of arguments, `kwargs` a list
- of keyword arguments (list of :class:`Keyword` nodes), and `dyn_args`
- and `dyn_kwargs` has to be either `None` or a node that is used as
- node for dynamic positional (``*args``) or keyword (``**kwargs``)
- arguments.
- """
-
+
+ def as_const(self, eval_ctx=None):
+ test = self.environment.tests.get(self.name)
+
+ if test is None:
+ raise Impossible()
+
+ eval_ctx = get_eval_context(self, eval_ctx)
+ args, kwargs = args_as_const(self, eval_ctx)
+ args.insert(0, self.node.as_const(eval_ctx))
+
+ try:
+ return test(*args, **kwargs)
+ except Exception:
+ raise Impossible()
+
+
+class Call(Expr):
+ """Calls an expression. `args` is a list of arguments, `kwargs` a list
+ of keyword arguments (list of :class:`Keyword` nodes), and `dyn_args`
+ and `dyn_kwargs` has to be either `None` or a node that is used as
+ node for dynamic positional (``*args``) or keyword (``**kwargs``)
+ arguments.
+ """
+
fields = ("node", "args", "kwargs", "dyn_args", "dyn_kwargs")
+
-
-class Getitem(Expr):
- """Get an attribute or item from an expression and prefer the item."""
-
+class Getitem(Expr):
+ """Get an attribute or item from an expression and prefer the item."""
+
fields = ("node", "arg", "ctx")
- def as_const(self, eval_ctx=None):
- eval_ctx = get_eval_context(self, eval_ctx)
+ def as_const(self, eval_ctx=None):
+ eval_ctx = get_eval_context(self, eval_ctx)
if self.ctx != "load":
- raise Impossible()
- try:
+ raise Impossible()
+ try:
return self.environment.getitem(
self.node.as_const(eval_ctx), self.arg.as_const(eval_ctx)
)
- except Exception:
- raise Impossible()
-
- def can_assign(self):
- return False
-
-
-class Getattr(Expr):
- """Get an attribute or item from an expression that is a ascii-only
- bytestring and prefer the attribute.
- """
-
+ except Exception:
+ raise Impossible()
+
+ def can_assign(self):
+ return False
+
+
+class Getattr(Expr):
+ """Get an attribute or item from an expression that is a ascii-only
+ bytestring and prefer the attribute.
+ """
+
fields = ("node", "attr", "ctx")
- def as_const(self, eval_ctx=None):
+ def as_const(self, eval_ctx=None):
if self.ctx != "load":
- raise Impossible()
- try:
- eval_ctx = get_eval_context(self, eval_ctx)
+ raise Impossible()
+ try:
+ eval_ctx = get_eval_context(self, eval_ctx)
return self.environment.getattr(self.node.as_const(eval_ctx), self.attr)
- except Exception:
- raise Impossible()
-
- def can_assign(self):
- return False
-
-
-class Slice(Expr):
- """Represents a slice object. This must only be used as argument for
- :class:`Subscript`.
- """
-
+ except Exception:
+ raise Impossible()
+
+ def can_assign(self):
+ return False
+
+
+class Slice(Expr):
+ """Represents a slice object. This must only be used as argument for
+ :class:`Subscript`.
+ """
+
fields = ("start", "stop", "step")
- def as_const(self, eval_ctx=None):
- eval_ctx = get_eval_context(self, eval_ctx)
-
- def const(obj):
- if obj is None:
- return None
- return obj.as_const(eval_ctx)
-
- return slice(const(self.start), const(self.stop), const(self.step))
-
-
-class Concat(Expr):
- """Concatenates the list of expressions provided after converting them to
- unicode.
- """
-
+ def as_const(self, eval_ctx=None):
+ eval_ctx = get_eval_context(self, eval_ctx)
+
+ def const(obj):
+ if obj is None:
+ return None
+ return obj.as_const(eval_ctx)
+
+ return slice(const(self.start), const(self.stop), const(self.step))
+
+
+class Concat(Expr):
+ """Concatenates the list of expressions provided after converting them to
+ unicode.
+ """
+
fields = ("nodes",)
- def as_const(self, eval_ctx=None):
- eval_ctx = get_eval_context(self, eval_ctx)
+ def as_const(self, eval_ctx=None):
+ eval_ctx = get_eval_context(self, eval_ctx)
return "".join(text_type(x.as_const(eval_ctx)) for x in self.nodes)
-
-
-class Compare(Expr):
- """Compares an expression with some other expressions. `ops` must be a
- list of :class:`Operand`\\s.
- """
-
+
+
+class Compare(Expr):
+ """Compares an expression with some other expressions. `ops` must be a
+ list of :class:`Operand`\\s.
+ """
+
fields = ("expr", "ops")
- def as_const(self, eval_ctx=None):
- eval_ctx = get_eval_context(self, eval_ctx)
- result = value = self.expr.as_const(eval_ctx)
+ def as_const(self, eval_ctx=None):
+ eval_ctx = get_eval_context(self, eval_ctx)
+ result = value = self.expr.as_const(eval_ctx)
- try:
- for op in self.ops:
- new_value = op.expr.as_const(eval_ctx)
- result = _cmpop_to_func[op.op](value, new_value)
+ try:
+ for op in self.ops:
+ new_value = op.expr.as_const(eval_ctx)
+ result = _cmpop_to_func[op.op](value, new_value)
if not result:
return False
- value = new_value
- except Exception:
- raise Impossible()
-
- return result
-
-
-class Operand(Helper):
- """Holds an operator and an expression."""
+ value = new_value
+ except Exception:
+ raise Impossible()
+ return result
+
+
+class Operand(Helper):
+ """Holds an operator and an expression."""
+
fields = ("op", "expr")
-if __debug__:
+if __debug__:
Operand.__doc__ += "\nThe following operators are available: " + ", ".join(
sorted(
"``%s``" % x
for x in set(_binop_to_func) | set(_uaop_to_func) | set(_cmpop_to_func)
)
)
-
-
-class Mul(BinExpr):
- """Multiplies the left with the right node."""
-
+
+
+class Mul(BinExpr):
+ """Multiplies the left with the right node."""
+
operator = "*"
+
-
-class Div(BinExpr):
- """Divides the left by the right node."""
-
+class Div(BinExpr):
+ """Divides the left by the right node."""
+
operator = "/"
+
-
-class FloorDiv(BinExpr):
- """Divides the left by the right node and truncates conver the
- result into an integer by truncating.
- """
-
+class FloorDiv(BinExpr):
+ """Divides the left by the right node and truncates conver the
+ result into an integer by truncating.
+ """
+
operator = "//"
+
-
-class Add(BinExpr):
- """Add the left to the right node."""
-
+class Add(BinExpr):
+ """Add the left to the right node."""
+
operator = "+"
+
-
-class Sub(BinExpr):
- """Subtract the right from the left node."""
-
+class Sub(BinExpr):
+ """Subtract the right from the left node."""
+
operator = "-"
+
-
-class Mod(BinExpr):
- """Left modulo right."""
-
+class Mod(BinExpr):
+ """Left modulo right."""
+
operator = "%"
+
-
-class Pow(BinExpr):
- """Left to the power of right."""
-
+class Pow(BinExpr):
+ """Left to the power of right."""
+
operator = "**"
+
-
-class And(BinExpr):
- """Short circuited AND."""
-
+class And(BinExpr):
+ """Short circuited AND."""
+
operator = "and"
- def as_const(self, eval_ctx=None):
- eval_ctx = get_eval_context(self, eval_ctx)
- return self.left.as_const(eval_ctx) and self.right.as_const(eval_ctx)
-
-
-class Or(BinExpr):
- """Short circuited OR."""
-
+ def as_const(self, eval_ctx=None):
+ eval_ctx = get_eval_context(self, eval_ctx)
+ return self.left.as_const(eval_ctx) and self.right.as_const(eval_ctx)
+
+
+class Or(BinExpr):
+ """Short circuited OR."""
+
operator = "or"
- def as_const(self, eval_ctx=None):
- eval_ctx = get_eval_context(self, eval_ctx)
- return self.left.as_const(eval_ctx) or self.right.as_const(eval_ctx)
-
-
-class Not(UnaryExpr):
- """Negate the expression."""
-
+ def as_const(self, eval_ctx=None):
+ eval_ctx = get_eval_context(self, eval_ctx)
+ return self.left.as_const(eval_ctx) or self.right.as_const(eval_ctx)
+
+
+class Not(UnaryExpr):
+ """Negate the expression."""
+
operator = "not"
+
-
-class Neg(UnaryExpr):
- """Make the expression negative."""
-
+class Neg(UnaryExpr):
+ """Make the expression negative."""
+
operator = "-"
+
-
-class Pos(UnaryExpr):
- """Make the expression positive (noop for most expressions)"""
-
+class Pos(UnaryExpr):
+ """Make the expression positive (noop for most expressions)"""
+
operator = "+"
-
-
-# Helpers for extensions
-
-
-class EnvironmentAttribute(Expr):
- """Loads an attribute from the environment object. This is useful for
- extensions that want to call a callback stored on the environment.
- """
-
+
+
+# Helpers for extensions
+
+
+class EnvironmentAttribute(Expr):
+ """Loads an attribute from the environment object. This is useful for
+ extensions that want to call a callback stored on the environment.
+ """
+
fields = ("name",)
-
-
-class ExtensionAttribute(Expr):
- """Returns the attribute of an extension bound to the environment.
- The identifier is the identifier of the :class:`Extension`.
-
- This node is usually constructed by calling the
- :meth:`~jinja2.ext.Extension.attr` method on an extension.
- """
-
+
+
+class ExtensionAttribute(Expr):
+ """Returns the attribute of an extension bound to the environment.
+ The identifier is the identifier of the :class:`Extension`.
+
+ This node is usually constructed by calling the
+ :meth:`~jinja2.ext.Extension.attr` method on an extension.
+ """
+
fields = ("identifier", "name")
-
-
-class ImportedName(Expr):
- """If created with an import name the import name is returned on node
- access. For example ``ImportedName('cgi.escape')`` returns the `escape`
- function from the cgi module on evaluation. Imports are optimized by the
- compiler so there is no need to assign them to local variables.
- """
-
+
+
+class ImportedName(Expr):
+ """If created with an import name the import name is returned on node
+ access. For example ``ImportedName('cgi.escape')`` returns the `escape`
+ function from the cgi module on evaluation. Imports are optimized by the
+ compiler so there is no need to assign them to local variables.
+ """
+
fields = ("importname",)
-
-
-class InternalName(Expr):
- """An internal name in the compiler. You cannot create these nodes
- yourself but the parser provides a
- :meth:`~jinja2.parser.Parser.free_identifier` method that creates
- a new identifier for you. This identifier is not available from the
- template and is not threated specially by the compiler.
- """
-
+
+
+class InternalName(Expr):
+ """An internal name in the compiler. You cannot create these nodes
+ yourself but the parser provides a
+ :meth:`~jinja2.parser.Parser.free_identifier` method that creates
+ a new identifier for you. This identifier is not available from the
+ template and is not threated specially by the compiler.
+ """
+
fields = ("name",)
- def __init__(self):
+ def __init__(self):
raise TypeError(
"Can't create internal names. Use the "
"`free_identifier` method on a parser."
)
-
-
-class MarkSafe(Expr):
- """Mark the wrapped expression as safe (wrap it as `Markup`)."""
-
+
+
+class MarkSafe(Expr):
+ """Mark the wrapped expression as safe (wrap it as `Markup`)."""
+
fields = ("expr",)
- def as_const(self, eval_ctx=None):
- eval_ctx = get_eval_context(self, eval_ctx)
- return Markup(self.expr.as_const(eval_ctx))
-
-
-class MarkSafeIfAutoescape(Expr):
- """Mark the wrapped expression as safe (wrap it as `Markup`) but
- only if autoescaping is active.
-
- .. versionadded:: 2.5
- """
-
+ def as_const(self, eval_ctx=None):
+ eval_ctx = get_eval_context(self, eval_ctx)
+ return Markup(self.expr.as_const(eval_ctx))
+
+
+class MarkSafeIfAutoescape(Expr):
+ """Mark the wrapped expression as safe (wrap it as `Markup`) but
+ only if autoescaping is active.
+
+ .. versionadded:: 2.5
+ """
+
fields = ("expr",)
- def as_const(self, eval_ctx=None):
- eval_ctx = get_eval_context(self, eval_ctx)
- if eval_ctx.volatile:
- raise Impossible()
- expr = self.expr.as_const(eval_ctx)
- if eval_ctx.autoescape:
- return Markup(expr)
- return expr
-
-
-class ContextReference(Expr):
- """Returns the current template context. It can be used like a
- :class:`Name` node, with a ``'load'`` ctx and will return the
- current :class:`~jinja2.runtime.Context` object.
-
- Here an example that assigns the current template name to a
- variable named `foo`::
-
- Assign(Name('foo', ctx='store'),
- Getattr(ContextReference(), 'name'))
+ def as_const(self, eval_ctx=None):
+ eval_ctx = get_eval_context(self, eval_ctx)
+ if eval_ctx.volatile:
+ raise Impossible()
+ expr = self.expr.as_const(eval_ctx)
+ if eval_ctx.autoescape:
+ return Markup(expr)
+ return expr
+
+
+class ContextReference(Expr):
+ """Returns the current template context. It can be used like a
+ :class:`Name` node, with a ``'load'`` ctx and will return the
+ current :class:`~jinja2.runtime.Context` object.
+
+ Here an example that assigns the current template name to a
+ variable named `foo`::
+
+ Assign(Name('foo', ctx='store'),
+ Getattr(ContextReference(), 'name'))
This is basically equivalent to using the
:func:`~jinja2.contextfunction` decorator when using the
high-level API, which causes a reference to the context to be passed
as the first argument to a function.
- """
-
-
+ """
+
+
class DerivedContextReference(Expr):
"""Return the current template context including locals. Behaves
exactly like :class:`ContextReference`, but includes local
@@ -1027,60 +1027,60 @@ class DerivedContextReference(Expr):
"""
-class Continue(Stmt):
- """Continue a loop."""
-
-
-class Break(Stmt):
- """Break a loop."""
-
-
-class Scope(Stmt):
- """An artificial scope."""
-
+class Continue(Stmt):
+ """Continue a loop."""
+
+
+class Break(Stmt):
+ """Break a loop."""
+
+
+class Scope(Stmt):
+ """An artificial scope."""
+
fields = ("body",)
-
-
-class OverlayScope(Stmt):
- """An overlay scope for extensions. This is a largely unoptimized scope
- that however can be used to introduce completely arbitrary variables into
- a sub scope from a dictionary or dictionary like object. The `context`
- field has to evaluate to a dictionary object.
-
- Example usage::
-
- OverlayScope(context=self.call_method('get_context'),
- body=[...])
-
- .. versionadded:: 2.10
- """
-
+
+
+class OverlayScope(Stmt):
+ """An overlay scope for extensions. This is a largely unoptimized scope
+ that however can be used to introduce completely arbitrary variables into
+ a sub scope from a dictionary or dictionary like object. The `context`
+ field has to evaluate to a dictionary object.
+
+ Example usage::
+
+ OverlayScope(context=self.call_method('get_context'),
+ body=[...])
+
+ .. versionadded:: 2.10
+ """
+
fields = ("context", "body")
-
-
-class EvalContextModifier(Stmt):
- """Modifies the eval context. For each option that should be modified,
- a :class:`Keyword` has to be added to the :attr:`options` list.
-
- Example to change the `autoescape` setting::
-
- EvalContextModifier(options=[Keyword('autoescape', Const(True))])
- """
-
+
+
+class EvalContextModifier(Stmt):
+ """Modifies the eval context. For each option that should be modified,
+ a :class:`Keyword` has to be added to the :attr:`options` list.
+
+ Example to change the `autoescape` setting::
+
+ EvalContextModifier(options=[Keyword('autoescape', Const(True))])
+ """
+
fields = ("options",)
-
-
-class ScopedEvalContextModifier(EvalContextModifier):
- """Modifies the eval context and reverts it later. Works exactly like
- :class:`EvalContextModifier` but will only modify the
- :class:`~jinja2.nodes.EvalContext` for nodes in the :attr:`body`.
- """
-
+
+
+class ScopedEvalContextModifier(EvalContextModifier):
+ """Modifies the eval context and reverts it later. Works exactly like
+ :class:`EvalContextModifier` but will only modify the
+ :class:`~jinja2.nodes.EvalContext` for nodes in the :attr:`body`.
+ """
+
fields = ("body",)
+
-
-# make sure nobody creates custom nodes
-def _failing_new(*args, **kwargs):
+# make sure nobody creates custom nodes
+def _failing_new(*args, **kwargs):
raise TypeError("can't create custom node types")
diff --git a/contrib/python/Jinja2/py2/jinja2/optimizer.py b/contrib/python/Jinja2/py2/jinja2/optimizer.py
index 7bc78c4524..f4fddd926d 100644
--- a/contrib/python/Jinja2/py2/jinja2/optimizer.py
+++ b/contrib/python/Jinja2/py2/jinja2/optimizer.py
@@ -1,31 +1,31 @@
-# -*- coding: utf-8 -*-
+# -*- 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.
-"""
+"""
from . import nodes
from .visitor import NodeTransformer
-
-
-def optimize(node, environment):
- """The context hint can be used to perform an static optimization
- based on the context given."""
- optimizer = Optimizer(environment)
- return optimizer.visit(node)
-
-
-class Optimizer(NodeTransformer):
- def __init__(self, environment):
- self.environment = environment
-
+
+
+def optimize(node, environment):
+ """The context hint can be used to perform an static optimization
+ based on the context given."""
+ optimizer = Optimizer(environment)
+ return optimizer.visit(node)
+
+
+class Optimizer(NodeTransformer):
+ def __init__(self, environment):
+ self.environment = environment
+
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):
diff --git a/contrib/python/Jinja2/py2/jinja2/parser.py b/contrib/python/Jinja2/py2/jinja2/parser.py
index d5881066f7..55a6de25a8 100644
--- a/contrib/python/Jinja2/py2/jinja2/parser.py
+++ b/contrib/python/Jinja2/py2/jinja2/parser.py
@@ -1,4 +1,4 @@
-# -*- coding: utf-8 -*-
+# -*- coding: utf-8 -*-
"""Parse tokens from the lexer into nodes for the compiler."""
from . import nodes
from ._compat import imap
@@ -6,7 +6,7 @@ from .exceptions import TemplateAssertionError
from .exceptions import TemplateSyntaxError
from .lexer import describe_token
from .lexer import describe_token_expr
-
+
_statement_keywords = frozenset(
[
"for",
@@ -24,313 +24,313 @@ _statement_keywords = frozenset(
]
)
_compare_operators = frozenset(["eq", "ne", "lt", "lteq", "gt", "gteq"])
-
-_math_nodes = {
+
+_math_nodes = {
"add": nodes.Add,
"sub": nodes.Sub,
"mul": nodes.Mul,
"div": nodes.Div,
"floordiv": nodes.FloorDiv,
"mod": nodes.Mod,
-}
-
-
-class Parser(object):
+}
+
+
+class Parser(object):
"""This is the central parsing class Jinja uses. It's passed to
- extensions and can be used to parse expressions or statements.
- """
-
+ extensions and can be used to parse expressions or statements.
+ """
+
def __init__(self, environment, source, name=None, filename=None, state=None):
- self.environment = environment
- self.stream = environment._tokenize(source, name, filename, state)
- self.name = name
- self.filename = filename
- self.closed = False
- self.extensions = {}
- for extension in environment.iter_extensions():
- for tag in extension.tags:
- self.extensions[tag] = extension.parse
- self._last_identifier = 0
- self._tag_stack = []
- self._end_token_stack = []
-
- def fail(self, msg, lineno=None, exc=TemplateSyntaxError):
- """Convenience method that raises `exc` with the message, passed
- line number or last line number as well as the current name and
- filename.
- """
- if lineno is None:
- lineno = self.stream.current.lineno
- raise exc(msg, lineno, self.name, self.filename)
-
- def _fail_ut_eof(self, name, end_token_stack, lineno):
- expected = []
- for exprs in end_token_stack:
- expected.extend(imap(describe_token_expr, exprs))
- if end_token_stack:
+ self.environment = environment
+ self.stream = environment._tokenize(source, name, filename, state)
+ self.name = name
+ self.filename = filename
+ self.closed = False
+ self.extensions = {}
+ for extension in environment.iter_extensions():
+ for tag in extension.tags:
+ self.extensions[tag] = extension.parse
+ self._last_identifier = 0
+ self._tag_stack = []
+ self._end_token_stack = []
+
+ def fail(self, msg, lineno=None, exc=TemplateSyntaxError):
+ """Convenience method that raises `exc` with the message, passed
+ line number or last line number as well as the current name and
+ filename.
+ """
+ if lineno is None:
+ lineno = self.stream.current.lineno
+ raise exc(msg, lineno, self.name, self.filename)
+
+ def _fail_ut_eof(self, name, end_token_stack, lineno):
+ expected = []
+ for exprs in end_token_stack:
+ expected.extend(imap(describe_token_expr, exprs))
+ if end_token_stack:
currently_looking = " or ".join(
"'%s'" % describe_token_expr(expr) for expr in end_token_stack[-1]
)
- else:
- currently_looking = None
-
- if name is None:
+ else:
+ currently_looking = None
+
+ if name is None:
message = ["Unexpected end of template."]
- else:
+ else:
message = ["Encountered unknown tag '%s'." % name]
-
- if currently_looking:
- if name is not None and name in expected:
+
+ if currently_looking:
+ if name is not None and name in expected:
message.append(
"You probably made a nesting mistake. Jinja "
"is expecting this tag, but currently looking "
"for %s." % currently_looking
)
- else:
+ else:
message.append(
"Jinja was looking for the following tags: "
"%s." % currently_looking
)
-
- if self._tag_stack:
+
+ if self._tag_stack:
message.append(
"The innermost block that needs to be "
"closed is '%s'." % self._tag_stack[-1]
)
-
+
self.fail(" ".join(message), lineno)
-
- def fail_unknown_tag(self, name, lineno=None):
- """Called if the parser encounters an unknown tag. Tries to fail
- with a human readable error message that could help to identify
- the problem.
- """
- return self._fail_ut_eof(name, self._end_token_stack, lineno)
-
- def fail_eof(self, end_tokens=None, lineno=None):
- """Like fail_unknown_tag but for end of template situations."""
- stack = list(self._end_token_stack)
- if end_tokens is not None:
- stack.append(end_tokens)
- return self._fail_ut_eof(None, stack, lineno)
-
- def is_tuple_end(self, extra_end_rules=None):
- """Are we at the end of a tuple?"""
+
+ def fail_unknown_tag(self, name, lineno=None):
+ """Called if the parser encounters an unknown tag. Tries to fail
+ with a human readable error message that could help to identify
+ the problem.
+ """
+ return self._fail_ut_eof(name, self._end_token_stack, lineno)
+
+ def fail_eof(self, end_tokens=None, lineno=None):
+ """Like fail_unknown_tag but for end of template situations."""
+ stack = list(self._end_token_stack)
+ if end_tokens is not None:
+ stack.append(end_tokens)
+ return self._fail_ut_eof(None, stack, lineno)
+
+ def is_tuple_end(self, extra_end_rules=None):
+ """Are we at the end of a tuple?"""
if self.stream.current.type in ("variable_end", "block_end", "rparen"):
- return True
- elif extra_end_rules is not None:
- return self.stream.current.test_any(extra_end_rules)
- return False
-
- def free_identifier(self, lineno=None):
- """Return a new free identifier as :class:`~jinja2.nodes.InternalName`."""
- self._last_identifier += 1
- rv = object.__new__(nodes.InternalName)
+ return True
+ elif extra_end_rules is not None:
+ return self.stream.current.test_any(extra_end_rules)
+ return False
+
+ def free_identifier(self, lineno=None):
+ """Return a new free identifier as :class:`~jinja2.nodes.InternalName`."""
+ self._last_identifier += 1
+ rv = object.__new__(nodes.InternalName)
nodes.Node.__init__(rv, "fi%d" % self._last_identifier, lineno=lineno)
- return rv
-
- def parse_statement(self):
- """Parse a single statement."""
- token = self.stream.current
+ return rv
+
+ def parse_statement(self):
+ """Parse a single statement."""
+ token = self.stream.current
if token.type != "name":
self.fail("tag name expected", token.lineno)
- self._tag_stack.append(token.value)
- pop_tag = True
- try:
- if token.value in _statement_keywords:
+ self._tag_stack.append(token.value)
+ pop_tag = True
+ try:
+ if token.value in _statement_keywords:
return getattr(self, "parse_" + self.stream.current.value)()
if token.value == "call":
- return self.parse_call_block()
+ return self.parse_call_block()
if token.value == "filter":
- return self.parse_filter_block()
- ext = self.extensions.get(token.value)
- if ext is not None:
- return ext(self)
-
- # did not work out, remove the token we pushed by accident
- # from the stack so that the unknown tag fail function can
- # produce a proper error message.
- self._tag_stack.pop()
- pop_tag = False
- self.fail_unknown_tag(token.value, token.lineno)
- finally:
- if pop_tag:
- self._tag_stack.pop()
-
- def parse_statements(self, end_tokens, drop_needle=False):
- """Parse multiple statements into a list until one of the end tokens
- is reached. This is used to parse the body of statements as it also
- parses template data if appropriate. The parser checks first if the
- current token is a colon and skips it if there is one. Then it checks
- for the block end and parses until if one of the `end_tokens` is
- reached. Per default the active token in the stream at the end of
- the call is the matched end token. If this is not wanted `drop_needle`
- can be set to `True` and the end token is removed.
- """
- # the first token may be a colon for python compatibility
+ return self.parse_filter_block()
+ ext = self.extensions.get(token.value)
+ if ext is not None:
+ return ext(self)
+
+ # did not work out, remove the token we pushed by accident
+ # from the stack so that the unknown tag fail function can
+ # produce a proper error message.
+ self._tag_stack.pop()
+ pop_tag = False
+ self.fail_unknown_tag(token.value, token.lineno)
+ finally:
+ if pop_tag:
+ self._tag_stack.pop()
+
+ def parse_statements(self, end_tokens, drop_needle=False):
+ """Parse multiple statements into a list until one of the end tokens
+ is reached. This is used to parse the body of statements as it also
+ parses template data if appropriate. The parser checks first if the
+ current token is a colon and skips it if there is one. Then it checks
+ for the block end and parses until if one of the `end_tokens` is
+ reached. Per default the active token in the stream at the end of
+ the call is the matched end token. If this is not wanted `drop_needle`
+ can be set to `True` and the end token is removed.
+ """
+ # the first token may be a colon for python compatibility
self.stream.skip_if("colon")
-
- # in the future it would be possible to add whole code sections
- # by adding some sort of end of statement token and parsing those here.
+
+ # in the future it would be possible to add whole code sections
+ # by adding some sort of end of statement token and parsing those here.
self.stream.expect("block_end")
- result = self.subparse(end_tokens)
-
- # we reached the end of the template too early, the subparser
- # does not check for this, so we do that now
+ result = self.subparse(end_tokens)
+
+ # we reached the end of the template too early, the subparser
+ # does not check for this, so we do that now
if self.stream.current.type == "eof":
- self.fail_eof(end_tokens)
-
- if drop_needle:
- next(self.stream)
- return result
-
- def parse_set(self):
- """Parse an assign statement."""
- lineno = next(self.stream).lineno
- target = self.parse_assign_target(with_namespace=True)
+ self.fail_eof(end_tokens)
+
+ if drop_needle:
+ next(self.stream)
+ return result
+
+ def parse_set(self):
+ """Parse an assign statement."""
+ lineno = next(self.stream).lineno
+ target = self.parse_assign_target(with_namespace=True)
if self.stream.skip_if("assign"):
- expr = self.parse_tuple()
- return nodes.Assign(target, expr, lineno=lineno)
- filter_node = self.parse_filter(None)
+ expr = self.parse_tuple()
+ return nodes.Assign(target, expr, lineno=lineno)
+ filter_node = self.parse_filter(None)
body = self.parse_statements(("name:endset",), drop_needle=True)
- return nodes.AssignBlock(target, filter_node, body, lineno=lineno)
-
- def parse_for(self):
- """Parse a for loop."""
+ return nodes.AssignBlock(target, filter_node, body, lineno=lineno)
+
+ def parse_for(self):
+ """Parse a for loop."""
lineno = self.stream.expect("name:for").lineno
target = self.parse_assign_target(extra_end_rules=("name:in",))
self.stream.expect("name:in")
iter = self.parse_tuple(
with_condexpr=False, extra_end_rules=("name:recursive",)
)
- test = None
+ test = None
if self.stream.skip_if("name:if"):
- test = self.parse_expression()
+ test = self.parse_expression()
recursive = self.stream.skip_if("name:recursive")
body = self.parse_statements(("name:endfor", "name:else"))
if next(self.stream).value == "endfor":
- else_ = []
- else:
+ else_ = []
+ else:
else_ = self.parse_statements(("name:endfor",), drop_needle=True)
return nodes.For(target, iter, body, else_, test, recursive, lineno=lineno)
-
- def parse_if(self):
- """Parse an if construct."""
+
+ def parse_if(self):
+ """Parse an if construct."""
node = result = nodes.If(lineno=self.stream.expect("name:if").lineno)
- while 1:
- node.test = self.parse_tuple(with_condexpr=False)
+ while 1:
+ node.test = self.parse_tuple(with_condexpr=False)
node.body = self.parse_statements(("name:elif", "name:else", "name:endif"))
- node.elif_ = []
- node.else_ = []
- token = next(self.stream)
+ node.elif_ = []
+ node.else_ = []
+ token = next(self.stream)
if token.test("name:elif"):
- node = nodes.If(lineno=self.stream.current.lineno)
- result.elif_.append(node)
- continue
+ node = nodes.If(lineno=self.stream.current.lineno)
+ result.elif_.append(node)
+ continue
elif token.test("name:else"):
result.else_ = self.parse_statements(("name:endif",), drop_needle=True)
- break
- return result
-
- def parse_with(self):
- node = nodes.With(lineno=next(self.stream).lineno)
- targets = []
- values = []
+ break
+ return result
+
+ def parse_with(self):
+ node = nodes.With(lineno=next(self.stream).lineno)
+ targets = []
+ values = []
while self.stream.current.type != "block_end":
- if targets:
+ if targets:
self.stream.expect("comma")
- target = self.parse_assign_target()
+ target = self.parse_assign_target()
target.set_ctx("param")
- targets.append(target)
+ targets.append(target)
self.stream.expect("assign")
- values.append(self.parse_expression())
- node.targets = targets
- node.values = values
+ values.append(self.parse_expression())
+ node.targets = targets
+ node.values = values
node.body = self.parse_statements(("name:endwith",), drop_needle=True)
- return node
-
- def parse_autoescape(self):
- node = nodes.ScopedEvalContextModifier(lineno=next(self.stream).lineno)
+ return node
+
+ def parse_autoescape(self):
+ node = nodes.ScopedEvalContextModifier(lineno=next(self.stream).lineno)
node.options = [nodes.Keyword("autoescape", self.parse_expression())]
node.body = self.parse_statements(("name:endautoescape",), drop_needle=True)
- return nodes.Scope([node])
-
- def parse_block(self):
- node = nodes.Block(lineno=next(self.stream).lineno)
+ return nodes.Scope([node])
+
+ def parse_block(self):
+ node = nodes.Block(lineno=next(self.stream).lineno)
node.name = self.stream.expect("name").value
node.scoped = self.stream.skip_if("name:scoped")
-
- # common problem people encounter when switching from django
- # to jinja. we do not support hyphens in block names, so let's
- # raise a nicer error message in that case.
+
+ # common problem people encounter when switching from django
+ # to jinja. we do not support hyphens in block names, so let's
+ # raise a nicer error message in that case.
if self.stream.current.type == "sub":
self.fail(
"Block names in Jinja have to be valid Python "
"identifiers and may not contain hyphens, use an "
"underscore instead."
)
-
+
node.body = self.parse_statements(("name:endblock",), drop_needle=True)
self.stream.skip_if("name:" + node.name)
- return node
-
- def parse_extends(self):
- node = nodes.Extends(lineno=next(self.stream).lineno)
- node.template = self.parse_expression()
- return node
-
- def parse_import_context(self, node, default):
+ return node
+
+ def parse_extends(self):
+ node = nodes.Extends(lineno=next(self.stream).lineno)
+ node.template = self.parse_expression()
+ return node
+
+ def parse_import_context(self, node, default):
if self.stream.current.test_any(
"name:with", "name:without"
) and self.stream.look().test("name:context"):
node.with_context = next(self.stream).value == "with"
- self.stream.skip()
- else:
- node.with_context = default
- return node
-
- def parse_include(self):
- node = nodes.Include(lineno=next(self.stream).lineno)
- node.template = self.parse_expression()
+ self.stream.skip()
+ else:
+ node.with_context = default
+ return node
+
+ def parse_include(self):
+ node = nodes.Include(lineno=next(self.stream).lineno)
+ node.template = self.parse_expression()
if self.stream.current.test("name:ignore") and self.stream.look().test(
"name:missing"
):
- node.ignore_missing = True
- self.stream.skip(2)
- else:
- node.ignore_missing = False
- return self.parse_import_context(node, True)
-
- def parse_import(self):
- node = nodes.Import(lineno=next(self.stream).lineno)
- node.template = self.parse_expression()
+ node.ignore_missing = True
+ self.stream.skip(2)
+ else:
+ node.ignore_missing = False
+ return self.parse_import_context(node, True)
+
+ def parse_import(self):
+ node = nodes.Import(lineno=next(self.stream).lineno)
+ node.template = self.parse_expression()
self.stream.expect("name:as")
- node.target = self.parse_assign_target(name_only=True).name
- return self.parse_import_context(node, False)
-
- def parse_from(self):
- node = nodes.FromImport(lineno=next(self.stream).lineno)
- node.template = self.parse_expression()
+ node.target = self.parse_assign_target(name_only=True).name
+ return self.parse_import_context(node, False)
+
+ def parse_from(self):
+ node = nodes.FromImport(lineno=next(self.stream).lineno)
+ node.template = self.parse_expression()
self.stream.expect("name:import")
- node.names = []
-
- def parse_context():
+ node.names = []
+
+ def parse_context():
if self.stream.current.value in (
"with",
"without",
) and self.stream.look().test("name:context"):
node.with_context = next(self.stream).value == "with"
- self.stream.skip()
- return True
- return False
-
- while 1:
- if node.names:
+ self.stream.skip()
+ return True
+ return False
+
+ while 1:
+ if node.names:
self.stream.expect("comma")
if self.stream.current.type == "name":
- if parse_context():
- break
- target = self.parse_assign_target(name_only=True)
+ if parse_context():
+ break
+ target = self.parse_assign_target(name_only=True)
if target.name.startswith("_"):
self.fail(
"names starting with an underline can not be imported",
@@ -338,70 +338,70 @@ class Parser(object):
exc=TemplateAssertionError,
)
if self.stream.skip_if("name:as"):
- alias = self.parse_assign_target(name_only=True)
- node.names.append((target.name, alias.name))
- else:
- node.names.append(target.name)
+ alias = self.parse_assign_target(name_only=True)
+ node.names.append((target.name, alias.name))
+ else:
+ node.names.append(target.name)
if parse_context() or self.stream.current.type != "comma":
- break
- else:
+ break
+ else:
self.stream.expect("name")
if not hasattr(node, "with_context"):
- node.with_context = False
- return node
-
- def parse_signature(self, node):
- node.args = args = []
- node.defaults = defaults = []
+ node.with_context = False
+ return node
+
+ def parse_signature(self, node):
+ node.args = args = []
+ node.defaults = defaults = []
self.stream.expect("lparen")
while self.stream.current.type != "rparen":
- if args:
+ if args:
self.stream.expect("comma")
- arg = self.parse_assign_target(name_only=True)
+ arg = self.parse_assign_target(name_only=True)
arg.set_ctx("param")
if self.stream.skip_if("assign"):
- defaults.append(self.parse_expression())
- elif defaults:
+ defaults.append(self.parse_expression())
+ elif defaults:
self.fail("non-default argument follows default argument")
- args.append(arg)
+ args.append(arg)
self.stream.expect("rparen")
-
- def parse_call_block(self):
- node = nodes.CallBlock(lineno=next(self.stream).lineno)
+
+ def parse_call_block(self):
+ node = nodes.CallBlock(lineno=next(self.stream).lineno)
if self.stream.current.type == "lparen":
- self.parse_signature(node)
- else:
- node.args = []
- node.defaults = []
-
- node.call = self.parse_expression()
- if not isinstance(node.call, nodes.Call):
+ self.parse_signature(node)
+ else:
+ node.args = []
+ node.defaults = []
+
+ node.call = self.parse_expression()
+ if not isinstance(node.call, nodes.Call):
self.fail("expected call", node.lineno)
node.body = self.parse_statements(("name:endcall",), drop_needle=True)
- return node
-
- def parse_filter_block(self):
- node = nodes.FilterBlock(lineno=next(self.stream).lineno)
- node.filter = self.parse_filter(None, start_inline=True)
+ return node
+
+ def parse_filter_block(self):
+ node = nodes.FilterBlock(lineno=next(self.stream).lineno)
+ node.filter = self.parse_filter(None, start_inline=True)
node.body = self.parse_statements(("name:endfilter",), drop_needle=True)
- return node
-
- def parse_macro(self):
- node = nodes.Macro(lineno=next(self.stream).lineno)
- node.name = self.parse_assign_target(name_only=True).name
- self.parse_signature(node)
+ return node
+
+ def parse_macro(self):
+ node = nodes.Macro(lineno=next(self.stream).lineno)
+ node.name = self.parse_assign_target(name_only=True).name
+ self.parse_signature(node)
node.body = self.parse_statements(("name:endmacro",), drop_needle=True)
- return node
-
- def parse_print(self):
- node = nodes.Output(lineno=next(self.stream).lineno)
- node.nodes = []
+ return node
+
+ def parse_print(self):
+ node = nodes.Output(lineno=next(self.stream).lineno)
+ node.nodes = []
while self.stream.current.type != "block_end":
- if node.nodes:
+ if node.nodes:
self.stream.expect("comma")
- node.nodes.append(self.parse_expression())
- return node
-
+ node.nodes.append(self.parse_expression())
+ return node
+
def parse_assign_target(
self,
with_tuple=True,
@@ -410,195 +410,195 @@ class Parser(object):
with_namespace=False,
):
"""Parse an assignment target. As Jinja allows assignments to
- tuples, this function can parse all allowed assignment targets. Per
- default assignments to tuples are parsed, that can be disable however
- by setting `with_tuple` to `False`. If only assignments to names are
- wanted `name_only` can be set to `True`. The `extra_end_rules`
- parameter is forwarded to the tuple parsing function. If
- `with_namespace` is enabled, a namespace assignment may be parsed.
- """
+ tuples, this function can parse all allowed assignment targets. Per
+ default assignments to tuples are parsed, that can be disable however
+ by setting `with_tuple` to `False`. If only assignments to names are
+ wanted `name_only` can be set to `True`. The `extra_end_rules`
+ parameter is forwarded to the tuple parsing function. If
+ `with_namespace` is enabled, a namespace assignment may be parsed.
+ """
if with_namespace and self.stream.look().type == "dot":
token = self.stream.expect("name")
- next(self.stream) # dot
+ next(self.stream) # dot
attr = self.stream.expect("name")
- target = nodes.NSRef(token.value, attr.value, lineno=token.lineno)
- elif name_only:
+ target = nodes.NSRef(token.value, attr.value, lineno=token.lineno)
+ elif name_only:
token = self.stream.expect("name")
target = nodes.Name(token.value, "store", lineno=token.lineno)
- else:
- if with_tuple:
+ else:
+ if with_tuple:
target = self.parse_tuple(
simplified=True, extra_end_rules=extra_end_rules
)
- else:
- target = self.parse_primary()
+ else:
+ target = self.parse_primary()
target.set_ctx("store")
- if not target.can_assign():
+ if not target.can_assign():
self.fail(
"can't assign to %r" % target.__class__.__name__.lower(), target.lineno
)
- return target
-
- def parse_expression(self, with_condexpr=True):
- """Parse an expression. Per default all expressions are parsed, if
- the optional `with_condexpr` parameter is set to `False` conditional
- expressions are not parsed.
- """
- if with_condexpr:
- return self.parse_condexpr()
- return self.parse_or()
-
- def parse_condexpr(self):
- lineno = self.stream.current.lineno
- expr1 = self.parse_or()
+ return target
+
+ def parse_expression(self, with_condexpr=True):
+ """Parse an expression. Per default all expressions are parsed, if
+ the optional `with_condexpr` parameter is set to `False` conditional
+ expressions are not parsed.
+ """
+ if with_condexpr:
+ return self.parse_condexpr()
+ return self.parse_or()
+
+ def parse_condexpr(self):
+ lineno = self.stream.current.lineno
+ expr1 = self.parse_or()
while self.stream.skip_if("name:if"):
- expr2 = self.parse_or()
+ expr2 = self.parse_or()
if self.stream.skip_if("name:else"):
- expr3 = self.parse_condexpr()
- else:
- expr3 = None
- expr1 = nodes.CondExpr(expr2, expr1, expr3, lineno=lineno)
- lineno = self.stream.current.lineno
- return expr1
-
- def parse_or(self):
- lineno = self.stream.current.lineno
- left = self.parse_and()
+ expr3 = self.parse_condexpr()
+ else:
+ expr3 = None
+ expr1 = nodes.CondExpr(expr2, expr1, expr3, lineno=lineno)
+ lineno = self.stream.current.lineno
+ return expr1
+
+ def parse_or(self):
+ lineno = self.stream.current.lineno
+ left = self.parse_and()
while self.stream.skip_if("name:or"):
- right = self.parse_and()
- left = nodes.Or(left, right, lineno=lineno)
- lineno = self.stream.current.lineno
- return left
-
- def parse_and(self):
- lineno = self.stream.current.lineno
- left = self.parse_not()
+ right = self.parse_and()
+ left = nodes.Or(left, right, lineno=lineno)
+ lineno = self.stream.current.lineno
+ return left
+
+ def parse_and(self):
+ lineno = self.stream.current.lineno
+ left = self.parse_not()
while self.stream.skip_if("name:and"):
- right = self.parse_not()
- left = nodes.And(left, right, lineno=lineno)
- lineno = self.stream.current.lineno
- return left
-
- def parse_not(self):
+ right = self.parse_not()
+ left = nodes.And(left, right, lineno=lineno)
+ lineno = self.stream.current.lineno
+ return left
+
+ def parse_not(self):
if self.stream.current.test("name:not"):
- lineno = next(self.stream).lineno
- return nodes.Not(self.parse_not(), lineno=lineno)
- return self.parse_compare()
-
- def parse_compare(self):
- lineno = self.stream.current.lineno
- expr = self.parse_math1()
- ops = []
- while 1:
- token_type = self.stream.current.type
- if token_type in _compare_operators:
- next(self.stream)
- ops.append(nodes.Operand(token_type, self.parse_math1()))
+ lineno = next(self.stream).lineno
+ return nodes.Not(self.parse_not(), lineno=lineno)
+ return self.parse_compare()
+
+ def parse_compare(self):
+ lineno = self.stream.current.lineno
+ expr = self.parse_math1()
+ ops = []
+ while 1:
+ token_type = self.stream.current.type
+ if token_type in _compare_operators:
+ next(self.stream)
+ ops.append(nodes.Operand(token_type, self.parse_math1()))
elif self.stream.skip_if("name:in"):
ops.append(nodes.Operand("in", self.parse_math1()))
elif self.stream.current.test("name:not") and self.stream.look().test(
"name:in"
):
- self.stream.skip(2)
+ self.stream.skip(2)
ops.append(nodes.Operand("notin", self.parse_math1()))
- else:
- break
- lineno = self.stream.current.lineno
- if not ops:
- return expr
- return nodes.Compare(expr, ops, lineno=lineno)
-
- def parse_math1(self):
- lineno = self.stream.current.lineno
- left = self.parse_concat()
+ else:
+ break
+ lineno = self.stream.current.lineno
+ if not ops:
+ return expr
+ return nodes.Compare(expr, ops, lineno=lineno)
+
+ def parse_math1(self):
+ lineno = self.stream.current.lineno
+ left = self.parse_concat()
while self.stream.current.type in ("add", "sub"):
- cls = _math_nodes[self.stream.current.type]
- next(self.stream)
- right = self.parse_concat()
- left = cls(left, right, lineno=lineno)
- lineno = self.stream.current.lineno
- return left
-
- def parse_concat(self):
- lineno = self.stream.current.lineno
- args = [self.parse_math2()]
+ cls = _math_nodes[self.stream.current.type]
+ next(self.stream)
+ right = self.parse_concat()
+ left = cls(left, right, lineno=lineno)
+ lineno = self.stream.current.lineno
+ return left
+
+ def parse_concat(self):
+ lineno = self.stream.current.lineno
+ args = [self.parse_math2()]
while self.stream.current.type == "tilde":
- next(self.stream)
- args.append(self.parse_math2())
- if len(args) == 1:
- return args[0]
- return nodes.Concat(args, lineno=lineno)
-
- def parse_math2(self):
- lineno = self.stream.current.lineno
- left = self.parse_pow()
+ next(self.stream)
+ args.append(self.parse_math2())
+ if len(args) == 1:
+ return args[0]
+ return nodes.Concat(args, lineno=lineno)
+
+ def parse_math2(self):
+ lineno = self.stream.current.lineno
+ left = self.parse_pow()
while self.stream.current.type in ("mul", "div", "floordiv", "mod"):
- cls = _math_nodes[self.stream.current.type]
- next(self.stream)
- right = self.parse_pow()
- left = cls(left, right, lineno=lineno)
- lineno = self.stream.current.lineno
- return left
-
- def parse_pow(self):
- lineno = self.stream.current.lineno
- left = self.parse_unary()
+ cls = _math_nodes[self.stream.current.type]
+ next(self.stream)
+ right = self.parse_pow()
+ left = cls(left, right, lineno=lineno)
+ lineno = self.stream.current.lineno
+ return left
+
+ def parse_pow(self):
+ lineno = self.stream.current.lineno
+ left = self.parse_unary()
while self.stream.current.type == "pow":
- next(self.stream)
- right = self.parse_unary()
- left = nodes.Pow(left, right, lineno=lineno)
- lineno = self.stream.current.lineno
- return left
-
- def parse_unary(self, with_filter=True):
- token_type = self.stream.current.type
- lineno = self.stream.current.lineno
+ next(self.stream)
+ right = self.parse_unary()
+ left = nodes.Pow(left, right, lineno=lineno)
+ lineno = self.stream.current.lineno
+ return left
+
+ def parse_unary(self, with_filter=True):
+ token_type = self.stream.current.type
+ lineno = self.stream.current.lineno
if token_type == "sub":
- next(self.stream)
- node = nodes.Neg(self.parse_unary(False), lineno=lineno)
+ next(self.stream)
+ node = nodes.Neg(self.parse_unary(False), lineno=lineno)
elif token_type == "add":
- next(self.stream)
- node = nodes.Pos(self.parse_unary(False), lineno=lineno)
- else:
- node = self.parse_primary()
- node = self.parse_postfix(node)
- if with_filter:
- node = self.parse_filter_expr(node)
- return node
-
- def parse_primary(self):
- token = self.stream.current
+ next(self.stream)
+ node = nodes.Pos(self.parse_unary(False), lineno=lineno)
+ else:
+ node = self.parse_primary()
+ node = self.parse_postfix(node)
+ if with_filter:
+ node = self.parse_filter_expr(node)
+ return node
+
+ def parse_primary(self):
+ token = self.stream.current
if token.type == "name":
if token.value in ("true", "false", "True", "False"):
node = nodes.Const(token.value in ("true", "True"), lineno=token.lineno)
elif token.value in ("none", "None"):
- node = nodes.Const(None, lineno=token.lineno)
- else:
+ node = nodes.Const(None, lineno=token.lineno)
+ else:
node = nodes.Name(token.value, "load", lineno=token.lineno)
- next(self.stream)
+ next(self.stream)
elif token.type == "string":
- next(self.stream)
- buf = [token.value]
- lineno = token.lineno
+ next(self.stream)
+ buf = [token.value]
+ lineno = token.lineno
while self.stream.current.type == "string":
- buf.append(self.stream.current.value)
- next(self.stream)
+ buf.append(self.stream.current.value)
+ next(self.stream)
node = nodes.Const("".join(buf), lineno=lineno)
elif token.type in ("integer", "float"):
- next(self.stream)
- node = nodes.Const(token.value, lineno=token.lineno)
+ next(self.stream)
+ node = nodes.Const(token.value, lineno=token.lineno)
elif token.type == "lparen":
- next(self.stream)
- node = self.parse_tuple(explicit_parentheses=True)
+ next(self.stream)
+ node = self.parse_tuple(explicit_parentheses=True)
self.stream.expect("rparen")
elif token.type == "lbracket":
- node = self.parse_list()
+ node = self.parse_list()
elif token.type == "lbrace":
- node = self.parse_dict()
- else:
- self.fail("unexpected '%s'" % describe_token(token), token.lineno)
- return node
-
+ node = self.parse_dict()
+ else:
+ self.fail("unexpected '%s'" % describe_token(token), token.lineno)
+ return node
+
def parse_tuple(
self,
simplified=False,
@@ -606,261 +606,261 @@ class Parser(object):
extra_end_rules=None,
explicit_parentheses=False,
):
- """Works like `parse_expression` but if multiple expressions are
- delimited by a comma a :class:`~jinja2.nodes.Tuple` node is created.
- This method could also return a regular expression instead of a tuple
- if no commas where found.
-
- The default parsing mode is a full tuple. If `simplified` is `True`
- only names and literals are parsed. The `no_condexpr` parameter is
- forwarded to :meth:`parse_expression`.
-
- Because tuples do not require delimiters and may end in a bogus comma
- an extra hint is needed that marks the end of a tuple. For example
- for loops support tuples between `for` and `in`. In that case the
- `extra_end_rules` is set to ``['name:in']``.
-
- `explicit_parentheses` is true if the parsing was triggered by an
- expression in parentheses. This is used to figure out if an empty
- tuple is a valid expression or not.
- """
- lineno = self.stream.current.lineno
- if simplified:
- parse = self.parse_primary
- elif with_condexpr:
- parse = self.parse_expression
- else:
+ """Works like `parse_expression` but if multiple expressions are
+ delimited by a comma a :class:`~jinja2.nodes.Tuple` node is created.
+ This method could also return a regular expression instead of a tuple
+ if no commas where found.
+
+ The default parsing mode is a full tuple. If `simplified` is `True`
+ only names and literals are parsed. The `no_condexpr` parameter is
+ forwarded to :meth:`parse_expression`.
+
+ Because tuples do not require delimiters and may end in a bogus comma
+ an extra hint is needed that marks the end of a tuple. For example
+ for loops support tuples between `for` and `in`. In that case the
+ `extra_end_rules` is set to ``['name:in']``.
+
+ `explicit_parentheses` is true if the parsing was triggered by an
+ expression in parentheses. This is used to figure out if an empty
+ tuple is a valid expression or not.
+ """
+ lineno = self.stream.current.lineno
+ if simplified:
+ parse = self.parse_primary
+ elif with_condexpr:
+ parse = self.parse_expression
+ else:
def parse():
return self.parse_expression(with_condexpr=False)
- args = []
- is_tuple = False
- while 1:
- if args:
+ args = []
+ is_tuple = False
+ while 1:
+ if args:
self.stream.expect("comma")
- if self.is_tuple_end(extra_end_rules):
- break
- args.append(parse())
+ if self.is_tuple_end(extra_end_rules):
+ break
+ args.append(parse())
if self.stream.current.type == "comma":
- is_tuple = True
- else:
- break
- lineno = self.stream.current.lineno
-
- if not is_tuple:
- if args:
- return args[0]
-
- # if we don't have explicit parentheses, an empty tuple is
- # not a valid expression. This would mean nothing (literally
- # nothing) in the spot of an expression would be an empty
- # tuple.
- if not explicit_parentheses:
+ is_tuple = True
+ else:
+ break
+ lineno = self.stream.current.lineno
+
+ if not is_tuple:
+ if args:
+ return args[0]
+
+ # if we don't have explicit parentheses, an empty tuple is
+ # not a valid expression. This would mean nothing (literally
+ # nothing) in the spot of an expression would be an empty
+ # tuple.
+ if not explicit_parentheses:
self.fail(
"Expected an expression, got '%s'"
% describe_token(self.stream.current)
)
-
+
return nodes.Tuple(args, "load", lineno=lineno)
-
- def parse_list(self):
+
+ def parse_list(self):
token = self.stream.expect("lbracket")
- items = []
+ items = []
while self.stream.current.type != "rbracket":
- if items:
+ if items:
self.stream.expect("comma")
if self.stream.current.type == "rbracket":
- break
- items.append(self.parse_expression())
+ break
+ items.append(self.parse_expression())
self.stream.expect("rbracket")
- return nodes.List(items, lineno=token.lineno)
-
- def parse_dict(self):
+ return nodes.List(items, lineno=token.lineno)
+
+ def parse_dict(self):
token = self.stream.expect("lbrace")
- items = []
+ items = []
while self.stream.current.type != "rbrace":
- if items:
+ if items:
self.stream.expect("comma")
if self.stream.current.type == "rbrace":
- break
- key = self.parse_expression()
+ break
+ key = self.parse_expression()
self.stream.expect("colon")
- value = self.parse_expression()
- items.append(nodes.Pair(key, value, lineno=key.lineno))
+ value = self.parse_expression()
+ items.append(nodes.Pair(key, value, lineno=key.lineno))
self.stream.expect("rbrace")
- return nodes.Dict(items, lineno=token.lineno)
-
- def parse_postfix(self, node):
- while 1:
- token_type = self.stream.current.type
+ return nodes.Dict(items, lineno=token.lineno)
+
+ def parse_postfix(self, node):
+ while 1:
+ token_type = self.stream.current.type
if token_type == "dot" or token_type == "lbracket":
- node = self.parse_subscript(node)
- # calls are valid both after postfix expressions (getattr
- # and getitem) as well as filters and tests
+ node = self.parse_subscript(node)
+ # calls are valid both after postfix expressions (getattr
+ # and getitem) as well as filters and tests
elif token_type == "lparen":
- node = self.parse_call(node)
- else:
- break
- return node
-
- def parse_filter_expr(self, node):
- while 1:
- token_type = self.stream.current.type
+ node = self.parse_call(node)
+ else:
+ break
+ return node
+
+ def parse_filter_expr(self, node):
+ while 1:
+ token_type = self.stream.current.type
if token_type == "pipe":
- node = self.parse_filter(node)
+ node = self.parse_filter(node)
elif token_type == "name" and self.stream.current.value == "is":
- node = self.parse_test(node)
- # calls are valid both after postfix expressions (getattr
- # and getitem) as well as filters and tests
+ node = self.parse_test(node)
+ # calls are valid both after postfix expressions (getattr
+ # and getitem) as well as filters and tests
elif token_type == "lparen":
- node = self.parse_call(node)
- else:
- break
- return node
-
- def parse_subscript(self, node):
- token = next(self.stream)
+ node = self.parse_call(node)
+ else:
+ break
+ return node
+
+ def parse_subscript(self, node):
+ token = next(self.stream)
if token.type == "dot":
- attr_token = self.stream.current
- next(self.stream)
+ attr_token = self.stream.current
+ next(self.stream)
if attr_token.type == "name":
return nodes.Getattr(
node, attr_token.value, "load", lineno=token.lineno
)
elif attr_token.type != "integer":
self.fail("expected name or number", attr_token.lineno)
- arg = nodes.Const(attr_token.value, lineno=attr_token.lineno)
+ arg = nodes.Const(attr_token.value, lineno=attr_token.lineno)
return nodes.Getitem(node, arg, "load", lineno=token.lineno)
if token.type == "lbracket":
- args = []
+ args = []
while self.stream.current.type != "rbracket":
- if args:
+ if args:
self.stream.expect("comma")
- args.append(self.parse_subscribed())
+ args.append(self.parse_subscribed())
self.stream.expect("rbracket")
- if len(args) == 1:
- arg = args[0]
- else:
+ if len(args) == 1:
+ arg = args[0]
+ else:
arg = nodes.Tuple(args, "load", lineno=token.lineno)
return nodes.Getitem(node, arg, "load", lineno=token.lineno)
self.fail("expected subscript expression", token.lineno)
-
- def parse_subscribed(self):
- lineno = self.stream.current.lineno
-
+
+ def parse_subscribed(self):
+ lineno = self.stream.current.lineno
+
if self.stream.current.type == "colon":
- next(self.stream)
- args = [None]
- else:
- node = self.parse_expression()
+ next(self.stream)
+ args = [None]
+ else:
+ node = self.parse_expression()
if self.stream.current.type != "colon":
- return node
- next(self.stream)
- args = [node]
-
+ return node
+ next(self.stream)
+ args = [node]
+
if self.stream.current.type == "colon":
- args.append(None)
+ args.append(None)
elif self.stream.current.type not in ("rbracket", "comma"):
- args.append(self.parse_expression())
- else:
- args.append(None)
-
+ args.append(self.parse_expression())
+ else:
+ args.append(None)
+
if self.stream.current.type == "colon":
- next(self.stream)
+ next(self.stream)
if self.stream.current.type not in ("rbracket", "comma"):
- args.append(self.parse_expression())
- else:
- args.append(None)
- else:
- args.append(None)
-
- return nodes.Slice(lineno=lineno, *args)
-
- def parse_call(self, node):
+ args.append(self.parse_expression())
+ else:
+ args.append(None)
+ else:
+ args.append(None)
+
+ return nodes.Slice(lineno=lineno, *args)
+
+ def parse_call(self, node):
token = self.stream.expect("lparen")
- args = []
- kwargs = []
- dyn_args = dyn_kwargs = None
- require_comma = False
-
- def ensure(expr):
- if not expr:
+ args = []
+ kwargs = []
+ dyn_args = dyn_kwargs = None
+ require_comma = False
+
+ def ensure(expr):
+ if not expr:
self.fail("invalid syntax for function call expression", token.lineno)
-
+
while self.stream.current.type != "rparen":
- if require_comma:
+ if require_comma:
self.stream.expect("comma")
- # support for trailing comma
+ # support for trailing comma
if self.stream.current.type == "rparen":
- break
+ break
if self.stream.current.type == "mul":
- ensure(dyn_args is None and dyn_kwargs is None)
- next(self.stream)
- dyn_args = self.parse_expression()
+ ensure(dyn_args is None and dyn_kwargs is None)
+ next(self.stream)
+ dyn_args = self.parse_expression()
elif self.stream.current.type == "pow":
- ensure(dyn_kwargs is None)
- next(self.stream)
- dyn_kwargs = self.parse_expression()
- else:
+ ensure(dyn_kwargs is None)
+ next(self.stream)
+ dyn_kwargs = self.parse_expression()
+ else:
if (
self.stream.current.type == "name"
and self.stream.look().type == "assign"
):
# Parsing a kwarg
ensure(dyn_kwargs is None)
- key = self.stream.current.value
- self.stream.skip(2)
- value = self.parse_expression()
+ key = self.stream.current.value
+ self.stream.skip(2)
+ value = self.parse_expression()
kwargs.append(nodes.Keyword(key, value, lineno=value.lineno))
- else:
+ else:
# Parsing an arg
ensure(dyn_args is None and dyn_kwargs is None and not kwargs)
- args.append(self.parse_expression())
-
- require_comma = True
+ args.append(self.parse_expression())
+
+ require_comma = True
self.stream.expect("rparen")
-
- if node is None:
- return args, kwargs, dyn_args, dyn_kwargs
+
+ if node is None:
+ return args, kwargs, dyn_args, dyn_kwargs
return nodes.Call(node, args, kwargs, dyn_args, dyn_kwargs, lineno=token.lineno)
-
- def parse_filter(self, node, start_inline=False):
+
+ def parse_filter(self, node, start_inline=False):
while self.stream.current.type == "pipe" or start_inline:
- if not start_inline:
- next(self.stream)
+ if not start_inline:
+ next(self.stream)
token = self.stream.expect("name")
- name = token.value
+ name = token.value
while self.stream.current.type == "dot":
- next(self.stream)
+ next(self.stream)
name += "." + self.stream.expect("name").value
if self.stream.current.type == "lparen":
- args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None)
- else:
- args = []
- kwargs = []
- dyn_args = dyn_kwargs = None
+ args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None)
+ else:
+ args = []
+ kwargs = []
+ dyn_args = dyn_kwargs = None
node = nodes.Filter(
node, name, args, kwargs, dyn_args, dyn_kwargs, lineno=token.lineno
)
- start_inline = False
- return node
-
- def parse_test(self, node):
- token = next(self.stream)
+ start_inline = False
+ return node
+
+ def parse_test(self, node):
+ token = next(self.stream)
if self.stream.current.test("name:not"):
- next(self.stream)
- negated = True
- else:
- negated = False
+ next(self.stream)
+ negated = True
+ else:
+ negated = False
name = self.stream.expect("name").value
while self.stream.current.type == "dot":
- next(self.stream)
+ next(self.stream)
name += "." + self.stream.expect("name").value
- dyn_args = dyn_kwargs = None
- kwargs = []
+ dyn_args = dyn_kwargs = None
+ kwargs = []
if self.stream.current.type == "lparen":
- args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None)
+ args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None)
elif self.stream.current.type in (
"name",
"string",
@@ -875,65 +875,65 @@ class Parser(object):
arg_node = self.parse_primary()
arg_node = self.parse_postfix(arg_node)
args = [arg_node]
- else:
- args = []
+ else:
+ args = []
node = nodes.Test(
node, name, args, kwargs, dyn_args, dyn_kwargs, lineno=token.lineno
)
- if negated:
- node = nodes.Not(node, lineno=token.lineno)
- return node
-
- def subparse(self, end_tokens=None):
- body = []
- data_buffer = []
- add_data = data_buffer.append
-
- if end_tokens is not None:
- self._end_token_stack.append(end_tokens)
-
- def flush_data():
- if data_buffer:
- lineno = data_buffer[0].lineno
- body.append(nodes.Output(data_buffer[:], lineno=lineno))
- del data_buffer[:]
-
- try:
- while self.stream:
- token = self.stream.current
+ if negated:
+ node = nodes.Not(node, lineno=token.lineno)
+ return node
+
+ def subparse(self, end_tokens=None):
+ body = []
+ data_buffer = []
+ add_data = data_buffer.append
+
+ if end_tokens is not None:
+ self._end_token_stack.append(end_tokens)
+
+ def flush_data():
+ if data_buffer:
+ lineno = data_buffer[0].lineno
+ body.append(nodes.Output(data_buffer[:], lineno=lineno))
+ del data_buffer[:]
+
+ try:
+ while self.stream:
+ token = self.stream.current
if token.type == "data":
- if token.value:
+ if token.value:
add_data(nodes.TemplateData(token.value, lineno=token.lineno))
- next(self.stream)
+ next(self.stream)
elif token.type == "variable_begin":
- next(self.stream)
- add_data(self.parse_tuple(with_condexpr=True))
+ next(self.stream)
+ add_data(self.parse_tuple(with_condexpr=True))
self.stream.expect("variable_end")
elif token.type == "block_begin":
- flush_data()
- next(self.stream)
+ flush_data()
+ next(self.stream)
if end_tokens is not None and self.stream.current.test_any(
*end_tokens
):
- return body
- rv = self.parse_statement()
- if isinstance(rv, list):
- body.extend(rv)
- else:
- body.append(rv)
+ return body
+ rv = self.parse_statement()
+ if isinstance(rv, list):
+ body.extend(rv)
+ else:
+ body.append(rv)
self.stream.expect("block_end")
- else:
+ else:
raise AssertionError("internal parsing error")
-
- flush_data()
- finally:
- if end_tokens is not None:
- self._end_token_stack.pop()
-
- return body
-
- def parse(self):
- """Parse the whole template into a `Template` node."""
- result = nodes.Template(self.subparse(), lineno=1)
- result.set_environment(self.environment)
- return result
+
+ flush_data()
+ finally:
+ if end_tokens is not None:
+ self._end_token_stack.pop()
+
+ return body
+
+ def parse(self):
+ """Parse the whole template into a `Template` node."""
+ result = nodes.Template(self.subparse(), lineno=1)
+ result.set_environment(self.environment)
+ return result
diff --git a/contrib/python/Jinja2/py2/jinja2/runtime.py b/contrib/python/Jinja2/py2/jinja2/runtime.py
index 3ad7968624..850f82da1c 100644
--- a/contrib/python/Jinja2/py2/jinja2/runtime.py
+++ b/contrib/python/Jinja2/py2/jinja2/runtime.py
@@ -1,13 +1,13 @@
-# -*- coding: utf-8 -*-
+# -*- coding: utf-8 -*-
"""The runtime functions and state used by compiled templates."""
-import sys
-from itertools import chain
-from types import MethodType
-
+import sys
+from itertools import chain
+from types import MethodType
+
from markupsafe import escape # noqa: F401
from markupsafe import Markup
from markupsafe import soft_unicode
-
+
from ._compat import abc
from ._compat import imap
from ._compat import implements_iterator
@@ -27,8 +27,8 @@ from .utils import internalcode
from .utils import missing
from .utils import Namespace # noqa: F401
from .utils import object_type_repr
-
-# these variables are exported to the template runtime
+
+# these variables are exported to the template runtime
exported = [
"LoopContext",
"TemplateReference",
@@ -46,35 +46,35 @@ exported = [
"Namespace",
"Undefined",
]
-
-#: the name of the function that is used to convert something into
-#: a string. We can just use the text type here.
-to_string = text_type
-
-
+
+#: the name of the function that is used to convert something into
+#: a string. We can just use the text type here.
+to_string = text_type
+
+
def identity(x):
"""Returns its argument. Useful for certain things in the
environment.
"""
return x
-
-
-def markup_join(seq):
- """Concatenation that escapes if necessary and converts to unicode."""
- buf = []
- iterator = imap(soft_unicode, seq)
- for arg in iterator:
- buf.append(arg)
+
+
+def markup_join(seq):
+ """Concatenation that escapes if necessary and converts to unicode."""
+ buf = []
+ iterator = imap(soft_unicode, seq)
+ for arg in iterator:
+ buf.append(arg)
if hasattr(arg, "__html__"):
return Markup(u"").join(chain(buf, iterator))
- return concat(buf)
-
-
-def unicode_join(seq):
- """Simple args to unicode conversion and concatenation."""
- return concat(imap(text_type, seq))
-
-
+ return concat(buf)
+
+
+def unicode_join(seq):
+ """Simple args to unicode conversion and concatenation."""
+ return concat(imap(text_type, seq))
+
+
def new_context(
environment,
template_name,
@@ -85,311 +85,311 @@ def new_context(
locals=None,
):
"""Internal helper for context creation."""
- if vars is None:
- vars = {}
- if shared:
- parent = vars
- else:
- parent = dict(globals or (), **vars)
- if locals:
- # if the parent is shared a copy should be created because
- # we don't want to modify the dict passed
- if shared:
- parent = dict(parent)
- for key, value in iteritems(locals):
- if value is not missing:
- parent[key] = value
+ if vars is None:
+ vars = {}
+ if shared:
+ parent = vars
+ else:
+ parent = dict(globals or (), **vars)
+ if locals:
+ # if the parent is shared a copy should be created because
+ # we don't want to modify the dict passed
+ if shared:
+ parent = dict(parent)
+ for key, value in iteritems(locals):
+ if value is not missing:
+ parent[key] = value
return environment.context_class(environment, parent, template_name, blocks)
-
-
-class TemplateReference(object):
- """The `self` in templates."""
-
- def __init__(self, context):
- self.__context = context
-
- def __getitem__(self, name):
- blocks = self.__context.blocks[name]
- return BlockReference(name, self.__context, blocks, 0)
-
- def __repr__(self):
+
+
+class TemplateReference(object):
+ """The `self` in templates."""
+
+ def __init__(self, context):
+ self.__context = context
+
+ def __getitem__(self, name):
+ blocks = self.__context.blocks[name]
+ return BlockReference(name, self.__context, blocks, 0)
+
+ def __repr__(self):
return "<%s %r>" % (self.__class__.__name__, self.__context.name)
-
-
-def _get_func(x):
+
+
+def _get_func(x):
return getattr(x, "__func__", x)
-
-
-class ContextMeta(type):
+
+
+class ContextMeta(type):
def __new__(mcs, name, bases, d):
rv = type.__new__(mcs, name, bases, d)
- if bases == ():
- return rv
-
- resolve = _get_func(rv.resolve)
- default_resolve = _get_func(Context.resolve)
- resolve_or_missing = _get_func(rv.resolve_or_missing)
- default_resolve_or_missing = _get_func(Context.resolve_or_missing)
-
- # If we have a changed resolve but no changed default or missing
- # resolve we invert the call logic.
+ if bases == ():
+ return rv
+
+ resolve = _get_func(rv.resolve)
+ default_resolve = _get_func(Context.resolve)
+ resolve_or_missing = _get_func(rv.resolve_or_missing)
+ default_resolve_or_missing = _get_func(Context.resolve_or_missing)
+
+ # If we have a changed resolve but no changed default or missing
+ # resolve we invert the call logic.
if (
resolve is not default_resolve
and resolve_or_missing is default_resolve_or_missing
):
- rv._legacy_resolve_mode = True
+ rv._legacy_resolve_mode = True
elif (
resolve is default_resolve
and resolve_or_missing is default_resolve_or_missing
):
- rv._fast_resolve_mode = True
-
- return rv
-
-
-def resolve_or_missing(context, key, missing=missing):
- if key in context.vars:
- return context.vars[key]
- if key in context.parent:
- return context.parent[key]
- return missing
-
-
-class Context(with_metaclass(ContextMeta)):
- """The template context holds the variables of a template. It stores the
- values passed to the template and also the names the template exports.
- Creating instances is neither supported nor useful as it's created
- automatically at various stages of the template evaluation and should not
- be created by hand.
-
- The context is immutable. Modifications on :attr:`parent` **must not**
- happen and modifications on :attr:`vars` are allowed from generated
- template code only. Template filters and global functions marked as
- :func:`contextfunction`\\s get the active context passed as first argument
- and are allowed to access the context read-only.
-
- The template context supports read only dict operations (`get`,
- `keys`, `values`, `items`, `iterkeys`, `itervalues`, `iteritems`,
- `__getitem__`, `__contains__`). Additionally there is a :meth:`resolve`
- method that doesn't fail with a `KeyError` but returns an
- :class:`Undefined` object for missing variables.
- """
-
- # XXX: we want to eventually make this be a deprecation warning and
- # remove it.
- _legacy_resolve_mode = False
- _fast_resolve_mode = False
-
- def __init__(self, environment, parent, name, blocks):
- self.parent = parent
- self.vars = {}
- self.environment = environment
- self.eval_ctx = EvalContext(self.environment, name)
- self.exported_vars = set()
- self.name = name
-
- # create the initial mapping of blocks. Whenever template inheritance
- # takes place the runtime will update this mapping with the new blocks
- # from the template.
- self.blocks = dict((k, [v]) for k, v in iteritems(blocks))
-
- # In case we detect the fast resolve mode we can set up an alias
- # here that bypasses the legacy code logic.
- if self._fast_resolve_mode:
- self.resolve_or_missing = MethodType(resolve_or_missing, self)
-
- def super(self, name, current):
- """Render a parent block."""
- try:
- blocks = self.blocks[name]
- index = blocks.index(current) + 1
- blocks[index]
- except LookupError:
+ rv._fast_resolve_mode = True
+
+ return rv
+
+
+def resolve_or_missing(context, key, missing=missing):
+ if key in context.vars:
+ return context.vars[key]
+ if key in context.parent:
+ return context.parent[key]
+ return missing
+
+
+class Context(with_metaclass(ContextMeta)):
+ """The template context holds the variables of a template. It stores the
+ values passed to the template and also the names the template exports.
+ Creating instances is neither supported nor useful as it's created
+ automatically at various stages of the template evaluation and should not
+ be created by hand.
+
+ The context is immutable. Modifications on :attr:`parent` **must not**
+ happen and modifications on :attr:`vars` are allowed from generated
+ template code only. Template filters and global functions marked as
+ :func:`contextfunction`\\s get the active context passed as first argument
+ and are allowed to access the context read-only.
+
+ The template context supports read only dict operations (`get`,
+ `keys`, `values`, `items`, `iterkeys`, `itervalues`, `iteritems`,
+ `__getitem__`, `__contains__`). Additionally there is a :meth:`resolve`
+ method that doesn't fail with a `KeyError` but returns an
+ :class:`Undefined` object for missing variables.
+ """
+
+ # XXX: we want to eventually make this be a deprecation warning and
+ # remove it.
+ _legacy_resolve_mode = False
+ _fast_resolve_mode = False
+
+ def __init__(self, environment, parent, name, blocks):
+ self.parent = parent
+ self.vars = {}
+ self.environment = environment
+ self.eval_ctx = EvalContext(self.environment, name)
+ self.exported_vars = set()
+ self.name = name
+
+ # create the initial mapping of blocks. Whenever template inheritance
+ # takes place the runtime will update this mapping with the new blocks
+ # from the template.
+ self.blocks = dict((k, [v]) for k, v in iteritems(blocks))
+
+ # In case we detect the fast resolve mode we can set up an alias
+ # here that bypasses the legacy code logic.
+ if self._fast_resolve_mode:
+ self.resolve_or_missing = MethodType(resolve_or_missing, self)
+
+ def super(self, name, current):
+ """Render a parent block."""
+ try:
+ blocks = self.blocks[name]
+ index = blocks.index(current) + 1
+ blocks[index]
+ except LookupError:
return self.environment.undefined(
"there is no parent block called %r." % name, name="super"
)
- return BlockReference(name, self, blocks, index)
-
- def get(self, key, default=None):
- """Returns an item from the template context, if it doesn't exist
- `default` is returned.
- """
- try:
- return self[key]
- except KeyError:
- return default
-
- def resolve(self, key):
- """Looks up a variable like `__getitem__` or `get` but returns an
- :class:`Undefined` object with the name of the name looked up.
- """
- if self._legacy_resolve_mode:
- rv = resolve_or_missing(self, key)
- else:
- rv = self.resolve_or_missing(key)
- if rv is missing:
- return self.environment.undefined(name=key)
- return rv
-
- def resolve_or_missing(self, key):
- """Resolves a variable like :meth:`resolve` but returns the
- special `missing` value if it cannot be found.
- """
- if self._legacy_resolve_mode:
- rv = self.resolve(key)
- if isinstance(rv, Undefined):
- rv = missing
- return rv
- return resolve_or_missing(self, key)
-
- def get_exported(self):
- """Get a new dict with the exported variables."""
- return dict((k, self.vars[k]) for k in self.exported_vars)
-
- def get_all(self):
- """Return the complete context as dict including the exported
- variables. For optimizations reasons this might not return an
- actual copy so be careful with using it.
- """
- if not self.vars:
- return self.parent
- if not self.parent:
- return self.vars
- return dict(self.parent, **self.vars)
-
- @internalcode
+ return BlockReference(name, self, blocks, index)
+
+ def get(self, key, default=None):
+ """Returns an item from the template context, if it doesn't exist
+ `default` is returned.
+ """
+ try:
+ return self[key]
+ except KeyError:
+ return default
+
+ def resolve(self, key):
+ """Looks up a variable like `__getitem__` or `get` but returns an
+ :class:`Undefined` object with the name of the name looked up.
+ """
+ if self._legacy_resolve_mode:
+ rv = resolve_or_missing(self, key)
+ else:
+ rv = self.resolve_or_missing(key)
+ if rv is missing:
+ return self.environment.undefined(name=key)
+ return rv
+
+ def resolve_or_missing(self, key):
+ """Resolves a variable like :meth:`resolve` but returns the
+ special `missing` value if it cannot be found.
+ """
+ if self._legacy_resolve_mode:
+ rv = self.resolve(key)
+ if isinstance(rv, Undefined):
+ rv = missing
+ return rv
+ return resolve_or_missing(self, key)
+
+ def get_exported(self):
+ """Get a new dict with the exported variables."""
+ return dict((k, self.vars[k]) for k in self.exported_vars)
+
+ def get_all(self):
+ """Return the complete context as dict including the exported
+ variables. For optimizations reasons this might not return an
+ actual copy so be careful with using it.
+ """
+ if not self.vars:
+ return self.parent
+ if not self.parent:
+ return self.vars
+ return dict(self.parent, **self.vars)
+
+ @internalcode
def call(__self, __obj, *args, **kwargs): # noqa: B902
- """Call the callable with the arguments and keyword arguments
- provided but inject the active context or environment as first
- argument if the callable is a :func:`contextfunction` or
- :func:`environmentfunction`.
- """
- if __debug__:
- __traceback_hide__ = True # noqa
-
- # Allow callable classes to take a context
+ """Call the callable with the arguments and keyword arguments
+ provided but inject the active context or environment as first
+ argument if the callable is a :func:`contextfunction` or
+ :func:`environmentfunction`.
+ """
+ if __debug__:
+ __traceback_hide__ = True # noqa
+
+ # Allow callable classes to take a context
if hasattr(__obj, "__call__"): # noqa: B004
- fn = __obj.__call__
+ fn = __obj.__call__
for fn_type in (
"contextfunction",
"evalcontextfunction",
"environmentfunction",
):
- if hasattr(fn, fn_type):
- __obj = fn
- break
-
+ if hasattr(fn, fn_type):
+ __obj = fn
+ break
+
if callable(__obj):
if getattr(__obj, "contextfunction", False) is True:
- args = (__self,) + args
+ args = (__self,) + args
elif getattr(__obj, "evalcontextfunction", False) is True:
- args = (__self.eval_ctx,) + args
+ args = (__self.eval_ctx,) + args
elif getattr(__obj, "environmentfunction", False) is True:
- args = (__self.environment,) + args
- try:
- return __obj(*args, **kwargs)
- except StopIteration:
+ args = (__self.environment,) + args
+ try:
+ return __obj(*args, **kwargs)
+ except StopIteration:
return __self.environment.undefined(
"value was undefined because "
"a callable raised a "
"StopIteration exception"
)
-
- def derived(self, locals=None):
- """Internal helper function to create a derived context. This is
- used in situations where the system needs a new context in the same
- template that is independent.
- """
+
+ def derived(self, locals=None):
+ """Internal helper function to create a derived context. This is
+ used in situations where the system needs a new context in the same
+ template that is independent.
+ """
context = new_context(
self.environment, self.name, {}, self.get_all(), True, None, locals
)
- context.eval_ctx = self.eval_ctx
- context.blocks.update((k, list(v)) for k, v in iteritems(self.blocks))
- return context
-
+ context.eval_ctx = self.eval_ctx
+ context.blocks.update((k, list(v)) for k, v in iteritems(self.blocks))
+ return context
+
def _all(meth): # noqa: B902
def proxy(self):
return getattr(self.get_all(), meth)()
- proxy.__doc__ = getattr(dict, meth).__doc__
- proxy.__name__ = meth
- return proxy
-
+ proxy.__doc__ = getattr(dict, meth).__doc__
+ proxy.__name__ = meth
+ return proxy
+
keys = _all("keys")
values = _all("values")
items = _all("items")
-
- # not available on python 3
- if PY2:
+
+ # not available on python 3
+ if PY2:
iterkeys = _all("iterkeys")
itervalues = _all("itervalues")
iteritems = _all("iteritems")
- del _all
-
- def __contains__(self, name):
- return name in self.vars or name in self.parent
-
- def __getitem__(self, key):
- """Lookup a variable or raise `KeyError` if the variable is
- undefined.
- """
- item = self.resolve_or_missing(key)
- if item is missing:
- raise KeyError(key)
- return item
-
- def __repr__(self):
+ del _all
+
+ def __contains__(self, name):
+ return name in self.vars or name in self.parent
+
+ def __getitem__(self, key):
+ """Lookup a variable or raise `KeyError` if the variable is
+ undefined.
+ """
+ item = self.resolve_or_missing(key)
+ if item is missing:
+ raise KeyError(key)
+ return item
+
+ def __repr__(self):
return "<%s %s of %r>" % (
- self.__class__.__name__,
- repr(self.get_all()),
+ self.__class__.__name__,
+ repr(self.get_all()),
self.name,
- )
-
-
+ )
+
+
abc.Mapping.register(Context)
-
-
-class BlockReference(object):
- """One block on a template reference."""
-
- def __init__(self, name, context, stack, depth):
- self.name = name
- self._context = context
- self._stack = stack
- self._depth = depth
-
- @property
- def super(self):
- """Super the block."""
- if self._depth + 1 >= len(self._stack):
+
+
+class BlockReference(object):
+ """One block on a template reference."""
+
+ def __init__(self, name, context, stack, depth):
+ self.name = name
+ self._context = context
+ self._stack = stack
+ self._depth = depth
+
+ @property
+ def super(self):
+ """Super the block."""
+ if self._depth + 1 >= len(self._stack):
return self._context.environment.undefined(
"there is no parent block called %r." % self.name, name="super"
)
return BlockReference(self.name, self._context, self._stack, self._depth + 1)
-
- @internalcode
- def __call__(self):
- rv = concat(self._stack[self._depth](self._context))
- if self._context.eval_ctx.autoescape:
- rv = Markup(rv)
- return rv
-
-
+
+ @internalcode
+ def __call__(self):
+ rv = concat(self._stack[self._depth](self._context))
+ if self._context.eval_ctx.autoescape:
+ rv = Markup(rv)
+ return rv
+
+
@implements_iterator
class LoopContext:
"""A wrapper iterable for dynamic ``for`` loops, with information
about the loop and iteration.
"""
-
+
#: Current iteration of the loop, starting at 0.
index0 = -1
- _length = None
+ _length = None
_after = missing
_current = missing
_before = missing
_last_changed_value = missing
-
+
def __init__(self, iterable, undefined, recurse=None, depth0=0):
"""
:param iterable: Iterable to wrap.
@@ -401,68 +401,68 @@ class LoopContext:
"""
self._iterable = iterable
self._iterator = self._to_iterator(iterable)
- self._undefined = undefined
- self._recurse = recurse
+ self._undefined = undefined
+ self._recurse = recurse
#: How many levels deep a recursive loop currently is, starting at 0.
- self.depth0 = depth0
-
+ self.depth0 = depth0
+
@staticmethod
def _to_iterator(iterable):
return iter(iterable)
-
+
@property
def length(self):
"""Length of the iterable.
-
+
If the iterable is a generator or otherwise does not have a
size, it is eagerly evaluated to get a size.
"""
if self._length is not None:
return self._length
-
+
try:
self._length = len(self._iterable)
except TypeError:
iterable = list(self._iterator)
self._iterator = self._to_iterator(iterable)
self._length = len(iterable) + self.index + (self._after is not missing)
-
+
return self._length
-
- def __len__(self):
- return self.length
-
+
+ def __len__(self):
+ return self.length
+
@property
def depth(self):
"""How many levels deep a recursive loop currently is, starting at 1."""
return self.depth0 + 1
-
+
@property
def index(self):
"""Current iteration of the loop, starting at 1."""
return self.index0 + 1
-
+
@property
def revindex0(self):
"""Number of iterations from the end of the loop, ending at 0.
-
+
Requires calculating :attr:`length`.
"""
return self.length - self.index
-
+
@property
def revindex(self):
"""Number of iterations from the end of the loop, ending at 1.
-
+
Requires calculating :attr:`length`.
"""
return self.length - self.index0
-
+
@property
def first(self):
"""Whether this is the first iteration of the loop."""
return self.index0 == 0
-
+
def _peek_next(self):
"""Return the next element in the iterable, or :data:`missing`
if the iterable is exhausted. Only peeks one item ahead, caching
@@ -475,16 +475,16 @@ class LoopContext:
self._after = next(self._iterator, missing)
return self._after
- @property
+ @property
def last(self):
"""Whether this is the last iteration of the loop.
-
+
Causes the iterable to advance early. See
:func:`itertools.groupby` for issues this can cause.
The :func:`groupby` filter avoids that issue.
"""
return self._peek_next() is missing
-
+
@property
def previtem(self):
"""The item in the previous iteration. Undefined during the
@@ -492,20 +492,20 @@ class LoopContext:
"""
if self.first:
return self._undefined("there is no previous item")
-
+
return self._before
-
+
@property
def nextitem(self):
"""The item in the next iteration. Undefined during the last
iteration.
-
+
Causes the iterable to advance early. See
:func:`itertools.groupby` for issues this can cause.
The :func:`groupby` filter avoids that issue.
"""
rv = self._peek_next()
-
+
if rv is missing:
return self._undefined("there is no next item")
@@ -534,21 +534,21 @@ class LoopContext:
return False
- def __iter__(self):
- return self
-
- def __next__(self):
+ def __iter__(self):
+ return self
+
+ def __next__(self):
if self._after is not missing:
rv = self._after
self._after = missing
else:
rv = next(self._iterator)
-
+
self.index0 += 1
self._before = self._current
self._current = rv
return rv, self
-
+
@internalcode
def __call__(self, iterable):
"""When iterating over nested data, render the body of the loop
@@ -567,9 +567,9 @@ class LoopContext:
return "<%s %d/%d>" % (self.__class__.__name__, self.index, self.length)
-class Macro(object):
- """Wraps a macro function."""
-
+class Macro(object):
+ """Wraps a macro function."""
+
def __init__(
self,
environment,
@@ -581,79 +581,79 @@ class Macro(object):
caller,
default_autoescape=None,
):
- self._environment = environment
- self._func = func
- self._argument_count = len(arguments)
- self.name = name
- self.arguments = arguments
- self.catch_kwargs = catch_kwargs
- self.catch_varargs = catch_varargs
- self.caller = caller
+ self._environment = environment
+ self._func = func
+ self._argument_count = len(arguments)
+ self.name = name
+ self.arguments = arguments
+ self.catch_kwargs = catch_kwargs
+ self.catch_varargs = catch_varargs
+ self.caller = caller
self.explicit_caller = "caller" in arguments
- if default_autoescape is None:
- default_autoescape = environment.autoescape
- self._default_autoescape = default_autoescape
-
- @internalcode
- @evalcontextfunction
- def __call__(self, *args, **kwargs):
- # This requires a bit of explanation, In the past we used to
- # decide largely based on compile-time information if a macro is
- # safe or unsafe. While there was a volatile mode it was largely
- # unused for deciding on escaping. This turns out to be
+ if default_autoescape is None:
+ default_autoescape = environment.autoescape
+ self._default_autoescape = default_autoescape
+
+ @internalcode
+ @evalcontextfunction
+ def __call__(self, *args, **kwargs):
+ # This requires a bit of explanation, In the past we used to
+ # decide largely based on compile-time information if a macro is
+ # safe or unsafe. While there was a volatile mode it was largely
+ # unused for deciding on escaping. This turns out to be
# problematic for macros because whether a macro is safe depends not
# on the escape mode when it was defined, but rather when it was used.
- #
- # Because however we export macros from the module system and
- # there are historic callers that do not pass an eval context (and
- # will continue to not pass one), we need to perform an instance
- # check here.
- #
- # This is considered safe because an eval context is not a valid
+ #
+ # Because however we export macros from the module system and
+ # there are historic callers that do not pass an eval context (and
+ # will continue to not pass one), we need to perform an instance
+ # check here.
+ #
+ # This is considered safe because an eval context is not a valid
# argument to callables otherwise anyway. Worst case here is
- # that if no eval context is passed we fall back to the compile
- # time autoescape flag.
- if args and isinstance(args[0], EvalContext):
- autoescape = args[0].autoescape
- args = args[1:]
- else:
- autoescape = self._default_autoescape
-
- # try to consume the positional arguments
+ # that if no eval context is passed we fall back to the compile
+ # time autoescape flag.
+ if args and isinstance(args[0], EvalContext):
+ autoescape = args[0].autoescape
+ args = args[1:]
+ else:
+ autoescape = self._default_autoescape
+
+ # try to consume the positional arguments
arguments = list(args[: self._argument_count])
- off = len(arguments)
-
- # For information why this is necessary refer to the handling
- # of caller in the `macro_body` handler in the compiler.
- found_caller = False
-
- # if the number of arguments consumed is not the number of
- # arguments expected we start filling in keyword arguments
- # and defaults.
- if off != self._argument_count:
+ off = len(arguments)
+
+ # For information why this is necessary refer to the handling
+ # of caller in the `macro_body` handler in the compiler.
+ found_caller = False
+
+ # if the number of arguments consumed is not the number of
+ # arguments expected we start filling in keyword arguments
+ # and defaults.
+ if off != self._argument_count:
for name in self.arguments[len(arguments) :]:
- try:
- value = kwargs.pop(name)
- except KeyError:
- value = missing
+ try:
+ value = kwargs.pop(name)
+ except KeyError:
+ value = missing
if name == "caller":
- found_caller = True
- arguments.append(value)
- else:
- found_caller = self.explicit_caller
-
- # it's important that the order of these arguments does not change
- # if not also changed in the compiler's `function_scoping` method.
- # the order is caller, keyword arguments, positional arguments!
- if self.caller and not found_caller:
+ found_caller = True
+ arguments.append(value)
+ else:
+ found_caller = self.explicit_caller
+
+ # it's important that the order of these arguments does not change
+ # if not also changed in the compiler's `function_scoping` method.
+ # the order is caller, keyword arguments, positional arguments!
+ if self.caller and not found_caller:
caller = kwargs.pop("caller", None)
- if caller is None:
+ if caller is None:
caller = self._environment.undefined("No caller defined", name="caller")
- arguments.append(caller)
-
- if self.catch_kwargs:
- arguments.append(kwargs)
- elif kwargs:
+ arguments.append(caller)
+
+ if self.catch_kwargs:
+ arguments.append(kwargs)
+ elif kwargs:
if "caller" in kwargs:
raise TypeError(
"macro %r was invoked with two values for "
@@ -664,46 +664,46 @@ class Macro(object):
"macro %r takes no keyword argument %r"
% (self.name, next(iter(kwargs)))
)
- if self.catch_varargs:
+ if self.catch_varargs:
arguments.append(args[self._argument_count :])
- elif len(args) > self._argument_count:
+ elif len(args) > self._argument_count:
raise TypeError(
"macro %r takes not more than %d argument(s)"
% (self.name, len(self.arguments))
)
-
- return self._invoke(arguments, autoescape)
-
- def _invoke(self, arguments, autoescape):
- """This method is being swapped out by the async implementation."""
- rv = self._func(*arguments)
- if autoescape:
- rv = Markup(rv)
- return rv
-
- def __repr__(self):
+
+ return self._invoke(arguments, autoescape)
+
+ def _invoke(self, arguments, autoescape):
+ """This method is being swapped out by the async implementation."""
+ rv = self._func(*arguments)
+ if autoescape:
+ rv = Markup(rv)
+ return rv
+
+ def __repr__(self):
return "<%s %s>" % (
- self.__class__.__name__,
+ self.__class__.__name__,
self.name is None and "anonymous" or repr(self.name),
- )
-
-
-@implements_to_string
-class Undefined(object):
- """The default undefined type. This undefined type can be printed and
+ )
+
+
+@implements_to_string
+class Undefined(object):
+ """The default undefined type. This undefined type can be printed and
iterated over, but every other access will raise an :exc:`UndefinedError`:
-
- >>> foo = Undefined(name='foo')
- >>> str(foo)
- ''
- >>> not foo
- True
- >>> foo + 42
- Traceback (most recent call last):
- ...
- jinja2.exceptions.UndefinedError: 'foo' is undefined
- """
-
+
+ >>> foo = Undefined(name='foo')
+ >>> str(foo)
+ ''
+ >>> not foo
+ True
+ >>> foo + 42
+ Traceback (most recent call last):
+ ...
+ jinja2.exceptions.UndefinedError: 'foo' is undefined
+ """
+
__slots__ = (
"_undefined_hint",
"_undefined_obj",
@@ -711,12 +711,12 @@ class Undefined(object):
"_undefined_exception",
)
- def __init__(self, hint=None, obj=missing, name=None, exc=UndefinedError):
- self._undefined_hint = hint
- self._undefined_obj = obj
- self._undefined_name = name
- self._undefined_exception = exc
-
+ def __init__(self, hint=None, obj=missing, name=None, exc=UndefinedError):
+ self._undefined_hint = hint
+ self._undefined_obj = obj
+ self._undefined_name = name
+ self._undefined_exception = exc
+
@property
def _undefined_message(self):
"""Build a message about the undefined value based on how it was
@@ -739,19 +739,19 @@ class Undefined(object):
self._undefined_name,
)
- @internalcode
- def _fail_with_undefined_error(self, *args, **kwargs):
+ @internalcode
+ def _fail_with_undefined_error(self, *args, **kwargs):
"""Raise an :exc:`UndefinedError` when operations are performed
on the undefined value.
- """
+ """
raise self._undefined_exception(self._undefined_message)
-
- @internalcode
- def __getattr__(self, name):
+
+ @internalcode
+ def __getattr__(self, name):
if name[:2] == "__":
- raise AttributeError(name)
- return self._fail_with_undefined_error()
-
+ raise AttributeError(name)
+ return self._fail_with_undefined_error()
+
__add__ = (
__radd__
) = (
@@ -797,121 +797,121 @@ class Undefined(object):
) = (
__complex__
) = __pow__ = __rpow__ = __sub__ = __rsub__ = _fail_with_undefined_error
-
- def __eq__(self, other):
- return type(self) is type(other)
-
- def __ne__(self, other):
- return not self.__eq__(other)
-
- def __hash__(self):
- return id(type(self))
-
- def __str__(self):
+
+ def __eq__(self, other):
+ return type(self) is type(other)
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
+ def __hash__(self):
+ return id(type(self))
+
+ def __str__(self):
return u""
-
- def __len__(self):
- return 0
-
- def __iter__(self):
- if 0:
- yield None
-
- def __nonzero__(self):
- return False
-
- __bool__ = __nonzero__
-
- def __repr__(self):
+
+ def __len__(self):
+ return 0
+
+ def __iter__(self):
+ if 0:
+ yield None
+
+ def __nonzero__(self):
+ return False
+
+ __bool__ = __nonzero__
+
+ def __repr__(self):
return "Undefined"
-
-
-def make_logging_undefined(logger=None, base=None):
- """Given a logger object this returns a new undefined class that will
- log certain failures. It will log iterations and printing. If no
- logger is given a default logger is created.
-
- Example::
-
- logger = logging.getLogger(__name__)
- LoggingUndefined = make_logging_undefined(
- logger=logger,
- base=Undefined
- )
-
- .. versionadded:: 2.8
-
- :param logger: the logger to use. If not provided, a default logger
- is created.
- :param base: the base class to add logging functionality to. This
- defaults to :class:`Undefined`.
- """
- if logger is None:
- import logging
-
- logger = logging.getLogger(__name__)
- logger.addHandler(logging.StreamHandler(sys.stderr))
- if base is None:
- base = Undefined
-
- def _log_message(undef):
- if undef._undefined_hint is None:
- if undef._undefined_obj is missing:
+
+
+def make_logging_undefined(logger=None, base=None):
+ """Given a logger object this returns a new undefined class that will
+ log certain failures. It will log iterations and printing. If no
+ logger is given a default logger is created.
+
+ Example::
+
+ logger = logging.getLogger(__name__)
+ LoggingUndefined = make_logging_undefined(
+ logger=logger,
+ base=Undefined
+ )
+
+ .. versionadded:: 2.8
+
+ :param logger: the logger to use. If not provided, a default logger
+ is created.
+ :param base: the base class to add logging functionality to. This
+ defaults to :class:`Undefined`.
+ """
+ if logger is None:
+ import logging
+
+ logger = logging.getLogger(__name__)
+ logger.addHandler(logging.StreamHandler(sys.stderr))
+ if base is None:
+ base = Undefined
+
+ def _log_message(undef):
+ if undef._undefined_hint is None:
+ if undef._undefined_obj is missing:
hint = "%s is undefined" % undef._undefined_name
- elif not isinstance(undef._undefined_name, string_types):
+ elif not isinstance(undef._undefined_name, string_types):
hint = "%s has no element %s" % (
- object_type_repr(undef._undefined_obj),
+ object_type_repr(undef._undefined_obj),
undef._undefined_name,
)
- else:
+ else:
hint = "%s has no attribute %s" % (
- object_type_repr(undef._undefined_obj),
+ object_type_repr(undef._undefined_obj),
undef._undefined_name,
)
- else:
- hint = undef._undefined_hint
+ else:
+ hint = undef._undefined_hint
logger.warning("Template variable warning: %s", hint)
-
- class LoggingUndefined(base):
- def _fail_with_undefined_error(self, *args, **kwargs):
- try:
- return base._fail_with_undefined_error(self, *args, **kwargs)
- except self._undefined_exception as e:
+
+ class LoggingUndefined(base):
+ def _fail_with_undefined_error(self, *args, **kwargs):
+ try:
+ return base._fail_with_undefined_error(self, *args, **kwargs)
+ except self._undefined_exception as e:
logger.error("Template variable error: %s", str(e))
- raise e
-
- def __str__(self):
- rv = base.__str__(self)
- _log_message(self)
- return rv
-
- def __iter__(self):
- rv = base.__iter__(self)
- _log_message(self)
- return rv
-
- if PY2:
-
- def __nonzero__(self):
- rv = base.__nonzero__(self)
- _log_message(self)
- return rv
-
- def __unicode__(self):
- rv = base.__unicode__(self)
- _log_message(self)
- return rv
-
- else:
-
- def __bool__(self):
- rv = base.__bool__(self)
- _log_message(self)
- return rv
-
- return LoggingUndefined
-
-
+ raise e
+
+ def __str__(self):
+ rv = base.__str__(self)
+ _log_message(self)
+ return rv
+
+ def __iter__(self):
+ rv = base.__iter__(self)
+ _log_message(self)
+ return rv
+
+ if PY2:
+
+ def __nonzero__(self):
+ rv = base.__nonzero__(self)
+ _log_message(self)
+ return rv
+
+ def __unicode__(self):
+ rv = base.__unicode__(self)
+ _log_message(self)
+ return rv
+
+ else:
+
+ def __bool__(self):
+ rv = base.__bool__(self)
+ _log_message(self)
+ return rv
+
+ return LoggingUndefined
+
+
# No @implements_to_string decorator here because __str__
# is not overwritten from Undefined in this class.
# This would cause a recursion error in Python 2.
@@ -942,56 +942,56 @@ class ChainableUndefined(Undefined):
__getitem__ = __getattr__
-@implements_to_string
-class DebugUndefined(Undefined):
- """An undefined that returns the debug info when printed.
-
- >>> foo = DebugUndefined(name='foo')
- >>> str(foo)
- '{{ foo }}'
- >>> not foo
- True
- >>> foo + 42
- Traceback (most recent call last):
- ...
- jinja2.exceptions.UndefinedError: 'foo' is undefined
- """
-
- __slots__ = ()
-
- def __str__(self):
- if self._undefined_hint is None:
- if self._undefined_obj is missing:
+@implements_to_string
+class DebugUndefined(Undefined):
+ """An undefined that returns the debug info when printed.
+
+ >>> foo = DebugUndefined(name='foo')
+ >>> str(foo)
+ '{{ foo }}'
+ >>> not foo
+ True
+ >>> foo + 42
+ Traceback (most recent call last):
+ ...
+ jinja2.exceptions.UndefinedError: 'foo' is undefined
+ """
+
+ __slots__ = ()
+
+ def __str__(self):
+ if self._undefined_hint is None:
+ if self._undefined_obj is missing:
return u"{{ %s }}" % self._undefined_name
return "{{ no such element: %s[%r] }}" % (
- object_type_repr(self._undefined_obj),
+ object_type_repr(self._undefined_obj),
self._undefined_name,
- )
+ )
return u"{{ undefined value printed: %s }}" % self._undefined_hint
-
-
-@implements_to_string
-class StrictUndefined(Undefined):
- """An undefined that barks on print and iteration as well as boolean
- tests and all kinds of comparisons. In other words: you can do nothing
- with it except checking if it's defined using the `defined` test.
-
- >>> foo = StrictUndefined(name='foo')
- >>> str(foo)
- Traceback (most recent call last):
- ...
- jinja2.exceptions.UndefinedError: 'foo' is undefined
- >>> not foo
- Traceback (most recent call last):
- ...
- jinja2.exceptions.UndefinedError: 'foo' is undefined
- >>> foo + 42
- Traceback (most recent call last):
- ...
- jinja2.exceptions.UndefinedError: 'foo' is undefined
- """
-
- __slots__ = ()
+
+
+@implements_to_string
+class StrictUndefined(Undefined):
+ """An undefined that barks on print and iteration as well as boolean
+ tests and all kinds of comparisons. In other words: you can do nothing
+ with it except checking if it's defined using the `defined` test.
+
+ >>> foo = StrictUndefined(name='foo')
+ >>> str(foo)
+ Traceback (most recent call last):
+ ...
+ jinja2.exceptions.UndefinedError: 'foo' is undefined
+ >>> not foo
+ Traceback (most recent call last):
+ ...
+ jinja2.exceptions.UndefinedError: 'foo' is undefined
+ >>> foo + 42
+ Traceback (most recent call last):
+ ...
+ jinja2.exceptions.UndefinedError: 'foo' is undefined
+ """
+
+ __slots__ = ()
__iter__ = (
__str__
) = (
@@ -999,10 +999,10 @@ class StrictUndefined(Undefined):
) = (
__nonzero__
) = __eq__ = __ne__ = __bool__ = __hash__ = Undefined._fail_with_undefined_error
-
-
-# remove remaining slots attributes, after the metaclass did the magic they
-# are unneeded and irritating as they contain wrong data for the subclasses.
+
+
+# remove remaining slots attributes, after the metaclass did the magic they
+# are unneeded and irritating as they contain wrong data for the subclasses.
del (
Undefined.__slots__,
ChainableUndefined.__slots__,
diff --git a/contrib/python/Jinja2/py2/jinja2/sandbox.py b/contrib/python/Jinja2/py2/jinja2/sandbox.py
index cfd7993aee..8434d7702f 100644
--- a/contrib/python/Jinja2/py2/jinja2/sandbox.py
+++ b/contrib/python/Jinja2/py2/jinja2/sandbox.py
@@ -1,28 +1,28 @@
-# -*- coding: utf-8 -*-
+# -*- coding: utf-8 -*-
"""A sandbox layer that ensures unsafe operations cannot be performed.
Useful when the template itself comes from an untrusted source.
-"""
+"""
import operator
-import types
+import types
import warnings
from collections import deque
from string import Formatter
-
-from markupsafe import EscapeFormatter
+
+from markupsafe import EscapeFormatter
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:
+
+#: maximum number of items a range may produce
+MAX_RANGE = 100000
+
+#: attributes of function objects that are considered unsafe.
+if PY2:
UNSAFE_FUNCTION_ATTRIBUTES = {
"func_closure",
"func_code",
@@ -30,56 +30,56 @@ if PY2:
"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
+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 = {"im_class", "im_func", "im_self"}
-
+
#: unsafe generator attributes.
UNSAFE_GENERATOR_ATTRIBUTES = {"gi_frame", "gi_code"}
-
-#: unsafe attributes on coroutines
+
+#: unsafe attributes on coroutines
UNSAFE_COROUTINE_ATTRIBUTES = {"cr_frame", "cr_code"}
-
-#: unsafe attributes on async generators
+
+#: unsafe attributes on async generators
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
+
+# 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=__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:
- pass
-
-# 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
-
-#: register Python 2.6 abstract base classes
+
+_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:
+ pass
+
+# 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
+
+#: register Python 2.6 abstract base classes
_mutable_set_types += (abc.MutableSet,)
_mutable_mapping_types += (abc.MutableMapping,)
_mutable_sequence_types += (abc.MutableSequence,)
-
-_mutable_spec = (
+
+_mutable_spec = (
(
_mutable_set_types,
frozenset(
@@ -119,160 +119,160 @@ _mutable_spec = (
]
),
),
-)
-
-
+)
+
+
class _MagicFormatMapping(abc.Mapping):
- """This class implements a dummy wrapper to fix a bug in the Python
- standard library for string formatting.
-
- See https://bugs.python.org/issue13598 for information about why
- this is necessary.
- """
-
- def __init__(self, args, kwargs):
- self._args = args
- self._kwargs = kwargs
- self._last_index = 0
-
- def __getitem__(self, key):
+ """This class implements a dummy wrapper to fix a bug in the Python
+ standard library for string formatting.
+
+ See https://bugs.python.org/issue13598 for information about why
+ this is necessary.
+ """
+
+ def __init__(self, args, kwargs):
+ self._args = args
+ self._kwargs = kwargs
+ self._last_index = 0
+
+ def __getitem__(self, key):
if key == "":
- idx = self._last_index
- self._last_index += 1
- try:
- return self._args[idx]
- except LookupError:
- pass
- key = str(idx)
- return self._kwargs[key]
-
- def __iter__(self):
- return iter(self._kwargs)
-
- def __len__(self):
- return len(self._kwargs)
-
-
-def inspect_format_method(callable):
+ idx = self._last_index
+ self._last_index += 1
+ try:
+ return self._args[idx]
+ except LookupError:
+ pass
+ key = str(idx)
+ return self._kwargs[key]
+
+ def __iter__(self):
+ return iter(self._kwargs)
+
+ def __len__(self):
+ return len(self._kwargs)
+
+
+def inspect_format_method(callable):
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):
- return obj
-
-
-def safe_range(*args):
- """A range that can't generate ranges with a length of more than
- MAX_RANGE items.
- """
+ return None
+ obj = callable.__self__
+ if isinstance(obj, string_types):
+ return obj
+
+
+def safe_range(*args):
+ """A range that can't generate ranges with a length of more than
+ MAX_RANGE items.
+ """
rng = range_type(*args)
- if len(rng) > MAX_RANGE:
+ if len(rng) > MAX_RANGE:
raise OverflowError(
"Range too big. The sandbox blocks ranges larger than"
" MAX_RANGE (%d)." % MAX_RANGE
)
- return rng
-
-
-def unsafe(f):
- """Marks a function or method as unsafe.
-
- ::
-
- @unsafe
- def delete(self):
- pass
- """
- f.unsafe_callable = True
- return f
-
-
-def is_internal_attribute(obj, attr):
- """Test if the attribute given is an internal python attribute. For
- example this function returns `True` for the `func_code` attribute of
- python objects. This is useful if the environment method
- :meth:`~SandboxedEnvironment.is_safe_attribute` is overridden.
-
- >>> from jinja2.sandbox import is_internal_attribute
- >>> is_internal_attribute(str, "mro")
- True
- >>> is_internal_attribute(str, "upper")
- False
- """
- if isinstance(obj, types.FunctionType):
- if attr in UNSAFE_FUNCTION_ATTRIBUTES:
- return True
- elif isinstance(obj, types.MethodType):
+ return rng
+
+
+def unsafe(f):
+ """Marks a function or method as unsafe.
+
+ ::
+
+ @unsafe
+ def delete(self):
+ pass
+ """
+ f.unsafe_callable = True
+ return f
+
+
+def is_internal_attribute(obj, attr):
+ """Test if the attribute given is an internal python attribute. For
+ example this function returns `True` for the `func_code` attribute of
+ python objects. This is useful if the environment method
+ :meth:`~SandboxedEnvironment.is_safe_attribute` is overridden.
+
+ >>> from jinja2.sandbox import is_internal_attribute
+ >>> is_internal_attribute(str, "mro")
+ True
+ >>> is_internal_attribute(str, "upper")
+ False
+ """
+ if isinstance(obj, types.FunctionType):
+ 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:
- return True
- elif isinstance(obj, type):
+ return True
+ elif isinstance(obj, type):
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
+ 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):
- if attr in UNSAFE_COROUTINE_ATTRIBUTES:
- return True
+ if attr in UNSAFE_COROUTINE_ATTRIBUTES:
+ return True
elif hasattr(types, "AsyncGeneratorType") and isinstance(
obj, types.AsyncGeneratorType
):
- if attr in UNSAFE_ASYNC_GENERATOR_ATTRIBUTES:
- return True
+ if attr in UNSAFE_ASYNC_GENERATOR_ATTRIBUTES:
+ return True
return attr.startswith("__")
-
-
-def modifies_known_mutable(obj, attr):
- """This function checks if an attribute on a builtin mutable object
- (list, dict, set or deque) would modify it if called. It also supports
- the "user"-versions of the objects (`sets.Set`, `UserDict.*` etc.) and
- with Python 2.6 onwards the abstract base classes `MutableSet`,
- `MutableMapping`, and `MutableSequence`.
-
- >>> modifies_known_mutable({}, "clear")
- True
- >>> modifies_known_mutable({}, "keys")
- False
- >>> modifies_known_mutable([], "append")
- True
- >>> modifies_known_mutable([], "index")
- False
-
- If called with an unsupported object (such as unicode) `False` is
- returned.
-
- >>> modifies_known_mutable("foo", "upper")
- False
- """
- for typespec, unsafe in _mutable_spec:
- if isinstance(obj, typespec):
- return attr in unsafe
- return False
-
-
-class SandboxedEnvironment(Environment):
- """The sandboxed environment. It works like the regular environment but
- tells the compiler to generate sandboxed code. Additionally subclasses of
- this environment may override the methods that tell the runtime what
- attributes or functions are safe to access.
-
- If the template tries to access insecure code a :exc:`SecurityError` is
- 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 = {
+
+
+def modifies_known_mutable(obj, attr):
+ """This function checks if an attribute on a builtin mutable object
+ (list, dict, set or deque) would modify it if called. It also supports
+ the "user"-versions of the objects (`sets.Set`, `UserDict.*` etc.) and
+ with Python 2.6 onwards the abstract base classes `MutableSet`,
+ `MutableMapping`, and `MutableSequence`.
+
+ >>> modifies_known_mutable({}, "clear")
+ True
+ >>> modifies_known_mutable({}, "keys")
+ False
+ >>> modifies_known_mutable([], "append")
+ True
+ >>> modifies_known_mutable([], "index")
+ False
+
+ If called with an unsupported object (such as unicode) `False` is
+ returned.
+
+ >>> modifies_known_mutable("foo", "upper")
+ False
+ """
+ for typespec, unsafe in _mutable_spec:
+ if isinstance(obj, typespec):
+ return attr in unsafe
+ return False
+
+
+class SandboxedEnvironment(Environment):
+ """The sandboxed environment. It works like the regular environment but
+ tells the compiler to generate sandboxed code. Additionally subclasses of
+ this environment may override the methods that tell the runtime what
+ attributes or functions are safe to access.
+
+ If the template tries to access insecure code a :exc:`SecurityError` is
+ 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,
@@ -280,144 +280,144 @@ class SandboxedEnvironment(Environment):
"//": 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 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}
-
- #: a set of binary operators that should be intercepted. Each operator
- #: that is added to this set (empty by default) is delegated to the
- #: :meth:`call_binop` method that will perform the operator. The default
- #: operator callback is specified by :attr:`binop_table`.
- #:
- #: The following binary operators are interceptable:
- #: ``//``, ``%``, ``+``, ``*``, ``-``, ``/``, and ``**``
- #:
- #: The default operation form the operator table corresponds to the
- #: builtin function. Intercepted calls are always slower than the native
- #: operator call, so make sure only to intercept the ones you are
- #: interested in.
- #:
- #: .. versionadded:: 2.6
- intercepted_binops = frozenset()
-
- #: a set of unary operators that should be intercepted. Each operator
- #: that is added to this set (empty by default) is delegated to the
- #: :meth:`call_unop` method that will perform the operator. The default
- #: operator callback is specified by :attr:`unop_table`.
- #:
- #: The following unary operators are interceptable: ``+``, ``-``
- #:
- #: The default operation form the operator table corresponds to the
- #: builtin function. Intercepted calls are always slower than the native
- #: operator call, so make sure only to intercept the ones you are
- #: interested in.
- #:
- #: .. versionadded:: 2.6
- intercepted_unops = frozenset()
-
- 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
+
+ #: a set of binary operators that should be intercepted. Each operator
+ #: that is added to this set (empty by default) is delegated to the
+ #: :meth:`call_binop` method that will perform the operator. The default
+ #: operator callback is specified by :attr:`binop_table`.
+ #:
+ #: The following binary operators are interceptable:
+ #: ``//``, ``%``, ``+``, ``*``, ``-``, ``/``, and ``**``
+ #:
+ #: The default operation form the operator table corresponds to the
+ #: builtin function. Intercepted calls are always slower than the native
+ #: operator call, so make sure only to intercept the ones you are
+ #: interested in.
+ #:
+ #: .. versionadded:: 2.6
+ intercepted_binops = frozenset()
+
+ #: a set of unary operators that should be intercepted. Each operator
+ #: that is added to this set (empty by default) is delegated to the
+ #: :meth:`call_unop` method that will perform the operator. The default
+ #: operator callback is specified by :attr:`unop_table`.
+ #:
+ #: The following unary operators are interceptable: ``+``, ``-``
+ #:
+ #: The default operation form the operator table corresponds to the
+ #: builtin function. Intercepted calls are always slower than the native
+ #: operator call, so make sure only to intercept the ones you are
+ #: interested in.
+ #:
+ #: .. versionadded:: 2.6
+ intercepted_unops = frozenset()
+
+ 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 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.
-
- The following unary operators are interceptable: ``+`` and ``-``
-
- Intercepted calls are always slower than the native operator call,
- so make sure only to intercept the ones you are interested in.
-
- .. versionadded:: 2.6
- """
- return False
-
- def __init__(self, *args, **kwargs):
- Environment.__init__(self, *args, **kwargs)
+ 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.
+
+ The following unary operators are interceptable: ``+`` and ``-``
+
+ Intercepted calls are always slower than the native operator call,
+ so make sure only to intercept the ones you are interested in.
+
+ .. versionadded:: 2.6
+ """
+ return False
+
+ def __init__(self, *args, **kwargs):
+ Environment.__init__(self, *args, **kwargs)
self.globals["range"] = safe_range
- self.binop_table = self.default_binop_table.copy()
- self.unop_table = self.default_unop_table.copy()
-
- def is_safe_attribute(self, obj, attr, value):
- """The sandboxed environment will call this method to check if the
- attribute of an object is safe to access. Per default all attributes
- starting with an underscore are considered private as well as the
- special attributes of internal python objects as returned by the
- :func:`is_internal_attribute` function.
- """
+ self.binop_table = self.default_binop_table.copy()
+ self.unop_table = self.default_unop_table.copy()
+
+ def is_safe_attribute(self, obj, attr, value):
+ """The sandboxed environment will call this method to check if the
+ attribute of an object is safe to access. Per default all attributes
+ starting with an underscore are considered private as well as the
+ 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))
-
- 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.
- """
+
+ 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)
)
-
- def call_binop(self, context, operator, left, right):
- """For intercepted binary operator calls (:meth:`intercepted_binops`)
- this function is executed instead of the builtin operator. This can
- be used to fine tune the behavior of certain operators.
-
- .. versionadded:: 2.6
- """
- return self.binop_table[operator](left, right)
-
- def call_unop(self, context, operator, arg):
- """For intercepted unary operator calls (:meth:`intercepted_unops`)
- this function is executed instead of the builtin operator. This can
- be used to fine tune the behavior of certain operators.
-
- .. versionadded:: 2.6
- """
- return self.unop_table[operator](arg)
-
- def getitem(self, obj, argument):
- """Subscribe an object from sandboxed code."""
- try:
- return obj[argument]
- except (TypeError, LookupError):
- if isinstance(argument, string_types):
- try:
- attr = str(argument)
- except Exception:
- pass
- else:
- try:
- value = getattr(obj, attr)
- except AttributeError:
- pass
- else:
- if self.is_safe_attribute(obj, argument, value):
- return value
- return self.unsafe_undefined(obj, argument)
- return self.undefined(obj=obj, name=argument)
-
- def getattr(self, obj, attribute):
- """Subscribe an object from sandboxed code and prefer the
- attribute. The attribute passed *must* be a bytestring.
- """
- try:
- value = getattr(obj, attribute)
- except AttributeError:
- try:
- return obj[attribute]
- except (TypeError, LookupError):
- pass
- else:
- if self.is_safe_attribute(obj, attribute, value):
- return value
- return self.unsafe_undefined(obj, attribute)
- return self.undefined(obj=obj, name=attribute)
-
- def unsafe_undefined(self, obj, attribute):
- """Return an undefined object for unsafe attributes."""
+
+ def call_binop(self, context, operator, left, right):
+ """For intercepted binary operator calls (:meth:`intercepted_binops`)
+ this function is executed instead of the builtin operator. This can
+ be used to fine tune the behavior of certain operators.
+
+ .. versionadded:: 2.6
+ """
+ return self.binop_table[operator](left, right)
+
+ def call_unop(self, context, operator, arg):
+ """For intercepted unary operator calls (:meth:`intercepted_unops`)
+ this function is executed instead of the builtin operator. This can
+ be used to fine tune the behavior of certain operators.
+
+ .. versionadded:: 2.6
+ """
+ return self.unop_table[operator](arg)
+
+ def getitem(self, obj, argument):
+ """Subscribe an object from sandboxed code."""
+ try:
+ return obj[argument]
+ except (TypeError, LookupError):
+ if isinstance(argument, string_types):
+ try:
+ attr = str(argument)
+ except Exception:
+ pass
+ else:
+ try:
+ value = getattr(obj, attr)
+ except AttributeError:
+ pass
+ else:
+ if self.is_safe_attribute(obj, argument, value):
+ return value
+ return self.unsafe_undefined(obj, argument)
+ return self.undefined(obj=obj, name=argument)
+
+ def getattr(self, obj, attribute):
+ """Subscribe an object from sandboxed code and prefer the
+ attribute. The attribute passed *must* be a bytestring.
+ """
+ try:
+ value = getattr(obj, attribute)
+ except AttributeError:
+ try:
+ return obj[attribute]
+ except (TypeError, LookupError):
+ pass
+ else:
+ if self.is_safe_attribute(obj, attribute, value):
+ return value
+ return self.unsafe_undefined(obj, attribute)
+ return self.undefined(obj=obj, name=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__),
@@ -425,15 +425,15 @@ class SandboxedEnvironment(Environment):
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
- method so that our safety sandbox can be used for it.
- """
- if isinstance(s, Markup):
- formatter = SandboxedEscapeFormatter(self, s.escape)
- else:
- formatter = SandboxedFormatter(self)
+ """If a format call is detected, then this is routed through this
+ method so that our safety sandbox can be used for it.
+ """
+ if isinstance(s, Markup):
+ formatter = SandboxedEscapeFormatter(self, s.escape)
+ else:
+ formatter = SandboxedFormatter(self)
if format_func is not None and format_func.__name__ == "format_map":
if len(args) != 1 or kwargs:
@@ -445,66 +445,66 @@ class SandboxedEnvironment(Environment):
kwargs = args[0]
args = None
- kwargs = _MagicFormatMapping(args, kwargs)
- rv = formatter.vformat(s, args, kwargs)
- return type(s)(rv)
-
+ kwargs = _MagicFormatMapping(args, kwargs)
+ rv = formatter.vformat(s, args, kwargs)
+ return type(s)(rv)
+
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:
+ """Call an object from sandboxed code."""
+ fmt = inspect_format_method(__obj)
+ if fmt is not None:
return __self.format_string(fmt, args, kwargs, __obj)
-
- # the double prefixes are to avoid double keyword argument
- # errors when proxying the call.
- if not __self.is_safe_callable(__obj):
+
+ # 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,))
- return __context.call(__obj, *args, **kwargs)
-
-
-class ImmutableSandboxedEnvironment(SandboxedEnvironment):
- """Works exactly like the regular `SandboxedEnvironment` but does not
- permit modifications on the builtin mutable objects `list`, `set`, and
- `dict` by using the :func:`modifies_known_mutable` function.
- """
-
- def is_safe_attribute(self, obj, attr, value):
- if not SandboxedEnvironment.is_safe_attribute(self, obj, attr, value):
- return False
- return not modifies_known_mutable(obj, attr)
-
-
+ return __context.call(__obj, *args, **kwargs)
+
+
+class ImmutableSandboxedEnvironment(SandboxedEnvironment):
+ """Works exactly like the regular `SandboxedEnvironment` but does not
+ permit modifications on the builtin mutable objects `list`, `set`, and
+ `dict` by using the :func:`modifies_known_mutable` function.
+ """
+
+ def is_safe_attribute(self, obj, attr, value):
+ if not SandboxedEnvironment.is_safe_attribute(self, obj, attr, value):
+ return False
+ return not modifies_known_mutable(obj, attr)
+
+
# This really is not a public API apparently.
-try:
- from _string import formatter_field_name_split
-except ImportError:
-
- def formatter_field_name_split(field_name):
- return field_name._formatter_field_name_split()
-
-
-class SandboxedFormatterMixin(object):
- def __init__(self, env):
- self._env = env
-
- def get_field(self, field_name, args, kwargs):
- first, rest = formatter_field_name_split(field_name)
- obj = self.get_value(first, args, kwargs)
- for is_attr, i in rest:
- if is_attr:
- obj = self._env.getattr(obj, i)
- else:
- obj = self._env.getitem(obj, i)
- return obj, first
-
-
-class SandboxedFormatter(SandboxedFormatterMixin, Formatter):
- def __init__(self, env):
- SandboxedFormatterMixin.__init__(self, env)
- Formatter.__init__(self)
-
-
-class SandboxedEscapeFormatter(SandboxedFormatterMixin, EscapeFormatter):
- def __init__(self, env, escape):
- SandboxedFormatterMixin.__init__(self, env)
- EscapeFormatter.__init__(self, escape)
+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
+
+ def get_field(self, field_name, args, kwargs):
+ first, rest = formatter_field_name_split(field_name)
+ obj = self.get_value(first, args, kwargs)
+ for is_attr, i in rest:
+ if is_attr:
+ obj = self._env.getattr(obj, i)
+ else:
+ obj = self._env.getitem(obj, i)
+ return obj, first
+
+
+class SandboxedFormatter(SandboxedFormatterMixin, Formatter):
+ def __init__(self, env):
+ SandboxedFormatterMixin.__init__(self, env)
+ Formatter.__init__(self)
+
+
+class SandboxedEscapeFormatter(SandboxedFormatterMixin, EscapeFormatter):
+ def __init__(self, env, escape):
+ SandboxedFormatterMixin.__init__(self, env)
+ EscapeFormatter.__init__(self, escape)
diff --git a/contrib/python/Jinja2/py2/jinja2/tests.py b/contrib/python/Jinja2/py2/jinja2/tests.py
index fabd4ce51b..b4722ad1bb 100644
--- a/contrib/python/Jinja2/py2/jinja2/tests.py
+++ b/contrib/python/Jinja2/py2/jinja2/tests.py
@@ -1,9 +1,9 @@
-# -*- coding: utf-8 -*-
+# -*- coding: utf-8 -*-
"""Built-in template tests used with the ``is`` operator."""
import decimal
-import operator
-import re
-
+import operator
+import re
+
from ._compat import abc
from ._compat import integer_types
from ._compat import string_types
@@ -11,52 +11,52 @@ from ._compat import text_type
from .runtime import Undefined
number_re = re.compile(r"^-?\d+(\.\d+)?$")
-regex_type = type(number_re)
-test_callable = callable
-
-
-def test_odd(value):
- """Return true if the variable is odd."""
- return value % 2 == 1
-
-
-def test_even(value):
- """Return true if the variable is even."""
- return value % 2 == 0
-
-
-def test_divisibleby(value, num):
- """Check if a variable is divisible by a number."""
- return value % num == 0
-
-
-def test_defined(value):
- """Return true if the variable is defined:
-
- .. sourcecode:: jinja
-
- {% if variable is defined %}
- value of variable: {{ variable }}
- {% else %}
- variable is not defined
- {% endif %}
-
- See the :func:`default` filter for a simple way to set undefined
- variables.
- """
- return not isinstance(value, Undefined)
-
-
-def test_undefined(value):
- """Like :func:`defined` but the other way round."""
- return isinstance(value, Undefined)
-
-
-def test_none(value):
- """Return true if the variable is none."""
- return value is None
-
-
+regex_type = type(number_re)
+test_callable = callable
+
+
+def test_odd(value):
+ """Return true if the variable is odd."""
+ return value % 2 == 1
+
+
+def test_even(value):
+ """Return true if the variable is even."""
+ return value % 2 == 0
+
+
+def test_divisibleby(value, num):
+ """Check if a variable is divisible by a number."""
+ return value % num == 0
+
+
+def test_defined(value):
+ """Return true if the variable is defined:
+
+ .. sourcecode:: jinja
+
+ {% if variable is defined %}
+ value of variable: {{ variable }}
+ {% else %}
+ variable is not defined
+ {% endif %}
+
+ See the :func:`default` filter for a simple way to set undefined
+ variables.
+ """
+ return not isinstance(value, Undefined)
+
+
+def test_undefined(value):
+ """Like :func:`defined` but the other way round."""
+ return isinstance(value, Undefined)
+
+
+def test_none(value):
+ """Return true if the variable is none."""
+ return value is None
+
+
def test_boolean(value):
"""Return true if the object is a boolean value.
@@ -99,82 +99,82 @@ def test_float(value):
return isinstance(value, float)
-def test_lower(value):
- """Return true if the variable is lowercased."""
- return text_type(value).islower()
-
-
-def test_upper(value):
- """Return true if the variable is uppercased."""
- return text_type(value).isupper()
-
-
-def test_string(value):
- """Return true if the object is a string."""
- return isinstance(value, string_types)
-
-
-def test_mapping(value):
- """Return true if the object is a mapping (dict etc.).
-
- .. versionadded:: 2.6
- """
+def test_lower(value):
+ """Return true if the variable is lowercased."""
+ return text_type(value).islower()
+
+
+def test_upper(value):
+ """Return true if the variable is uppercased."""
+ return text_type(value).isupper()
+
+
+def test_string(value):
+ """Return true if the object is a string."""
+ return isinstance(value, string_types)
+
+
+def test_mapping(value):
+ """Return true if the object is a mapping (dict etc.).
+
+ .. versionadded:: 2.6
+ """
return isinstance(value, abc.Mapping)
-
-
-def test_number(value):
- """Return true if the variable is a number."""
- return isinstance(value, integer_types + (float, complex, decimal.Decimal))
-
-
-def test_sequence(value):
- """Return true if the variable is a sequence. Sequences are variables
- that are iterable.
- """
- try:
- len(value)
- value.__getitem__
+
+
+def test_number(value):
+ """Return true if the variable is a number."""
+ return isinstance(value, integer_types + (float, complex, decimal.Decimal))
+
+
+def test_sequence(value):
+ """Return true if the variable is a sequence. Sequences are variables
+ that are iterable.
+ """
+ try:
+ len(value)
+ value.__getitem__
except Exception:
- return False
- return True
-
-
-def test_sameas(value, other):
- """Check if an object points to the same memory address than another
- object:
-
- .. sourcecode:: jinja
-
- {% if foo.attribute is sameas false %}
- the foo attribute really is the `False` singleton
- {% endif %}
- """
- return value is other
-
-
-def test_iterable(value):
- """Check if it's possible to iterate over an object."""
- try:
- iter(value)
- except TypeError:
- return False
- return True
-
-
-def test_escaped(value):
- """Check if the value is escaped."""
+ return False
+ return True
+
+
+def test_sameas(value, other):
+ """Check if an object points to the same memory address than another
+ object:
+
+ .. sourcecode:: jinja
+
+ {% if foo.attribute is sameas false %}
+ the foo attribute really is the `False` singleton
+ {% endif %}
+ """
+ return value is other
+
+
+def test_iterable(value):
+ """Check if it's possible to iterate over an object."""
+ try:
+ iter(value)
+ except TypeError:
+ return False
+ return True
+
+
+def test_escaped(value):
+ """Check if the value is escaped."""
return hasattr(value, "__html__")
-
-
-def test_in(value, seq):
- """Check if value is in seq.
-
- .. versionadded:: 2.10
- """
- return value in seq
-
-
-TESTS = {
+
+
+def test_in(value, seq):
+ """Check if value is in seq.
+
+ .. versionadded:: 2.10
+ """
+ return value in seq
+
+
+TESTS = {
"odd": test_odd,
"even": test_even,
"divisibleby": test_divisibleby,
@@ -212,4 +212,4 @@ TESTS = {
"lessthan": operator.lt,
"<=": operator.le,
"le": operator.le,
-}
+}
diff --git a/contrib/python/Jinja2/py2/jinja2/utils.py b/contrib/python/Jinja2/py2/jinja2/utils.py
index 6afca81055..a5273c9782 100644
--- a/contrib/python/Jinja2/py2/jinja2/utils.py
+++ b/contrib/python/Jinja2/py2/jinja2/utils.py
@@ -1,198 +1,198 @@
-# -*- coding: utf-8 -*-
+# -*- coding: utf-8 -*-
import json
import os
-import re
+import re
import warnings
-from collections import deque
+from collections import deque
from random import choice
from random import randrange
from string import ascii_letters as _letters
from string import digits as _digits
-from threading import Lock
-
+from threading import Lock
+
from markupsafe import escape
from markupsafe import Markup
-
+
from ._compat import abc
from ._compat import string_types
from ._compat import text_type
from ._compat import url_quote
-# special singleton representing missing values for the runtime
+# special singleton representing missing values for the runtime
missing = type("MissingType", (), {"__repr__": lambda x: "missing"})()
-
-# internal code
-internal_code = set()
-
+
+# internal code
+internal_code = set()
+
concat = u"".join
-
+
_slash_escape = "\\/" not in json.dumps("/")
-
-
-def contextfunction(f):
- """This decorator can be used to mark a function or method context callable.
- A context callable is passed the active :class:`Context` as first argument when
- called from the template. This is useful if a function wants to get access
- to the context or functions provided on the context object. For example
- a function that returns a sorted list of template variables the current
- template exports could look like this::
-
- @contextfunction
- def get_exported_names(context):
- return sorted(context.exported_vars)
- """
- f.contextfunction = True
- return f
-
-
-def evalcontextfunction(f):
- """This decorator can be used to mark a function or method as an eval
- context callable. This is similar to the :func:`contextfunction`
- but instead of passing the context, an evaluation context object is
- passed. For more information about the eval context, see
- :ref:`eval-context`.
-
- .. versionadded:: 2.4
- """
- f.evalcontextfunction = True
- return f
-
-
-def environmentfunction(f):
- """This decorator can be used to mark a function or method as environment
- callable. This decorator works exactly like the :func:`contextfunction`
- decorator just that the first argument is the active :class:`Environment`
- and not context.
- """
- f.environmentfunction = True
- return f
-
-
-def internalcode(f):
- """Marks the function as internally used"""
- internal_code.add(f.__code__)
- return f
-
-
-def is_undefined(obj):
- """Check if the object passed is undefined. This does nothing more than
- performing an instance check against :class:`Undefined` but looks nicer.
- This can be used for custom filters or tests that want to react to
- undefined variables. For example a custom default filter can look like
- this::
-
- def default(var, default=''):
- if is_undefined(var):
- return default
- return var
- """
+
+
+def contextfunction(f):
+ """This decorator can be used to mark a function or method context callable.
+ A context callable is passed the active :class:`Context` as first argument when
+ called from the template. This is useful if a function wants to get access
+ to the context or functions provided on the context object. For example
+ a function that returns a sorted list of template variables the current
+ template exports could look like this::
+
+ @contextfunction
+ def get_exported_names(context):
+ return sorted(context.exported_vars)
+ """
+ f.contextfunction = True
+ return f
+
+
+def evalcontextfunction(f):
+ """This decorator can be used to mark a function or method as an eval
+ context callable. This is similar to the :func:`contextfunction`
+ but instead of passing the context, an evaluation context object is
+ passed. For more information about the eval context, see
+ :ref:`eval-context`.
+
+ .. versionadded:: 2.4
+ """
+ f.evalcontextfunction = True
+ return f
+
+
+def environmentfunction(f):
+ """This decorator can be used to mark a function or method as environment
+ callable. This decorator works exactly like the :func:`contextfunction`
+ decorator just that the first argument is the active :class:`Environment`
+ and not context.
+ """
+ f.environmentfunction = True
+ return f
+
+
+def internalcode(f):
+ """Marks the function as internally used"""
+ internal_code.add(f.__code__)
+ return f
+
+
+def is_undefined(obj):
+ """Check if the object passed is undefined. This does nothing more than
+ performing an instance check against :class:`Undefined` but looks nicer.
+ This can be used for custom filters or tests that want to react to
+ undefined variables. For example a custom default filter can look like
+ this::
+
+ def default(var, default=''):
+ if is_undefined(var):
+ return default
+ return var
+ """
from .runtime import Undefined
- return isinstance(obj, Undefined)
-
-
-def consume(iterable):
- """Consumes an iterable without doing anything with it."""
+ return isinstance(obj, Undefined)
+
+
+def consume(iterable):
+ """Consumes an iterable without doing anything with it."""
for _ in iterable:
- pass
-
-
-def clear_caches():
+ pass
+
+
+def clear_caches():
"""Jinja keeps internal caches for environments and lexers. These are
used so that Jinja doesn't have to recreate environments and lexers all
- the time. Normally you don't have to care about that but if you are
- measuring memory consumption you may want to clean the caches.
- """
+ the time. Normally you don't have to care about that but if you are
+ measuring memory consumption you may want to clean the caches.
+ """
from .environment import _spontaneous_environments
from .lexer import _lexer_cache
- _spontaneous_environments.clear()
- _lexer_cache.clear()
-
-
-def import_string(import_name, silent=False):
- """Imports an object based on a string. This is useful if you want to
- use import paths as endpoints or something similar. An import path can
- be specified either in dotted notation (``xml.sax.saxutils.escape``)
- or with a colon as object delimiter (``xml.sax.saxutils:escape``).
-
- If the `silent` is True the return value will be `None` if the import
- fails.
-
- :return: imported object
- """
- try:
+ _spontaneous_environments.clear()
+ _lexer_cache.clear()
+
+
+def import_string(import_name, silent=False):
+ """Imports an object based on a string. This is useful if you want to
+ use import paths as endpoints or something similar. An import path can
+ be specified either in dotted notation (``xml.sax.saxutils.escape``)
+ or with a colon as object delimiter (``xml.sax.saxutils:escape``).
+
+ If the `silent` is True the return value will be `None` if the import
+ fails.
+
+ :return: imported object
+ """
+ try:
if ":" in import_name:
module, obj = import_name.split(":", 1)
elif "." in import_name:
module, _, obj = import_name.rpartition(".")
- else:
- return __import__(import_name)
- return getattr(__import__(module, None, None, [obj]), obj)
- except (ImportError, AttributeError):
- if not silent:
- raise
-
-
+ else:
+ return __import__(import_name)
+ return getattr(__import__(module, None, None, [obj]), obj)
+ except (ImportError, AttributeError):
+ if not silent:
+ raise
+
+
def open_if_exists(filename, mode="rb"):
- """Returns a file descriptor for the filename if that file exists,
+ """Returns a file descriptor for the filename if that file exists,
otherwise ``None``.
- """
+ """
if not os.path.isfile(filename):
return None
-
+
return open(filename, mode)
-
-
-def object_type_repr(obj):
- """Returns the name of the object's type. For some recognized
- singletons the name of the object is returned instead. (For
- example for `None` and `Ellipsis`).
- """
- if obj is None:
+
+
+def object_type_repr(obj):
+ """Returns the name of the object's type. For some recognized
+ singletons the name of the object is returned instead. (For
+ example for `None` and `Ellipsis`).
+ """
+ if obj is None:
return "None"
- elif obj is Ellipsis:
+ elif obj is Ellipsis:
return "Ellipsis"
cls = type(obj)
- # __builtin__ in 2.x, builtins in 3.x
+ # __builtin__ in 2.x, builtins in 3.x
if cls.__module__ in ("__builtin__", "builtins"):
name = cls.__name__
- else:
+ else:
name = cls.__module__ + "." + cls.__name__
-
+
return "%s object" % name
-
-
-def pformat(obj, verbose=False):
- """Prettyprint an object. Either use the `pretty` library or the
- builtin `pprint`.
- """
- try:
- from pretty import pretty
-
- return pretty(obj, verbose=verbose)
- except ImportError:
- from pprint import pformat
-
- return pformat(obj)
-
-
-def urlize(text, trim_url_limit=None, rel=None, target=None):
- """Converts any URLs in text into clickable links. Works on http://,
- https:// and www. links. Links can have trailing punctuation (periods,
- commas, close-parens) and leading punctuation (opening parens) and
- it'll still do the right thing.
-
- If trim_url_limit is not None, the URLs in link text will be limited
- to trim_url_limit characters.
-
- If nofollow is True, the URLs in link text will get a rel="nofollow"
- attribute.
-
- If target is not None, a target attribute will be added to the link.
- """
+
+
+def pformat(obj, verbose=False):
+ """Prettyprint an object. Either use the `pretty` library or the
+ builtin `pprint`.
+ """
+ try:
+ from pretty import pretty
+
+ return pretty(obj, verbose=verbose)
+ except ImportError:
+ from pprint import pformat
+
+ return pformat(obj)
+
+
+def urlize(text, trim_url_limit=None, rel=None, target=None):
+ """Converts any URLs in text into clickable links. Works on http://,
+ https:// and www. links. Links can have trailing punctuation (periods,
+ commas, close-parens) and leading punctuation (opening parens) and
+ it'll still do the right thing.
+
+ If trim_url_limit is not None, the URLs in link text will be limited
+ to trim_url_limit characters.
+
+ If nofollow is True, the URLs in link text will get a rel="nofollow"
+ attribute.
+
+ If target is not None, a target attribute will be added to the link.
+ """
trim_url = (
lambda x, limit=trim_url_limit: limit is not None
and (x[:limit] + (len(x) >= limit and "..." or ""))
@@ -201,12 +201,12 @@ def urlize(text, trim_url_limit=None, rel=None, target=None):
words = re.split(r"(\s+)", text_type(escape(text)))
rel_attr = rel and ' rel="%s"' % text_type(escape(rel)) or ""
target_attr = target and ' target="%s"' % escape(target) or ""
-
- for i, word in enumerate(words):
+
+ for i, word in enumerate(words):
head, middle, tail = "", word, ""
match = re.match(r"^([(<]|&lt;)+", middle)
- if match:
+ if match:
head = match.group()
middle = middle[match.end() :]
@@ -258,60 +258,60 @@ def urlize(text, trim_url_limit=None, rel=None, target=None):
words[i] = head + middle + tail
return u"".join(words)
-
-
-def generate_lorem_ipsum(n=5, html=True, min=20, max=100):
- """Generate some lorem ipsum for the template."""
+
+
+def generate_lorem_ipsum(n=5, html=True, min=20, max=100):
+ """Generate some lorem ipsum for the template."""
from .constants import LOREM_IPSUM_WORDS
- words = LOREM_IPSUM_WORDS.split()
- result = []
-
- for _ in range(n):
- next_capitalized = True
- last_comma = last_fullstop = 0
- word = None
- last = None
- p = []
-
- # each paragraph contains out of 20 to 100 words.
- for idx, _ in enumerate(range(randrange(min, max))):
- while True:
- word = choice(words)
- if word != last:
- last = word
- break
- if next_capitalized:
- word = word.capitalize()
- next_capitalized = False
- # add commas
- if idx - randrange(3, 8) > last_comma:
- last_comma = idx
- last_fullstop += 2
+ words = LOREM_IPSUM_WORDS.split()
+ result = []
+
+ for _ in range(n):
+ next_capitalized = True
+ last_comma = last_fullstop = 0
+ word = None
+ last = None
+ p = []
+
+ # each paragraph contains out of 20 to 100 words.
+ for idx, _ in enumerate(range(randrange(min, max))):
+ while True:
+ word = choice(words)
+ if word != last:
+ last = word
+ break
+ if next_capitalized:
+ word = word.capitalize()
+ next_capitalized = False
+ # add commas
+ if idx - randrange(3, 8) > last_comma:
+ last_comma = idx
+ last_fullstop += 2
word += ","
- # add end of sentences
- if idx - randrange(10, 20) > last_fullstop:
- last_comma = last_fullstop = idx
+ # add end of sentences
+ if idx - randrange(10, 20) > last_fullstop:
+ last_comma = last_fullstop = idx
word += "."
- next_capitalized = True
- p.append(word)
-
- # ensure that the paragraph ends with a dot.
+ next_capitalized = True
+ p.append(word)
+
+ # ensure that the paragraph ends with a dot.
p = u" ".join(p)
if p.endswith(","):
p = p[:-1] + "."
elif not p.endswith("."):
p += "."
- result.append(p)
-
- if not html:
+ result.append(p)
+
+ if not html:
return u"\n\n".join(result)
return Markup(u"\n".join(u"<p>%s</p>" % escape(x) for x in result))
-
-
+
+
def unicode_urlencode(obj, charset="utf-8", for_qs=False):
"""Quote a string for use in a URL using the given charset.
-
+
This function is misnamed, it is a wrapper around
:func:`urllib.parse.quote`.
@@ -319,12 +319,12 @@ def unicode_urlencode(obj, charset="utf-8", for_qs=False):
string then encoded to bytes using the given charset.
:param charset: Encode text to bytes using this charset.
:param for_qs: Quote "/" and use "+" for spaces.
- """
- if not isinstance(obj, string_types):
- obj = text_type(obj)
+ """
+ if not isinstance(obj, string_types):
+ obj = text_type(obj)
- if isinstance(obj, text_type):
- obj = obj.encode(charset)
+ if isinstance(obj, text_type):
+ obj = obj.encode(charset)
safe = b"" if for_qs else b"/"
rv = url_quote(obj, safe)
@@ -332,172 +332,172 @@ def unicode_urlencode(obj, charset="utf-8", for_qs=False):
if not isinstance(rv, text_type):
rv = rv.decode("utf-8")
- if for_qs:
+ if for_qs:
rv = rv.replace("%20", "+")
- return rv
-
-
-class LRUCache(object):
- """A simple LRU Cache implementation."""
-
- # this is fast for small capacities (something below 1000) but doesn't
- # scale. But as long as it's only used as storage for templates this
- # won't do any harm.
-
- def __init__(self, capacity):
- self.capacity = capacity
- self._mapping = {}
- self._queue = deque()
- self._postinit()
-
- def _postinit(self):
- # alias all queue methods for faster lookup
- self._popleft = self._queue.popleft
- self._pop = self._queue.pop
- self._remove = self._queue.remove
- self._wlock = Lock()
- self._append = self._queue.append
-
- def __getstate__(self):
- return {
+ return rv
+
+
+class LRUCache(object):
+ """A simple LRU Cache implementation."""
+
+ # this is fast for small capacities (something below 1000) but doesn't
+ # scale. But as long as it's only used as storage for templates this
+ # won't do any harm.
+
+ def __init__(self, capacity):
+ self.capacity = capacity
+ self._mapping = {}
+ self._queue = deque()
+ self._postinit()
+
+ def _postinit(self):
+ # alias all queue methods for faster lookup
+ self._popleft = self._queue.popleft
+ self._pop = self._queue.pop
+ self._remove = self._queue.remove
+ self._wlock = Lock()
+ self._append = self._queue.append
+
+ def __getstate__(self):
+ return {
"capacity": self.capacity,
"_mapping": self._mapping,
"_queue": self._queue,
- }
-
- def __setstate__(self, d):
- self.__dict__.update(d)
- self._postinit()
-
- def __getnewargs__(self):
- return (self.capacity,)
-
- def copy(self):
- """Return a shallow copy of the instance."""
- rv = self.__class__(self.capacity)
- rv._mapping.update(self._mapping)
+ }
+
+ def __setstate__(self, d):
+ self.__dict__.update(d)
+ self._postinit()
+
+ def __getnewargs__(self):
+ return (self.capacity,)
+
+ def copy(self):
+ """Return a shallow copy of the instance."""
+ rv = self.__class__(self.capacity)
+ rv._mapping.update(self._mapping)
rv._queue.extend(self._queue)
- return rv
-
- def get(self, key, default=None):
- """Return an item from the cache dict or `default`"""
- try:
- return self[key]
- except KeyError:
- return default
-
- def setdefault(self, key, default=None):
- """Set `default` if the key is not in the cache otherwise
- leave unchanged. Return the value of this key.
- """
- try:
+ return rv
+
+ def get(self, key, default=None):
+ """Return an item from the cache dict or `default`"""
+ try:
+ return self[key]
+ except KeyError:
+ return default
+
+ def setdefault(self, key, default=None):
+ """Set `default` if the key is not in the cache otherwise
+ leave unchanged. Return the value of this key.
+ """
+ try:
return self[key]
except KeyError:
self[key] = default
return default
-
- def clear(self):
- """Clear the cache."""
- self._wlock.acquire()
- try:
- self._mapping.clear()
- self._queue.clear()
- finally:
- self._wlock.release()
-
- def __contains__(self, key):
- """Check if a key exists in this cache."""
- return key in self._mapping
-
- def __len__(self):
- """Return the current size of the cache."""
- return len(self._mapping)
-
- def __repr__(self):
+
+ def clear(self):
+ """Clear the cache."""
+ self._wlock.acquire()
+ try:
+ self._mapping.clear()
+ self._queue.clear()
+ finally:
+ self._wlock.release()
+
+ def __contains__(self, key):
+ """Check if a key exists in this cache."""
+ return key in self._mapping
+
+ def __len__(self):
+ """Return the current size of the cache."""
+ return len(self._mapping)
+
+ def __repr__(self):
return "<%s %r>" % (self.__class__.__name__, self._mapping)
-
- def __getitem__(self, key):
- """Get an item from the cache. Moves the item up so that it has the
- highest priority then.
-
- Raise a `KeyError` if it does not exist.
- """
- self._wlock.acquire()
- try:
- rv = self._mapping[key]
- if self._queue[-1] != key:
- try:
- self._remove(key)
- except ValueError:
- # if something removed the key from the container
- # when we read, ignore the ValueError that we would
- # get otherwise.
- pass
- self._append(key)
- return rv
- finally:
- self._wlock.release()
-
- def __setitem__(self, key, value):
- """Sets the value for an item. Moves the item up so that it
- has the highest priority then.
- """
- self._wlock.acquire()
- try:
- if key in self._mapping:
- self._remove(key)
- elif len(self._mapping) == self.capacity:
- del self._mapping[self._popleft()]
- self._append(key)
- self._mapping[key] = value
- finally:
- self._wlock.release()
-
- def __delitem__(self, key):
- """Remove an item from the cache dict.
- Raise a `KeyError` if it does not exist.
- """
- self._wlock.acquire()
- try:
- del self._mapping[key]
- try:
- self._remove(key)
- except ValueError:
- pass
- finally:
- self._wlock.release()
-
- def items(self):
- """Return a list of items."""
- result = [(key, self._mapping[key]) for key in list(self._queue)]
- result.reverse()
- return result
-
- def iteritems(self):
- """Iterate over all items."""
+
+ def __getitem__(self, key):
+ """Get an item from the cache. Moves the item up so that it has the
+ highest priority then.
+
+ Raise a `KeyError` if it does not exist.
+ """
+ self._wlock.acquire()
+ try:
+ rv = self._mapping[key]
+ if self._queue[-1] != key:
+ try:
+ self._remove(key)
+ except ValueError:
+ # if something removed the key from the container
+ # when we read, ignore the ValueError that we would
+ # get otherwise.
+ pass
+ self._append(key)
+ return rv
+ finally:
+ self._wlock.release()
+
+ def __setitem__(self, key, value):
+ """Sets the value for an item. Moves the item up so that it
+ has the highest priority then.
+ """
+ self._wlock.acquire()
+ try:
+ if key in self._mapping:
+ self._remove(key)
+ elif len(self._mapping) == self.capacity:
+ del self._mapping[self._popleft()]
+ self._append(key)
+ self._mapping[key] = value
+ finally:
+ self._wlock.release()
+
+ def __delitem__(self, key):
+ """Remove an item from the cache dict.
+ Raise a `KeyError` if it does not exist.
+ """
+ self._wlock.acquire()
+ try:
+ del self._mapping[key]
+ try:
+ self._remove(key)
+ except ValueError:
+ pass
+ finally:
+ self._wlock.release()
+
+ def items(self):
+ """Return a list of items."""
+ result = [(key, self._mapping[key]) for key in list(self._queue)]
+ result.reverse()
+ return result
+
+ def iteritems(self):
+ """Iterate over all items."""
warnings.warn(
"'iteritems()' will be removed in version 3.0. Use"
" 'iter(cache.items())' instead.",
DeprecationWarning,
stacklevel=2,
)
- return iter(self.items())
-
- def values(self):
- """Return a list of all values."""
- return [x[1] for x in self.items()]
-
- def itervalue(self):
- """Iterate over all values."""
+ return iter(self.items())
+
+ def values(self):
+ """Return a list of all values."""
+ return [x[1] for x in self.items()]
+
+ def itervalue(self):
+ """Iterate over all values."""
warnings.warn(
"'itervalue()' will be removed in version 3.0. Use"
" 'iter(cache.values())' instead.",
DeprecationWarning,
stacklevel=2,
)
- return iter(self.values())
-
+ return iter(self.values())
+
def itervalues(self):
"""Iterate over all values."""
warnings.warn(
@@ -508,14 +508,14 @@ class LRUCache(object):
)
return iter(self.values())
- def keys(self):
- """Return a list of all keys ordered by most recent usage."""
- return list(self)
-
- def iterkeys(self):
- """Iterate over all keys in the cache dict, ordered by
- the most recent usage.
- """
+ def keys(self):
+ """Return a list of all keys ordered by most recent usage."""
+ return list(self)
+
+ def iterkeys(self):
+ """Iterate over all keys in the cache dict, ordered by
+ the most recent usage.
+ """
warnings.warn(
"'iterkeys()' will be removed in version 3.0. Use"
" 'iter(cache.keys())' instead.",
@@ -525,96 +525,96 @@ class LRUCache(object):
return iter(self)
def __iter__(self):
- return reversed(tuple(self._queue))
-
- def __reversed__(self):
+ return reversed(tuple(self._queue))
+
+ def __reversed__(self):
"""Iterate over the keys in the cache dict, oldest items
- coming first.
- """
- return iter(tuple(self._queue))
-
- __copy__ = copy
-
-
+ coming first.
+ """
+ return iter(tuple(self._queue))
+
+ __copy__ = copy
+
+
abc.MutableMapping.register(LRUCache)
-
-
+
+
def select_autoescape(
enabled_extensions=("html", "htm", "xml"),
disabled_extensions=(),
default_for_string=True,
default=False,
):
- """Intelligently sets the initial value of autoescaping based on the
- filename of the template. This is the recommended way to configure
- autoescaping if you do not want to write a custom function yourself.
-
- If you want to enable it for all templates created from strings or
- for all templates with `.html` and `.xml` extensions::
-
- from jinja2 import Environment, select_autoescape
- env = Environment(autoescape=select_autoescape(
- enabled_extensions=('html', 'xml'),
- default_for_string=True,
- ))
-
- Example configuration to turn it on at all times except if the template
- ends with `.txt`::
-
- from jinja2 import Environment, select_autoescape
- env = Environment(autoescape=select_autoescape(
- disabled_extensions=('txt',),
- default_for_string=True,
- default=True,
- ))
-
- The `enabled_extensions` is an iterable of all the extensions that
- autoescaping should be enabled for. Likewise `disabled_extensions` is
- a list of all templates it should be disabled for. If a template is
- loaded from a string then the default from `default_for_string` is used.
- If nothing matches then the initial value of autoescaping is set to the
- value of `default`.
-
- For security reasons this function operates case insensitive.
-
- .. versionadded:: 2.9
- """
+ """Intelligently sets the initial value of autoescaping based on the
+ filename of the template. This is the recommended way to configure
+ autoescaping if you do not want to write a custom function yourself.
+
+ If you want to enable it for all templates created from strings or
+ for all templates with `.html` and `.xml` extensions::
+
+ from jinja2 import Environment, select_autoescape
+ env = Environment(autoescape=select_autoescape(
+ enabled_extensions=('html', 'xml'),
+ default_for_string=True,
+ ))
+
+ Example configuration to turn it on at all times except if the template
+ ends with `.txt`::
+
+ from jinja2 import Environment, select_autoescape
+ env = Environment(autoescape=select_autoescape(
+ disabled_extensions=('txt',),
+ default_for_string=True,
+ default=True,
+ ))
+
+ The `enabled_extensions` is an iterable of all the extensions that
+ autoescaping should be enabled for. Likewise `disabled_extensions` is
+ a list of all templates it should be disabled for. If a template is
+ loaded from a string then the default from `default_for_string` is used.
+ If nothing matches then the initial value of autoescaping is set to the
+ value of `default`.
+
+ For security reasons this function operates case insensitive.
+
+ .. versionadded:: 2.9
+ """
enabled_patterns = tuple("." + x.lstrip(".").lower() for x in enabled_extensions)
disabled_patterns = tuple("." + x.lstrip(".").lower() for x in disabled_extensions)
- def autoescape(template_name):
- if template_name is None:
- return default_for_string
- template_name = template_name.lower()
- if template_name.endswith(enabled_patterns):
- return True
- if template_name.endswith(disabled_patterns):
- return False
- return default
-
- return autoescape
-
-
-def htmlsafe_json_dumps(obj, dumper=None, **kwargs):
- """Works exactly like :func:`dumps` but is safe for use in ``<script>``
- tags. It accepts the same arguments and returns a JSON string. Note that
- this is available in templates through the ``|tojson`` filter which will
- also mark the result as safe. Due to how this function escapes certain
- characters this is safe even if used outside of ``<script>`` tags.
-
- The following characters are escaped in strings:
-
- - ``<``
- - ``>``
- - ``&``
- - ``'``
-
- This makes it safe to embed such strings in any place in HTML with the
- notable exception of double quoted attributes. In that case single
- quote your attributes or HTML escape it in addition.
- """
- if dumper is None:
- dumper = json.dumps
+ def autoescape(template_name):
+ if template_name is None:
+ return default_for_string
+ template_name = template_name.lower()
+ if template_name.endswith(enabled_patterns):
+ return True
+ if template_name.endswith(disabled_patterns):
+ return False
+ return default
+
+ return autoescape
+
+
+def htmlsafe_json_dumps(obj, dumper=None, **kwargs):
+ """Works exactly like :func:`dumps` but is safe for use in ``<script>``
+ tags. It accepts the same arguments and returns a JSON string. Note that
+ this is available in templates through the ``|tojson`` filter which will
+ also mark the result as safe. Due to how this function escapes certain
+ characters this is safe even if used outside of ``<script>`` tags.
+
+ The following characters are escaped in strings:
+
+ - ``<``
+ - ``>``
+ - ``&``
+ - ``'``
+
+ This makes it safe to embed such strings in any place in HTML with the
+ notable exception of double quoted attributes. In that case single
+ quote your attributes or HTML escape it in addition.
+ """
+ if dumper is None:
+ dumper = json.dumps
rv = (
dumper(obj, **kwargs)
.replace(u"<", u"\\u003c")
@@ -622,13 +622,13 @@ def htmlsafe_json_dumps(obj, dumper=None, **kwargs):
.replace(u"&", u"\\u0026")
.replace(u"'", u"\\u0027")
)
- return Markup(rv)
-
-
-class Cycler(object):
+ return Markup(rv)
+
+
+class Cycler(object):
"""Cycle through values by yield them one at a time, then restarting
once the end is reached. Available as ``cycler`` in templates.
-
+
Similar to ``loop.cycle``, but can be used outside loops or across
multiple loops. For example, render a list of folders and files in a
list, alternating giving them "odd" and "even" classes.
@@ -651,80 +651,80 @@ class Cycler(object):
.. versionadded:: 2.1
"""
- def __init__(self, *items):
- if not items:
+ def __init__(self, *items):
+ if not items:
raise RuntimeError("at least one item has to be provided")
- self.items = items
+ self.items = items
self.pos = 0
-
- def reset(self):
+
+ def reset(self):
"""Resets the current item to the first item."""
- self.pos = 0
-
- @property
- def current(self):
+ self.pos = 0
+
+ @property
+ def current(self):
"""Return the current item. Equivalent to the item that will be
returned next time :meth:`next` is called.
"""
- return self.items[self.pos]
-
- def next(self):
+ return self.items[self.pos]
+
+ def next(self):
"""Return the current item, then advance :attr:`current` to the
next item.
"""
- rv = self.current
- self.pos = (self.pos + 1) % len(self.items)
- return rv
-
- __next__ = next
-
-
-class Joiner(object):
- """A joining helper for templates."""
-
+ rv = self.current
+ self.pos = (self.pos + 1) % len(self.items)
+ return rv
+
+ __next__ = next
+
+
+class Joiner(object):
+ """A joining helper for templates."""
+
def __init__(self, sep=u", "):
- self.sep = sep
- self.used = False
-
- def __call__(self):
- if not self.used:
- self.used = True
+ self.sep = sep
+ self.used = False
+
+ def __call__(self):
+ if not self.used:
+ self.used = True
return u""
- return self.sep
-
-
-class Namespace(object):
- """A namespace object that can hold arbitrary attributes. It may be
+ return self.sep
+
+
+class Namespace(object):
+ """A namespace object that can hold arbitrary attributes. It may be
initialized from a dictionary or with keyword arguments."""
-
+
def __init__(*args, **kwargs): # noqa: B902
- self, args = args[0], args[1:]
- self.__attrs = dict(*args, **kwargs)
-
- def __getattribute__(self, name):
+ self, args = args[0], args[1:]
+ self.__attrs = dict(*args, **kwargs)
+
+ def __getattribute__(self, name):
# __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]
- except KeyError:
- raise AttributeError(name)
-
- def __setitem__(self, name, value):
- self.__attrs[name] = value
-
- def __repr__(self):
+ return object.__getattribute__(self, name)
+ try:
+ return self.__attrs[name]
+ except KeyError:
+ raise AttributeError(name)
+
+ def __setitem__(self, name, value):
+ self.__attrs[name] = value
+
+ def __repr__(self):
return "<Namespace %r>" % self.__attrs
-
-
-# does this python version support async for in and async generators?
-try:
+
+
+# does this python version support async for in and async generators?
+try:
exec("async def _():\n async for _ in ():\n yield _")
- have_async_gen = True
-except SyntaxError:
- have_async_gen = False
-
-
+ have_async_gen = True
+except SyntaxError:
+ have_async_gen = False
+
+
def soft_unicode(s):
from markupsafe import soft_unicode
diff --git a/contrib/python/Jinja2/py2/jinja2/visitor.py b/contrib/python/Jinja2/py2/jinja2/visitor.py
index d1365bf10e..7e65ca1bc0 100644
--- a/contrib/python/Jinja2/py2/jinja2/visitor.py
+++ b/contrib/python/Jinja2/py2/jinja2/visitor.py
@@ -1,81 +1,81 @@
-# -*- coding: utf-8 -*-
+# -*- coding: utf-8 -*-
"""API for traversing the AST nodes. Implemented by the compiler and
meta introspection.
-"""
+"""
from .nodes import Node
-
-
-class NodeVisitor(object):
- """Walks the abstract syntax tree and call visitor functions for every
- node found. The visitor functions may return values which will be
- forwarded by the `visit` method.
-
- Per default the visitor functions for the nodes are ``'visit_'`` +
- class name of the node. So a `TryFinally` node visit function would
- be `visit_TryFinally`. This behavior can be changed by overriding
- the `get_visitor` function. If no visitor function exists for a node
- (return value `None`) the `generic_visit` visitor is used instead.
- """
-
- def get_visitor(self, node):
- """Return the visitor function for this node or `None` if no visitor
- exists for this node. In that case the generic visit function is
- used instead.
- """
+
+
+class NodeVisitor(object):
+ """Walks the abstract syntax tree and call visitor functions for every
+ node found. The visitor functions may return values which will be
+ forwarded by the `visit` method.
+
+ Per default the visitor functions for the nodes are ``'visit_'`` +
+ class name of the node. So a `TryFinally` node visit function would
+ be `visit_TryFinally`. This behavior can be changed by overriding
+ the `get_visitor` function. If no visitor function exists for a node
+ (return value `None`) the `generic_visit` visitor is used instead.
+ """
+
+ def get_visitor(self, node):
+ """Return the visitor function for this node or `None` if no visitor
+ exists for this node. In that case the generic visit function is
+ used instead.
+ """
method = "visit_" + node.__class__.__name__
- return getattr(self, method, None)
-
- def visit(self, node, *args, **kwargs):
- """Visit a node."""
- f = self.get_visitor(node)
- if f is not None:
- return f(node, *args, **kwargs)
- return self.generic_visit(node, *args, **kwargs)
-
- def generic_visit(self, node, *args, **kwargs):
- """Called if no explicit visitor function exists for a node."""
- for node in node.iter_child_nodes():
- self.visit(node, *args, **kwargs)
-
-
-class NodeTransformer(NodeVisitor):
- """Walks the abstract syntax tree and allows modifications of nodes.
-
- The `NodeTransformer` will walk the AST and use the return value of the
- visitor functions to replace or remove the old node. If the return
- value of the visitor function is `None` the node will be removed
- from the previous location otherwise it's replaced with the return
- value. The return value may be the original node in which case no
- replacement takes place.
- """
-
- def generic_visit(self, node, *args, **kwargs):
- for field, old_value in node.iter_fields():
- if isinstance(old_value, list):
- new_values = []
- for value in old_value:
- if isinstance(value, Node):
- value = self.visit(value, *args, **kwargs)
- if value is None:
- continue
- elif not isinstance(value, Node):
- new_values.extend(value)
- continue
- new_values.append(value)
- old_value[:] = new_values
- elif isinstance(old_value, Node):
- new_node = self.visit(old_value, *args, **kwargs)
- if new_node is None:
- delattr(node, field)
- else:
- setattr(node, field, new_node)
- return node
-
- def visit_list(self, node, *args, **kwargs):
- """As transformers may return lists in some places this method
- can be used to enforce a list as return value.
- """
- rv = self.visit(node, *args, **kwargs)
- if not isinstance(rv, list):
- rv = [rv]
- return rv
+ return getattr(self, method, None)
+
+ def visit(self, node, *args, **kwargs):
+ """Visit a node."""
+ f = self.get_visitor(node)
+ if f is not None:
+ return f(node, *args, **kwargs)
+ return self.generic_visit(node, *args, **kwargs)
+
+ def generic_visit(self, node, *args, **kwargs):
+ """Called if no explicit visitor function exists for a node."""
+ for node in node.iter_child_nodes():
+ self.visit(node, *args, **kwargs)
+
+
+class NodeTransformer(NodeVisitor):
+ """Walks the abstract syntax tree and allows modifications of nodes.
+
+ The `NodeTransformer` will walk the AST and use the return value of the
+ visitor functions to replace or remove the old node. If the return
+ value of the visitor function is `None` the node will be removed
+ from the previous location otherwise it's replaced with the return
+ value. The return value may be the original node in which case no
+ replacement takes place.
+ """
+
+ def generic_visit(self, node, *args, **kwargs):
+ for field, old_value in node.iter_fields():
+ if isinstance(old_value, list):
+ new_values = []
+ for value in old_value:
+ if isinstance(value, Node):
+ value = self.visit(value, *args, **kwargs)
+ if value is None:
+ continue
+ elif not isinstance(value, Node):
+ new_values.extend(value)
+ continue
+ new_values.append(value)
+ old_value[:] = new_values
+ elif isinstance(old_value, Node):
+ new_node = self.visit(old_value, *args, **kwargs)
+ if new_node is None:
+ delattr(node, field)
+ else:
+ setattr(node, field, new_node)
+ return node
+
+ def visit_list(self, node, *args, **kwargs):
+ """As transformers may return lists in some places this method
+ can be used to enforce a list as return value.
+ """
+ rv = self.visit(node, *args, **kwargs)
+ if not isinstance(rv, list):
+ rv = [rv]
+ return rv
diff --git a/contrib/python/Jinja2/py2/tests/conftest.py b/contrib/python/Jinja2/py2/tests/conftest.py
index c34e6c53c6..f900cd780a 100644
--- a/contrib/python/Jinja2/py2/tests/conftest.py
+++ b/contrib/python/Jinja2/py2/tests/conftest.py
@@ -1,39 +1,39 @@
-# -*- coding: utf-8 -*-
+# -*- coding: utf-8 -*-
import os
-
-import pytest
-
+
+import pytest
+
from jinja2 import Environment
-from jinja2 import loaders
-from jinja2.utils import have_async_gen
-
-
+from jinja2 import loaders
+from jinja2.utils import have_async_gen
+
+
def pytest_ignore_collect(path):
if "async" in path.basename and not have_async_gen:
- return True
- return False
-
-
-@pytest.fixture
-def env():
+ return True
+ return False
+
+
+@pytest.fixture
+def env():
"""returns a new environment."""
- return Environment()
-
-
-@pytest.fixture
-def dict_loader():
+ return Environment()
+
+
+@pytest.fixture
+def dict_loader():
"""returns DictLoader"""
return loaders.DictLoader({"justdict.html": "FOO"})
-
-
-@pytest.fixture
-def package_loader():
+
+
+@pytest.fixture
+def package_loader():
"""returns PackageLoader initialized from templates"""
return loaders.PackageLoader("res", "templates")
-
-
-@pytest.fixture
-def filesystem_loader():
+
+
+@pytest.fixture
+def filesystem_loader():
"""returns FileSystemLoader initialized to res/templates directory"""
try:
import yatest.common
@@ -41,21 +41,21 @@ def filesystem_loader():
except ImportError:
here = os.path.dirname(os.path.abspath(__file__))
return loaders.FileSystemLoader(here + "/res/templates")
-
-
-@pytest.fixture
-def function_loader():
+
+
+@pytest.fixture
+def function_loader():
"""returns a FunctionLoader"""
return loaders.FunctionLoader({"justfunction.html": "FOO"}.get)
-
-
-@pytest.fixture
-def choice_loader(dict_loader, package_loader):
+
+
+@pytest.fixture
+def choice_loader(dict_loader, package_loader):
"""returns a ChoiceLoader"""
- return loaders.ChoiceLoader([dict_loader, package_loader])
-
-
-@pytest.fixture
-def prefix_loader(filesystem_loader, dict_loader):
+ return loaders.ChoiceLoader([dict_loader, package_loader])
+
+
+@pytest.fixture
+def prefix_loader(filesystem_loader, dict_loader):
"""returns a PrefixLoader"""
return loaders.PrefixLoader({"a": filesystem_loader, "b": dict_loader})
diff --git a/contrib/python/Jinja2/py2/tests/res/templates/broken.html b/contrib/python/Jinja2/py2/tests/res/templates/broken.html
index 77669fae57..b38d7bb927 100644
--- a/contrib/python/Jinja2/py2/tests/res/templates/broken.html
+++ b/contrib/python/Jinja2/py2/tests/res/templates/broken.html
@@ -1,3 +1,3 @@
-Before
-{{ fail() }}
-After
+Before
+{{ fail() }}
+After
diff --git a/contrib/python/Jinja2/py2/tests/res/templates/foo/test.html b/contrib/python/Jinja2/py2/tests/res/templates/foo/test.html
index b7d6715e2d..bbd2d23cd1 100644
--- a/contrib/python/Jinja2/py2/tests/res/templates/foo/test.html
+++ b/contrib/python/Jinja2/py2/tests/res/templates/foo/test.html
@@ -1 +1 @@
-FOO
+FOO
diff --git a/contrib/python/Jinja2/py2/tests/res/templates/syntaxerror.html b/contrib/python/Jinja2/py2/tests/res/templates/syntaxerror.html
index f21b817939..dc8c8af224 100644
--- a/contrib/python/Jinja2/py2/tests/res/templates/syntaxerror.html
+++ b/contrib/python/Jinja2/py2/tests/res/templates/syntaxerror.html
@@ -1,4 +1,4 @@
-Foo
-{% for item in broken %}
- ...
-{% endif %}
+Foo
+{% for item in broken %}
+ ...
+{% endif %}
diff --git a/contrib/python/Jinja2/py2/tests/res/templates/test.html b/contrib/python/Jinja2/py2/tests/res/templates/test.html
index ba578e48b1..640acfc455 100644
--- a/contrib/python/Jinja2/py2/tests/res/templates/test.html
+++ b/contrib/python/Jinja2/py2/tests/res/templates/test.html
@@ -1 +1 @@
-BAR
+BAR
diff --git a/contrib/python/Jinja2/py2/tests/test_api.py b/contrib/python/Jinja2/py2/tests/test_api.py
index 7a1cae866b..0ac95186bd 100644
--- a/contrib/python/Jinja2/py2/tests/test_api.py
+++ b/contrib/python/Jinja2/py2/tests/test_api.py
@@ -1,9 +1,9 @@
-# -*- coding: utf-8 -*-
-import os
+# -*- coding: utf-8 -*-
+import os
import shutil
-import tempfile
-
-import pytest
+import tempfile
+
+import pytest
from jinja2 import ChainableUndefined
from jinja2 import DebugUndefined
@@ -17,32 +17,32 @@ from jinja2 import Template
from jinja2 import TemplatesNotFound
from jinja2 import Undefined
from jinja2 import UndefinedError
-from jinja2.compiler import CodeGenerator
-from jinja2.runtime import Context
+from jinja2.compiler import CodeGenerator
+from jinja2.runtime import Context
from jinja2.utils import contextfunction
-from jinja2.utils import Cycler
+from jinja2.utils import Cycler
from jinja2.utils import environmentfunction
from jinja2.utils import evalcontextfunction
-
-
-class TestExtendedAPI(object):
- def test_item_and_attribute(self, env):
- from jinja2.sandbox import SandboxedEnvironment
-
- for env in Environment(), SandboxedEnvironment():
- # the |list is necessary for python3
+
+
+class TestExtendedAPI(object):
+ def test_item_and_attribute(self, env):
+ from jinja2.sandbox import SandboxedEnvironment
+
+ for env in Environment(), SandboxedEnvironment():
+ # the |list is necessary for python3
tmpl = env.from_string("{{ foo.items()|list }}")
assert tmpl.render(foo={"items": 42}) == "[('items', 42)]"
- tmpl = env.from_string('{{ foo|attr("items")()|list }}')
+ tmpl = env.from_string('{{ foo|attr("items")()|list }}')
assert tmpl.render(foo={"items": 42}) == "[('items', 42)]"
- tmpl = env.from_string('{{ foo["items"] }}')
+ tmpl = env.from_string('{{ foo["items"] }}')
assert tmpl.render(foo={"items": 42}) == "42"
-
+
def test_finalize(self):
e = Environment(finalize=lambda v: "" if v is None else v)
t = e.from_string("{% for item in seq %}|{{ item }}{% endfor %}")
assert t.render(seq=(None, 1, "foo")) == "||1|foo"
-
+
def test_finalize_constant_expression(self):
e = Environment(finalize=lambda v: "" if v is None else v)
t = e.from_string("<{{ none }}>")
@@ -83,34 +83,34 @@ class TestExtendedAPI(object):
t = e.from_string("{{ value }}")
assert t.render(value="hello") == "{{ 'hello' }}"
- def test_cycler(self, env):
- items = 1, 2, 3
- c = Cycler(*items)
- for item in items + items:
- assert c.current == item
- assert next(c) == item
- next(c)
- assert c.current == 2
- c.reset()
- assert c.current == 1
-
- def test_expressions(self, env):
- expr = env.compile_expression("foo")
- assert expr() is None
- assert expr(foo=42) == 42
- expr2 = env.compile_expression("foo", undefined_to_none=False)
- assert is_undefined(expr2())
-
- expr = env.compile_expression("42 + foo")
- assert expr(foo=42) == 84
-
- def test_template_passthrough(self, env):
+ def test_cycler(self, env):
+ items = 1, 2, 3
+ c = Cycler(*items)
+ for item in items + items:
+ assert c.current == item
+ assert next(c) == item
+ next(c)
+ assert c.current == 2
+ c.reset()
+ assert c.current == 1
+
+ def test_expressions(self, env):
+ expr = env.compile_expression("foo")
+ assert expr() is None
+ assert expr(foo=42) == 42
+ expr2 = env.compile_expression("foo", undefined_to_none=False)
+ assert is_undefined(expr2())
+
+ expr = env.compile_expression("42 + foo")
+ assert expr(foo=42) == 84
+
+ def test_template_passthrough(self, env):
t = Template("Content")
- assert env.get_template(t) is t
- assert env.select_template([t]) is t
- assert env.get_or_select_template([t]) is t
- assert env.get_or_select_template(t) is t
-
+ assert env.get_template(t) is t
+ assert env.select_template([t]) is t
+ assert env.get_or_select_template([t]) is t
+ assert env.get_or_select_template(t) is t
+
def test_get_template_undefined(self, env):
"""Passing Undefined to get/select_template raises an
UndefinedError or shows the undefined message in the list.
@@ -134,12 +134,12 @@ class TestExtendedAPI(object):
assert "'no_name_1' is undefined" in exc_message
assert "no_name_2" in exc_message
- def test_autoescape_autoselect(self, env):
- def select_autoescape(name):
+ def test_autoescape_autoselect(self, env):
+ def select_autoescape(name):
if name is None or "." not in name:
- return False
+ return False
return name.endswith(".html")
-
+
env = Environment(
autoescape=select_autoescape,
loader=DictLoader({"test.txt": "{{ foo }}", "test.html": "{{ foo }}"}),
@@ -150,7 +150,7 @@ class TestExtendedAPI(object):
assert t.render(foo="<foo>") == "&lt;foo&gt;"
t = env.from_string("{{ foo }}")
assert t.render(foo="<foo>") == "<foo>"
-
+
def test_sandbox_max_range(self, env):
from jinja2.sandbox import SandboxedEnvironment, MAX_RANGE
@@ -161,61 +161,61 @@ class TestExtendedAPI(object):
t.render(total=MAX_RANGE + 1)
-class TestMeta(object):
- def test_find_undeclared_variables(self, env):
+class TestMeta(object):
+ def test_find_undeclared_variables(self, env):
ast = env.parse("{% set foo = 42 %}{{ bar + foo }}")
- x = meta.find_undeclared_variables(ast)
+ x = meta.find_undeclared_variables(ast)
assert x == set(["bar"])
-
+
ast = env.parse(
"{% set foo = 42 %}{{ bar + foo }}"
"{% macro meh(x) %}{{ x }}{% endmacro %}"
"{% for item in seq %}{{ muh(item) + meh(seq) }}"
"{% endfor %}"
)
- x = meta.find_undeclared_variables(ast)
+ x = meta.find_undeclared_variables(ast)
assert x == set(["bar", "seq", "muh"])
-
+
ast = env.parse("{% for x in range(5) %}{{ x }}{% endfor %}{{ foo }}")
x = meta.find_undeclared_variables(ast)
assert x == set(["foo"])
- def test_find_refererenced_templates(self, env):
- ast = env.parse('{% extends "layout.html" %}{% include helper %}')
- i = meta.find_referenced_templates(ast)
+ def test_find_refererenced_templates(self, env):
+ ast = env.parse('{% extends "layout.html" %}{% include helper %}')
+ i = meta.find_referenced_templates(ast)
assert next(i) == "layout.html"
- assert next(i) is None
- assert list(i) == []
-
+ assert next(i) is None
+ assert list(i) == []
+
ast = env.parse(
'{% extends "layout.html" %}'
'{% from "test.html" import a, b as c %}'
'{% import "meh.html" as meh %}'
'{% include "muh.html" %}'
)
- i = meta.find_referenced_templates(ast)
+ i = meta.find_referenced_templates(ast)
assert list(i) == ["layout.html", "test.html", "meh.html", "muh.html"]
-
- def test_find_included_templates(self, env):
- ast = env.parse('{% include ["foo.html", "bar.html"] %}')
- i = meta.find_referenced_templates(ast)
+
+ def test_find_included_templates(self, env):
+ ast = env.parse('{% include ["foo.html", "bar.html"] %}')
+ i = meta.find_referenced_templates(ast)
assert list(i) == ["foo.html", "bar.html"]
-
- ast = env.parse('{% include ("foo.html", "bar.html") %}')
- i = meta.find_referenced_templates(ast)
+
+ ast = env.parse('{% include ("foo.html", "bar.html") %}')
+ i = meta.find_referenced_templates(ast)
assert list(i) == ["foo.html", "bar.html"]
-
- ast = env.parse('{% include ["foo.html", "bar.html", foo] %}')
- i = meta.find_referenced_templates(ast)
+
+ ast = env.parse('{% include ["foo.html", "bar.html", foo] %}')
+ i = meta.find_referenced_templates(ast)
assert list(i) == ["foo.html", "bar.html", None]
-
- ast = env.parse('{% include ("foo.html", "bar.html", foo) %}')
- i = meta.find_referenced_templates(ast)
+
+ ast = env.parse('{% include ("foo.html", "bar.html", foo) %}')
+ i = meta.find_referenced_templates(ast)
assert list(i) == ["foo.html", "bar.html", None]
-
-
-class TestStreaming(object):
- def test_basic_streaming(self, env):
+
+
+class TestStreaming(object):
+ def test_basic_streaming(self, env):
t = env.from_string(
"<ul>{% for item in seq %}<li>{{ loop.index }} - {{ item }}</li>"
"{%- endfor %}</ul>"
@@ -223,52 +223,52 @@ class TestStreaming(object):
stream = t.stream(seq=list(range(3)))
assert next(stream) == "<ul>"
assert "".join(stream) == "<li>1 - 0</li><li>2 - 1</li><li>3 - 2</li></ul>"
-
- def test_buffered_streaming(self, env):
+
+ def test_buffered_streaming(self, env):
tmpl = env.from_string(
"<ul>{% for item in seq %}<li>{{ loop.index }} - {{ item }}</li>"
"{%- endfor %}</ul>"
)
stream = tmpl.stream(seq=list(range(3)))
- stream.enable_buffering(size=3)
+ stream.enable_buffering(size=3)
assert next(stream) == u"<ul><li>1"
assert next(stream) == u" - 0</li>"
-
- def test_streaming_behavior(self, env):
- tmpl = env.from_string("")
- stream = tmpl.stream()
- assert not stream.buffered
- stream.enable_buffering(20)
- assert stream.buffered
- stream.disable_buffering()
- assert not stream.buffered
-
- def test_dump_stream(self, env):
- tmp = tempfile.mkdtemp()
- try:
- tmpl = env.from_string(u"\u2713")
- stream = tmpl.stream()
+
+ def test_streaming_behavior(self, env):
+ tmpl = env.from_string("")
+ stream = tmpl.stream()
+ assert not stream.buffered
+ stream.enable_buffering(20)
+ assert stream.buffered
+ stream.disable_buffering()
+ assert not stream.buffered
+
+ def test_dump_stream(self, env):
+ tmp = tempfile.mkdtemp()
+ try:
+ tmpl = env.from_string(u"\u2713")
+ stream = tmpl.stream()
stream.dump(os.path.join(tmp, "dump.txt"), "utf-8")
with open(os.path.join(tmp, "dump.txt"), "rb") as f:
assert f.read() == b"\xe2\x9c\x93"
- finally:
- shutil.rmtree(tmp)
-
-
-class TestUndefined(object):
- def test_stopiteration_is_undefined(self):
- def test():
- raise StopIteration()
+ finally:
+ shutil.rmtree(tmp)
+
+
+class TestUndefined(object):
+ def test_stopiteration_is_undefined(self):
+ def test():
+ raise StopIteration()
t = Template("A{{ test() }}B")
assert t.render(test=test) == "AB"
t = Template("A{{ test().missingattribute }}B")
- pytest.raises(UndefinedError, t.render, test=test)
-
- def test_undefined_and_special_attributes(self):
+ pytest.raises(UndefinedError, t.render, test=test)
+
+ def test_undefined_and_special_attributes(self):
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
@@ -284,34 +284,34 @@ class TestUndefined(object):
with pytest.raises(UndefinedError):
getattr(u, "recursion", None)
- def test_logging_undefined(self):
- _messages = []
-
- class DebugLogger(object):
- def warning(self, msg, *args):
+ def test_logging_undefined(self):
+ _messages = []
+
+ class DebugLogger(object):
+ def warning(self, msg, *args):
_messages.append("W:" + msg % args)
-
- def error(self, msg, *args):
+
+ def error(self, msg, *args):
_messages.append("E:" + msg % args)
-
- logging_undefined = make_logging_undefined(DebugLogger())
- env = Environment(undefined=logging_undefined)
+
+ logging_undefined = make_logging_undefined(DebugLogger())
+ env = Environment(undefined=logging_undefined)
assert env.from_string("{{ missing }}").render() == u""
pytest.raises(UndefinedError, env.from_string("{{ missing.attribute }}").render)
assert env.from_string("{{ missing|list }}").render() == "[]"
assert env.from_string("{{ missing is not defined }}").render() == "True"
assert env.from_string("{{ foo.missing }}").render(foo=42) == ""
assert env.from_string("{{ not missing }}").render() == "True"
- assert _messages == [
+ assert _messages == [
"W:Template variable warning: missing is undefined",
- "E:Template variable error: 'missing' is undefined",
+ "E:Template variable error: 'missing' is undefined",
"W:Template variable warning: missing is undefined",
"W:Template variable warning: int object has no attribute missing",
"W:Template variable warning: missing is undefined",
- ]
-
- def test_default_undefined(self):
- env = Environment(undefined=Undefined)
+ ]
+
+ def test_default_undefined(self):
+ env = Environment(undefined=Undefined)
assert env.from_string("{{ missing }}").render() == u""
pytest.raises(UndefinedError, env.from_string("{{ missing.attribute }}").render)
assert env.from_string("{{ missing|list }}").render() == "[]"
@@ -326,7 +326,7 @@ class TestUndefined(object):
assert hash(und1) == hash(und2) == hash(Undefined())
with pytest.raises(AttributeError):
getattr(Undefined, "__slots__") # noqa: B009
-
+
def test_chainable_undefined(self):
env = Environment(undefined=ChainableUndefined)
# The following tests are copied from test_default_undefined
@@ -355,15 +355,15 @@ class TestUndefined(object):
== u"baz"
)
- def test_debug_undefined(self):
- env = Environment(undefined=DebugUndefined)
+ def test_debug_undefined(self):
+ env = Environment(undefined=DebugUndefined)
assert env.from_string("{{ missing }}").render() == "{{ missing }}"
pytest.raises(UndefinedError, env.from_string("{{ missing.attribute }}").render)
assert env.from_string("{{ missing|list }}").render() == "[]"
assert env.from_string("{{ missing is not defined }}").render() == "True"
assert (
env.from_string("{{ foo.missing }}").render(foo=42)
- == u"{{ no such element: int object['missing'] }}"
+ == u"{{ no such element: int object['missing'] }}"
)
assert env.from_string("{{ not missing }}").render() == "True"
undefined_hint = "this is testing undefined hint of DebugUndefined"
@@ -373,9 +373,9 @@ class TestUndefined(object):
)
with pytest.raises(AttributeError):
getattr(DebugUndefined, "__slots__") # noqa: B009
-
- def test_strict_undefined(self):
- env = Environment(undefined=StrictUndefined)
+
+ def test_strict_undefined(self):
+ env = Environment(undefined=StrictUndefined)
pytest.raises(UndefinedError, env.from_string("{{ missing }}").render)
pytest.raises(UndefinedError, env.from_string("{{ missing.attribute }}").render)
pytest.raises(UndefinedError, env.from_string("{{ missing|list }}").render)
@@ -391,47 +391,47 @@ class TestUndefined(object):
with pytest.raises(AttributeError):
getattr(StrictUndefined, "__slots__") # noqa: B009
assert env.from_string('{{ "foo" if false }}').render() == ""
-
- def test_indexing_gives_undefined(self):
- t = Template("{{ var[42].foo }}")
- pytest.raises(UndefinedError, t.render, var=0)
-
- def test_none_gives_proper_error(self):
+
+ def test_indexing_gives_undefined(self):
+ t = Template("{{ var[42].foo }}")
+ pytest.raises(UndefinedError, t.render, var=0)
+
+ def test_none_gives_proper_error(self):
with pytest.raises(UndefinedError, match="'None' has no attribute 'split'"):
Environment().getattr(None, "split")()
-
- def test_object_repr(self):
+
+ def test_object_repr(self):
with pytest.raises(
UndefinedError, match="'int object' has no attribute 'upper'"
):
Undefined(obj=42, name="upper")()
-
-
-class TestLowLevel(object):
- def test_custom_code_generator(self):
- class CustomCodeGenerator(CodeGenerator):
- def visit_Const(self, node, frame=None):
- # This method is pure nonsense, but works fine for testing...
+
+
+class TestLowLevel(object):
+ def test_custom_code_generator(self):
+ class CustomCodeGenerator(CodeGenerator):
+ def visit_Const(self, node, frame=None):
+ # This method is pure nonsense, but works fine for testing...
if node.value == "foo":
self.write(repr("bar"))
- else:
- super(CustomCodeGenerator, self).visit_Const(node, frame)
-
- class CustomEnvironment(Environment):
- code_generator_class = CustomCodeGenerator
-
- env = CustomEnvironment()
- tmpl = env.from_string('{% set foo = "foo" %}{{ foo }}')
+ else:
+ super(CustomCodeGenerator, self).visit_Const(node, frame)
+
+ class CustomEnvironment(Environment):
+ code_generator_class = CustomCodeGenerator
+
+ env = CustomEnvironment()
+ tmpl = env.from_string('{% set foo = "foo" %}{{ foo }}')
assert tmpl.render() == "bar"
-
- def test_custom_context(self):
- class CustomContext(Context):
- def resolve_or_missing(self, key):
+
+ def test_custom_context(self):
+ class CustomContext(Context):
+ def resolve_or_missing(self, key):
return "resolve-" + key
-
- class CustomEnvironment(Environment):
- context_class = CustomContext
-
- env = CustomEnvironment()
+
+ class CustomEnvironment(Environment):
+ context_class = CustomContext
+
+ env = CustomEnvironment()
tmpl = env.from_string("{{ foo }}")
assert tmpl.render() == "resolve-foo"
diff --git a/contrib/python/Jinja2/py2/tests/test_async.py b/contrib/python/Jinja2/py2/tests/test_async.py
index 2b9974e35d..6059c1272a 100644
--- a/contrib/python/Jinja2/py2/tests/test_async.py
+++ b/contrib/python/Jinja2/py2/tests/test_async.py
@@ -1,7 +1,7 @@
-import asyncio
-
+import asyncio
+
import pytest
-
+
from jinja2 import DictLoader
from jinja2 import Environment
from jinja2 import Template
@@ -9,113 +9,113 @@ from jinja2.asyncsupport import auto_aiter
from jinja2.exceptions import TemplateNotFound
from jinja2.exceptions import TemplatesNotFound
from jinja2.exceptions import UndefinedError
-
-
-def run(coro):
- loop = asyncio.get_event_loop()
- return loop.run_until_complete(coro)
-
-
-def test_basic_async():
+
+
+def run(coro):
+ loop = asyncio.get_event_loop()
+ return loop.run_until_complete(coro)
+
+
+def test_basic_async():
t = Template(
"{% for item in [1, 2, 3] %}[{{ item }}]{% endfor %}", enable_async=True
)
- async def func():
- return await t.render_async()
-
- rv = run(func())
+ async def func():
+ return await t.render_async()
+
+ rv = run(func())
assert rv == "[1][2][3]"
-
-
-def test_await_on_calls():
+
+
+def test_await_on_calls():
t = Template("{{ async_func() + normal_func() }}", enable_async=True)
-
- async def async_func():
- return 42
-
- def normal_func():
- return 23
-
- async def func():
+
+ async def async_func():
+ return 42
+
+ def normal_func():
+ return 23
+
+ async def func():
return await t.render_async(async_func=async_func, normal_func=normal_func)
-
- rv = run(func())
+
+ rv = run(func())
assert rv == "65"
-
-
-def test_await_on_calls_normal_render():
+
+
+def test_await_on_calls_normal_render():
t = Template("{{ async_func() + normal_func() }}", enable_async=True)
-
- async def async_func():
- return 42
-
- def normal_func():
- return 23
-
+
+ async def async_func():
+ return 42
+
+ def normal_func():
+ return 23
+
rv = t.render(async_func=async_func, normal_func=normal_func)
-
+
assert rv == "65"
-
-
-def test_await_and_macros():
+
+
+def test_await_and_macros():
t = Template(
"{% macro foo(x) %}[{{ x }}][{{ async_func() }}]{% endmacro %}{{ foo(42) }}",
enable_async=True,
)
-
- async def async_func():
- return 42
-
- async def func():
- return await t.render_async(async_func=async_func)
-
- rv = run(func())
+
+ async def async_func():
+ return 42
+
+ async def func():
+ return await t.render_async(async_func=async_func)
+
+ rv = run(func())
assert rv == "[42][42]"
-
-
-def test_async_blocks():
+
+
+def test_async_blocks():
t = Template(
"{% block foo %}<Test>{% endblock %}{{ self.foo() }}",
enable_async=True,
autoescape=True,
)
- async def func():
- return await t.render_async()
-
- rv = run(func())
+ async def func():
+ return await t.render_async()
+
+ rv = run(func())
assert rv == "<Test><Test>"
-
-
-def test_async_generate():
+
+
+def test_async_generate():
t = Template("{% for x in [1, 2, 3] %}{{ x }}{% endfor %}", enable_async=True)
- rv = list(t.generate())
+ rv = list(t.generate())
assert rv == ["1", "2", "3"]
-
-
-def test_async_iteration_in_templates():
+
+
+def test_async_iteration_in_templates():
t = Template("{% for x in rng %}{{ x }}{% endfor %}", enable_async=True)
- async def async_iterator():
- for item in [1, 2, 3]:
- yield item
+ async def async_iterator():
+ for item in [1, 2, 3]:
+ yield item
- rv = list(t.generate(rng=async_iterator()))
+ rv = list(t.generate(rng=async_iterator()))
assert rv == ["1", "2", "3"]
-
-
-def test_async_iteration_in_templates_extended():
+
+
+def test_async_iteration_in_templates_extended():
t = Template(
"{% for x in rng %}{{ loop.index0 }}/{{ x }}{% endfor %}", enable_async=True
)
stream = t.generate(rng=auto_aiter(range(1, 4)))
assert next(stream) == "0"
assert "".join(stream) == "/11/22/3"
-
-
-@pytest.fixture
-def test_env_async():
+
+
+@pytest.fixture
+def test_env_async():
env = Environment(
loader=DictLoader(
dict(
@@ -127,93 +127,93 @@ def test_env_async():
enable_async=True,
)
env.globals["bar"] = 23
- return env
-
-
-class TestAsyncImports(object):
- def test_context_imports(self, test_env_async):
- t = test_env_async.from_string('{% import "module" as m %}{{ m.test() }}')
+ return env
+
+
+class TestAsyncImports(object):
+ def test_context_imports(self, test_env_async):
+ t = test_env_async.from_string('{% import "module" as m %}{{ m.test() }}')
assert t.render(foo=42) == "[|23]"
- t = test_env_async.from_string(
- '{% import "module" as m without context %}{{ m.test() }}'
- )
+ t = test_env_async.from_string(
+ '{% import "module" as m without context %}{{ m.test() }}'
+ )
assert t.render(foo=42) == "[|23]"
- t = test_env_async.from_string(
- '{% import "module" as m with context %}{{ m.test() }}'
- )
+ t = test_env_async.from_string(
+ '{% import "module" as m with context %}{{ m.test() }}'
+ )
assert t.render(foo=42) == "[42|23]"
- t = test_env_async.from_string('{% from "module" import test %}{{ test() }}')
+ t = test_env_async.from_string('{% from "module" import test %}{{ test() }}')
assert t.render(foo=42) == "[|23]"
- t = test_env_async.from_string(
- '{% from "module" import test without context %}{{ test() }}'
- )
+ t = test_env_async.from_string(
+ '{% from "module" import test without context %}{{ test() }}'
+ )
assert t.render(foo=42) == "[|23]"
- t = test_env_async.from_string(
- '{% from "module" import test with context %}{{ test() }}'
- )
+ t = test_env_async.from_string(
+ '{% from "module" import test with context %}{{ test() }}'
+ )
assert t.render(foo=42) == "[42|23]"
-
- def test_trailing_comma(self, test_env_async):
- test_env_async.from_string('{% from "foo" import bar, baz with context %}')
- test_env_async.from_string('{% from "foo" import bar, baz, with context %}')
- test_env_async.from_string('{% from "foo" import bar, with context %}')
- test_env_async.from_string('{% from "foo" import bar, with, context %}')
- test_env_async.from_string('{% from "foo" import bar, with with context %}')
-
- def test_exports(self, test_env_async):
+
+ def test_trailing_comma(self, test_env_async):
+ test_env_async.from_string('{% from "foo" import bar, baz with context %}')
+ test_env_async.from_string('{% from "foo" import bar, baz, with context %}')
+ test_env_async.from_string('{% from "foo" import bar, with context %}')
+ test_env_async.from_string('{% from "foo" import bar, with, context %}')
+ test_env_async.from_string('{% from "foo" import bar, with with context %}')
+
+ def test_exports(self, test_env_async):
m = run(
test_env_async.from_string(
"""
- {% macro toplevel() %}...{% endmacro %}
- {% macro __private() %}...{% endmacro %}
- {% set variable = 42 %}
- {% for item in [1] %}
- {% macro notthere() %}{% endmacro %}
- {% endfor %}
+ {% macro toplevel() %}...{% endmacro %}
+ {% macro __private() %}...{% endmacro %}
+ {% set variable = 42 %}
+ {% for item in [1] %}
+ {% macro notthere() %}{% endmacro %}
+ {% endfor %}
"""
)._get_default_module_async()
)
assert run(m.toplevel()) == "..."
assert not hasattr(m, "__missing")
- assert m.variable == 42
+ assert m.variable == 42
assert not hasattr(m, "notthere")
-
-
-class TestAsyncIncludes(object):
- def test_context_include(self, test_env_async):
- t = test_env_async.from_string('{% include "header" %}')
+
+
+class TestAsyncIncludes(object):
+ def test_context_include(self, test_env_async):
+ t = test_env_async.from_string('{% include "header" %}')
assert t.render(foo=42) == "[42|23]"
- t = test_env_async.from_string('{% include "header" with context %}')
+ t = test_env_async.from_string('{% include "header" with context %}')
assert t.render(foo=42) == "[42|23]"
- t = test_env_async.from_string('{% include "header" without context %}')
+ t = test_env_async.from_string('{% include "header" without context %}')
assert t.render(foo=42) == "[|23]"
-
- def test_choice_includes(self, test_env_async):
- t = test_env_async.from_string('{% include ["missing", "header"] %}')
+
+ def test_choice_includes(self, test_env_async):
+ t = test_env_async.from_string('{% include ["missing", "header"] %}')
assert t.render(foo=42) == "[42|23]"
-
- t = test_env_async.from_string(
- '{% include ["missing", "missing2"] ignore missing %}'
- )
+
+ t = test_env_async.from_string(
+ '{% include ["missing", "missing2"] ignore missing %}'
+ )
assert t.render(foo=42) == ""
-
- t = test_env_async.from_string('{% include ["missing", "missing2"] %}')
- pytest.raises(TemplateNotFound, t.render)
+
+ t = test_env_async.from_string('{% include ["missing", "missing2"] %}')
+ pytest.raises(TemplateNotFound, t.render)
with pytest.raises(TemplatesNotFound) as e:
- t.render()
-
+ t.render()
+
assert e.value.templates == ["missing", "missing2"]
assert e.value.name == "missing2"
- def test_includes(t, **ctx):
+ def test_includes(t, **ctx):
ctx["foo"] = 42
assert t.render(ctx) == "[42|23]"
-
- t = test_env_async.from_string('{% include ["missing", "header"] %}')
- test_includes(t)
+
+ t = test_env_async.from_string('{% include ["missing", "header"] %}')
+ test_includes(t)
t = test_env_async.from_string("{% include x %}")
test_includes(t, x=["missing", "header"])
- t = test_env_async.from_string('{% include [x, "header"] %}')
+ t = test_env_async.from_string('{% include [x, "header"] %}')
test_includes(t, x="missing")
t = test_env_async.from_string("{% include x %}")
test_includes(t, x="header")
@@ -221,17 +221,17 @@ class TestAsyncIncludes(object):
test_includes(t, x="header")
t = test_env_async.from_string("{% include [x] %}")
test_includes(t, x="header")
-
- def test_include_ignoring_missing(self, test_env_async):
- t = test_env_async.from_string('{% include "missing" %}')
- pytest.raises(TemplateNotFound, t.render)
+
+ def test_include_ignoring_missing(self, test_env_async):
+ t = test_env_async.from_string('{% include "missing" %}')
+ pytest.raises(TemplateNotFound, t.render)
for extra in "", "with context", "without context":
t = test_env_async.from_string(
'{% include "missing" ignore missing ' + extra + " %}"
)
assert t.render() == ""
-
- def test_context_include_with_overrides(self, test_env_async):
+
+ def test_context_include_with_overrides(self, test_env_async):
env = Environment(
loader=DictLoader(
dict(
@@ -240,23 +240,23 @@ class TestAsyncIncludes(object):
)
)
)
- assert env.get_template("main").render() == "123"
-
- def test_unoptimized_scopes(self, test_env_async):
+ assert env.get_template("main").render() == "123"
+
+ def test_unoptimized_scopes(self, test_env_async):
t = test_env_async.from_string(
"""
- {% macro outer(o) %}
- {% macro inner() %}
- {% include "o_printer" %}
- {% endmacro %}
- {{ inner() }}
- {% endmacro %}
- {{ outer("FOO") }}
+ {% macro outer(o) %}
+ {% macro inner() %}
+ {% include "o_printer" %}
+ {% endmacro %}
+ {{ inner() }}
+ {% endmacro %}
+ {{ outer("FOO") }}
"""
)
assert t.render().strip() == "(FOO)"
-
- def test_unoptimized_scopes_autoescape(self):
+
+ def test_unoptimized_scopes_autoescape(self):
env = Environment(
loader=DictLoader(dict(o_printer="({{ o }})",)),
autoescape=True,
@@ -264,35 +264,35 @@ class TestAsyncIncludes(object):
)
t = env.from_string(
"""
- {% macro outer(o) %}
- {% macro inner() %}
- {% include "o_printer" %}
- {% endmacro %}
- {{ inner() }}
- {% endmacro %}
- {{ outer("FOO") }}
+ {% macro outer(o) %}
+ {% macro inner() %}
+ {% include "o_printer" %}
+ {% endmacro %}
+ {{ inner() }}
+ {% endmacro %}
+ {{ outer("FOO") }}
"""
)
assert t.render().strip() == "(FOO)"
-
-
-class TestAsyncForLoop(object):
- def test_simple(self, test_env_async):
+
+
+class TestAsyncForLoop(object):
+ def test_simple(self, test_env_async):
tmpl = test_env_async.from_string("{% for item in seq %}{{ item }}{% endfor %}")
assert tmpl.render(seq=list(range(10))) == "0123456789"
-
- def test_else(self, test_env_async):
- tmpl = test_env_async.from_string(
+
+ def test_else(self, test_env_async):
+ tmpl = test_env_async.from_string(
"{% for item in seq %}XXX{% else %}...{% endfor %}"
)
assert tmpl.render() == "..."
-
- def test_empty_blocks(self, test_env_async):
+
+ def test_empty_blocks(self, test_env_async):
tmpl = test_env_async.from_string(
"<{% for item in seq %}{% else %}{% endfor %}>"
)
assert tmpl.render() == "<>"
-
+
@pytest.mark.parametrize(
"transform", [lambda x: x, iter, reversed, lambda x: (i for i in x), auto_aiter]
)
@@ -304,59 +304,59 @@ class TestAsyncForLoop(object):
)
out = t.render(seq=transform([42, 24]))
assert out == "1|0|2|1|True|False|2\n2|1|1|0|False|True|2\n"
-
- def test_cycling(self, test_env_async):
+
+ def test_cycling(self, test_env_async):
tmpl = test_env_async.from_string(
"""{% for item in seq %}{{
- loop.cycle('<1>', '<2>') }}{% endfor %}{%
+ loop.cycle('<1>', '<2>') }}{% endfor %}{%
for item in seq %}{{ loop.cycle(*through) }}{% endfor %}"""
)
output = tmpl.render(seq=list(range(4)), through=("<1>", "<2>"))
assert output == "<1><2>" * 4
-
- def test_lookaround(self, test_env_async):
+
+ def test_lookaround(self, test_env_async):
tmpl = test_env_async.from_string(
"""{% for item in seq -%}
- {{ loop.previtem|default('x') }}-{{ item }}-{{
- loop.nextitem|default('x') }}|
+ {{ loop.previtem|default('x') }}-{{ item }}-{{
+ loop.nextitem|default('x') }}|
{%- endfor %}"""
)
- output = tmpl.render(seq=list(range(4)))
+ output = tmpl.render(seq=list(range(4)))
assert output == "x-0-1|0-1-2|1-2-3|2-3-x|"
-
- def test_changed(self, test_env_async):
+
+ def test_changed(self, test_env_async):
tmpl = test_env_async.from_string(
"""{% for item in seq -%}
- {{ loop.changed(item) }},
+ {{ loop.changed(item) }},
{%- endfor %}"""
)
- output = tmpl.render(seq=[None, None, 1, 2, 2, 3, 4, 4, 4])
+ output = tmpl.render(seq=[None, None, 1, 2, 2, 3, 4, 4, 4])
assert output == "True,False,True,True,False,True,True,False,False,"
-
- def test_scope(self, test_env_async):
+
+ def test_scope(self, test_env_async):
tmpl = test_env_async.from_string("{% for item in seq %}{% endfor %}{{ item }}")
- output = tmpl.render(seq=list(range(10)))
- assert not output
-
- def test_varlen(self, test_env_async):
- def inner():
- for item in range(5):
- yield item
+ output = tmpl.render(seq=list(range(10)))
+ assert not output
+
+ def test_varlen(self, test_env_async):
+ def inner():
+ for item in range(5):
+ yield item
tmpl = test_env_async.from_string(
"{% for item in iter %}{{ item }}{% endfor %}"
)
- output = tmpl.render(iter=inner())
+ output = tmpl.render(iter=inner())
assert output == "01234"
-
- def test_noniter(self, test_env_async):
+
+ def test_noniter(self, test_env_async):
tmpl = test_env_async.from_string("{% for item in none %}...{% endfor %}")
- pytest.raises(TypeError, tmpl.render)
-
- def test_recursive(self, test_env_async):
+ pytest.raises(TypeError, tmpl.render)
+
+ def test_recursive(self, test_env_async):
tmpl = test_env_async.from_string(
"""{% for item in seq recursive -%}
- [{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
+ [{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
{%- endfor %}"""
)
assert (
@@ -369,13 +369,13 @@ class TestAsyncForLoop(object):
)
== "[1<[1][2]>][2<[1][2]>][3<[a]>]"
)
-
- def test_recursive_lookaround(self, test_env_async):
+
+ def test_recursive_lookaround(self, test_env_async):
tmpl = test_env_async.from_string(
"""{% for item in seq recursive -%}
- [{{ loop.previtem.a if loop.previtem is defined else 'x' }}.{{
- item.a }}.{{ loop.nextitem.a if loop.nextitem is defined else 'x'
- }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
+ [{{ loop.previtem.a if loop.previtem is defined else 'x' }}.{{
+ item.a }}.{{ loop.nextitem.a if loop.nextitem is defined else 'x'
+ }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
{%- endfor %}"""
)
assert (
@@ -388,8 +388,8 @@ class TestAsyncForLoop(object):
)
== "[x.1.2<[x.1.2][1.2.x]>][1.2.3<[x.1.2][1.2.x]>][2.3.x<[x.a.x]>]"
)
-
- def test_recursive_depth0(self, test_env_async):
+
+ def test_recursive_depth0(self, test_env_async):
tmpl = test_env_async.from_string(
"{% for item in seq recursive %}[{{ loop.depth0 }}:{{ item.a }}"
"{% if item.b %}<{{ loop(item.b) }}>{% endif %}]{% endfor %}"
@@ -404,8 +404,8 @@ class TestAsyncForLoop(object):
)
== "[0:1<[1:1][1:2]>][0:2<[1:1][1:2]>][0:3<[1:a]>]"
)
-
- def test_recursive_depth(self, test_env_async):
+
+ def test_recursive_depth(self, test_env_async):
tmpl = test_env_async.from_string(
"{% for item in seq recursive %}[{{ loop.depth }}:{{ item.a }}"
"{% if item.b %}<{{ loop(item.b) }}>{% endif %}]{% endfor %}"
@@ -420,58 +420,58 @@ class TestAsyncForLoop(object):
)
== "[1:1<[2:1][2:2]>][1:2<[2:1][2:2]>][1:3<[2:a]>]"
)
-
- def test_looploop(self, test_env_async):
+
+ def test_looploop(self, test_env_async):
tmpl = test_env_async.from_string(
"""{% for row in table %}
- {%- set rowloop = loop -%}
- {% for cell in row -%}
- [{{ rowloop.index }}|{{ loop.index }}]
- {%- endfor %}
+ {%- set rowloop = loop -%}
+ {% for cell in row -%}
+ [{{ rowloop.index }}|{{ loop.index }}]
+ {%- endfor %}
{%- endfor %}"""
)
assert tmpl.render(table=["ab", "cd"]) == "[1|1][1|2][2|1][2|2]"
-
- def test_reversed_bug(self, test_env_async):
+
+ def test_reversed_bug(self, test_env_async):
tmpl = test_env_async.from_string(
"{% for i in items %}{{ i }}"
"{% if not loop.last %}"
",{% endif %}{% endfor %}"
)
assert tmpl.render(items=reversed([3, 2, 1])) == "1,2,3"
-
- def test_loop_errors(self, test_env_async):
+
+ def test_loop_errors(self, test_env_async):
tmpl = test_env_async.from_string(
"""{% for item in [1] if loop.index
== 0 %}...{% endfor %}"""
)
- pytest.raises(UndefinedError, tmpl.render)
+ pytest.raises(UndefinedError, tmpl.render)
tmpl = test_env_async.from_string(
"""{% for item in [] %}...{% else
%}{{ loop }}{% endfor %}"""
)
assert tmpl.render() == ""
-
- def test_loop_filter(self, test_env_async):
+
+ def test_loop_filter(self, test_env_async):
tmpl = test_env_async.from_string(
"{% for item in range(10) if item is even %}[{{ item }}]{% endfor %}"
)
assert tmpl.render() == "[0][2][4][6][8]"
tmpl = test_env_async.from_string(
"""
- {%- for item in range(10) if item is even %}[{{
+ {%- for item in range(10) if item is even %}[{{
loop.index }}:{{ item }}]{% endfor %}"""
)
assert tmpl.render() == "[1:0][2:2][3:4][4:6][5:8]"
-
- def test_scoped_special_var(self, test_env_async):
- t = test_env_async.from_string(
+
+ def test_scoped_special_var(self, test_env_async):
+ t = test_env_async.from_string(
"{% for s in seq %}[{{ loop.first }}{% for c in s %}"
"|{{ loop.first }}{% endfor %}]{% endfor %}"
)
assert t.render(seq=("ab", "cd")) == "[True|True|False][False|True|False]"
-
- def test_scoped_loop_var(self, test_env_async):
+
+ def test_scoped_loop_var(self, test_env_async):
t = test_env_async.from_string(
"{% for x in seq %}{{ loop.first }}"
"{% for y in seq %}{% endfor %}{% endfor %}"
@@ -482,97 +482,97 @@ class TestAsyncForLoop(object):
"{{ loop.first }}{% endfor %}{% endfor %}"
)
assert t.render(seq="ab") == "TrueFalseTrueFalse"
-
- def test_recursive_empty_loop_iter(self, test_env_async):
+
+ def test_recursive_empty_loop_iter(self, test_env_async):
t = test_env_async.from_string(
"""
- {%- for item in foo recursive -%}{%- endfor -%}
+ {%- for item in foo recursive -%}{%- endfor -%}
"""
)
assert t.render(dict(foo=[])) == ""
-
- def test_call_in_loop(self, test_env_async):
+
+ def test_call_in_loop(self, test_env_async):
t = test_env_async.from_string(
"""
- {%- macro do_something() -%}
- [{{ caller() }}]
- {%- endmacro %}
-
- {%- for i in [1, 2, 3] %}
- {%- call do_something() -%}
- {{ i }}
- {%- endcall %}
- {%- endfor -%}
+ {%- macro do_something() -%}
+ [{{ caller() }}]
+ {%- endmacro %}
+
+ {%- for i in [1, 2, 3] %}
+ {%- call do_something() -%}
+ {{ i }}
+ {%- endcall %}
+ {%- endfor -%}
"""
)
assert t.render() == "[1][2][3]"
-
- def test_scoping_bug(self, test_env_async):
+
+ def test_scoping_bug(self, test_env_async):
t = test_env_async.from_string(
"""
- {%- for item in foo %}...{{ item }}...{% endfor %}
- {%- macro item(a) %}...{{ a }}...{% endmacro %}
- {{- item(2) -}}
+ {%- for item in foo %}...{{ item }}...{% endfor %}
+ {%- macro item(a) %}...{{ a }}...{% endmacro %}
+ {{- item(2) -}}
"""
)
assert t.render(foo=(1,)) == "...1......2..."
-
- def test_unpacking(self, test_env_async):
+
+ def test_unpacking(self, test_env_async):
tmpl = test_env_async.from_string(
"{% for a, b, c in [[1, 2, 3]] %}{{ a }}|{{ b }}|{{ c }}{% endfor %}"
)
assert tmpl.render() == "1|2|3"
-
- def test_recursive_loop_filter(self, test_env_async):
+
+ def test_recursive_loop_filter(self, test_env_async):
t = test_env_async.from_string(
"""
- <?xml version="1.0" encoding="UTF-8"?>
- <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
- {%- for page in [site.root] if page.url != this recursive %}
- <url><loc>{{ page.url }}</loc></url>
- {{- loop(page.children) }}
- {%- endfor %}
- </urlset>
+ <?xml version="1.0" encoding="UTF-8"?>
+ <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
+ {%- for page in [site.root] if page.url != this recursive %}
+ <url><loc>{{ page.url }}</loc></url>
+ {{- loop(page.children) }}
+ {%- endfor %}
+ </urlset>
"""
)
sm = t.render(
this="/foo",
site={"root": {"url": "/", "children": [{"url": "/foo"}, {"url": "/bar"}]}},
)
- lines = [x.strip() for x in sm.splitlines() if x.strip()]
- assert lines == [
- '<?xml version="1.0" encoding="UTF-8"?>',
- '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
+ lines = [x.strip() for x in sm.splitlines() if x.strip()]
+ assert lines == [
+ '<?xml version="1.0" encoding="UTF-8"?>',
+ '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
"<url><loc>/</loc></url>",
"<url><loc>/bar</loc></url>",
"</urlset>",
- ]
-
- def test_nonrecursive_loop_filter(self, test_env_async):
+ ]
+
+ def test_nonrecursive_loop_filter(self, test_env_async):
t = test_env_async.from_string(
"""
- <?xml version="1.0" encoding="UTF-8"?>
- <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
- {%- for page in items if page.url != this %}
- <url><loc>{{ page.url }}</loc></url>
- {%- endfor %}
- </urlset>
+ <?xml version="1.0" encoding="UTF-8"?>
+ <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
+ {%- for page in items if page.url != this %}
+ <url><loc>{{ page.url }}</loc></url>
+ {%- endfor %}
+ </urlset>
"""
)
sm = t.render(
this="/foo", items=[{"url": "/"}, {"url": "/foo"}, {"url": "/bar"}]
)
- lines = [x.strip() for x in sm.splitlines() if x.strip()]
- assert lines == [
- '<?xml version="1.0" encoding="UTF-8"?>',
- '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
+ lines = [x.strip() for x in sm.splitlines() if x.strip()]
+ assert lines == [
+ '<?xml version="1.0" encoding="UTF-8"?>',
+ '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
"<url><loc>/</loc></url>",
"<url><loc>/bar</loc></url>",
"</urlset>",
- ]
-
- def test_bare_async(self, test_env_async):
- t = test_env_async.from_string('{% extends "header" %}')
+ ]
+
+ def test_bare_async(self, test_env_async):
+ t = test_env_async.from_string('{% extends "header" %}')
assert t.render(foo=42) == "[42|23]"
def test_awaitable_property_slicing(self, test_env_async):
diff --git a/contrib/python/Jinja2/py2/tests/test_asyncfilters.py b/contrib/python/Jinja2/py2/tests/test_asyncfilters.py
index 7c737c835e..85c206be9d 100644
--- a/contrib/python/Jinja2/py2/tests/test_asyncfilters.py
+++ b/contrib/python/Jinja2/py2/tests/test_asyncfilters.py
@@ -1,37 +1,37 @@
from collections import namedtuple
-import pytest
-
-from jinja2 import Environment
-from jinja2.utils import Markup
-
-
-async def make_aiter(iter):
- for item in iter:
- yield item
-
-
-def mark_dualiter(parameter, factory):
- def decorator(f):
+import pytest
+
+from jinja2 import Environment
+from jinja2.utils import Markup
+
+
+async def make_aiter(iter):
+ for item in iter:
+ yield item
+
+
+def mark_dualiter(parameter, factory):
+ def decorator(f):
return pytest.mark.parametrize(
parameter, [lambda: factory(), lambda: make_aiter(factory())]
)(f)
- return decorator
-
-
-@pytest.fixture
-def env_async():
- return Environment(enable_async=True)
-
-
+ return decorator
+
+
+@pytest.fixture
+def env_async():
+ return Environment(enable_async=True)
+
+
@mark_dualiter("foo", lambda: range(10))
-def test_first(env_async, foo):
+def test_first(env_async, foo):
tmpl = env_async.from_string("{{ foo()|first }}")
- out = tmpl.render(foo=foo)
+ out = tmpl.render(foo=foo)
assert out == "0"
-
-
+
+
@mark_dualiter(
"items",
lambda: [
@@ -41,159 +41,159 @@ def test_first(env_async, foo):
{"foo": 3, "bar": 4},
],
)
-def test_groupby(env_async, items):
+def test_groupby(env_async, items):
tmpl = env_async.from_string(
"""
- {%- for grouper, list in items()|groupby('foo') -%}
- {{ grouper }}{% for x in list %}: {{ x.foo }}, {{ x.bar }}{% endfor %}|
+ {%- for grouper, list in items()|groupby('foo') -%}
+ {{ grouper }}{% for x in list %}: {{ x.foo }}, {{ x.bar }}{% endfor %}|
{%- endfor %}"""
)
assert tmpl.render(items=items).split("|") == [
- "1: 1, 2: 1, 1",
- "2: 2, 3",
- "3: 3, 4",
+ "1: 1, 2: 1, 1",
+ "2: 2, 3",
+ "3: 3, 4",
"",
- ]
-
-
+ ]
+
+
@mark_dualiter("items", lambda: [("a", 1), ("a", 2), ("b", 1)])
-def test_groupby_tuple_index(env_async, items):
+def test_groupby_tuple_index(env_async, items):
tmpl = env_async.from_string(
"""
- {%- for grouper, list in items()|groupby(0) -%}
- {{ grouper }}{% for x in list %}:{{ x.1 }}{% endfor %}|
+ {%- for grouper, list in items()|groupby(0) -%}
+ {{ grouper }}{% for x in list %}:{{ x.1 }}{% endfor %}|
{%- endfor %}"""
)
assert tmpl.render(items=items) == "a:1:2|b:1|"
-
-
-def make_articles():
+
+
+def make_articles():
Date = namedtuple("Date", "day,month,year")
Article = namedtuple("Article", "title,date")
- return [
+ return [
Article("aha", Date(1, 1, 1970)),
Article("interesting", Date(2, 1, 1970)),
Article("really?", Date(3, 1, 1970)),
Article("totally not", Date(1, 1, 1971)),
- ]
-
-
+ ]
+
+
@mark_dualiter("articles", make_articles)
-def test_groupby_multidot(env_async, articles):
+def test_groupby_multidot(env_async, articles):
tmpl = env_async.from_string(
"""
- {%- for year, list in articles()|groupby('date.year') -%}
- {{ year }}{% for x in list %}[{{ x.title }}]{% endfor %}|
+ {%- for year, list in articles()|groupby('date.year') -%}
+ {{ year }}{% for x in list %}[{{ x.title }}]{% endfor %}|
{%- endfor %}"""
)
assert tmpl.render(articles=articles).split("|") == [
"1970[aha][interesting][really?]",
"1971[totally not]",
"",
- ]
-
-
+ ]
+
+
@mark_dualiter("int_items", lambda: [1, 2, 3])
def test_join_env_int(env_async, int_items):
- tmpl = env_async.from_string('{{ items()|join("|") }}')
- out = tmpl.render(items=int_items)
+ tmpl = env_async.from_string('{{ items()|join("|") }}')
+ out = tmpl.render(items=int_items)
assert out == "1|2|3"
-
-
+
+
@mark_dualiter("string_items", lambda: ["<foo>", Markup("<span>foo</span>")])
def test_join_string_list(string_items):
- env2 = Environment(autoescape=True, enable_async=True)
+ env2 = Environment(autoescape=True, enable_async=True)
tmpl = env2.from_string('{{ ["<foo>", "<span>foo</span>"|safe]|join }}')
assert tmpl.render(items=string_items) == "&lt;foo&gt;<span>foo</span>"
-
-
-def make_users():
+
+
+def make_users():
User = namedtuple("User", "username")
return map(User, ["foo", "bar"])
-
-
+
+
@mark_dualiter("users", make_users)
-def test_join_attribute(env_async, users):
+def test_join_attribute(env_async, users):
tmpl = env_async.from_string("""{{ users()|join(', ', 'username') }}""")
assert tmpl.render(users=users) == "foo, bar"
-
-
+
+
@mark_dualiter("items", lambda: [1, 2, 3, 4, 5])
-def test_simple_reject(env_async, items):
- tmpl = env_async.from_string('{{ items()|reject("odd")|join("|") }}')
+def test_simple_reject(env_async, items):
+ tmpl = env_async.from_string('{{ items()|reject("odd")|join("|") }}')
assert tmpl.render(items=items) == "2|4"
-
-
+
+
@mark_dualiter("items", lambda: [None, False, 0, 1, 2, 3, 4, 5])
-def test_bool_reject(env_async, items):
+def test_bool_reject(env_async, items):
tmpl = env_async.from_string('{{ items()|reject|join("|") }}')
assert tmpl.render(items=items) == "None|False|0"
-
-
+
+
@mark_dualiter("items", lambda: [1, 2, 3, 4, 5])
-def test_simple_select(env_async, items):
- tmpl = env_async.from_string('{{ items()|select("odd")|join("|") }}')
+def test_simple_select(env_async, items):
+ tmpl = env_async.from_string('{{ items()|select("odd")|join("|") }}')
assert tmpl.render(items=items) == "1|3|5"
-
-
+
+
@mark_dualiter("items", lambda: [None, False, 0, 1, 2, 3, 4, 5])
-def test_bool_select(env_async, items):
+def test_bool_select(env_async, items):
tmpl = env_async.from_string('{{ items()|select|join("|") }}')
assert tmpl.render(items=items) == "1|2|3|4|5"
-
-
-def make_users():
+
+
+def make_users():
User = namedtuple("User", "name,is_active")
- return [
+ return [
User("john", True),
User("jane", True),
User("mike", False),
- ]
-
-
+ ]
+
+
@mark_dualiter("users", make_users)
-def test_simple_select_attr(env_async, users):
- tmpl = env_async.from_string(
+def test_simple_select_attr(env_async, users):
+ tmpl = env_async.from_string(
'{{ users()|selectattr("is_active")|map(attribute="name")|join("|") }}'
- )
+ )
assert tmpl.render(users=users) == "john|jane"
-
-
+
+
@mark_dualiter("items", lambda: list("123"))
-def test_simple_map(env_async, items):
- tmpl = env_async.from_string('{{ items()|map("int")|sum }}')
+def test_simple_map(env_async, items):
+ tmpl = env_async.from_string('{{ items()|map("int")|sum }}')
assert tmpl.render(items=items) == "6"
-
-
+
+
def test_map_sum(env_async): # async map + async filter
tmpl = env_async.from_string('{{ [[1,2], [3], [4,5,6]]|map("sum")|list }}')
assert tmpl.render() == "[3, 3, 15]"
@mark_dualiter("users", make_users)
-def test_attribute_map(env_async, users):
- tmpl = env_async.from_string('{{ users()|map(attribute="name")|join("|") }}')
+def test_attribute_map(env_async, users):
+ tmpl = env_async.from_string('{{ users()|map(attribute="name")|join("|") }}')
assert tmpl.render(users=users) == "john|jane|mike"
-
-
-def test_empty_map(env_async):
- tmpl = env_async.from_string('{{ none|map("upper")|list }}')
+
+
+def test_empty_map(env_async):
+ tmpl = env_async.from_string('{{ none|map("upper")|list }}')
assert tmpl.render() == "[]"
-
-
+
+
@mark_dualiter("items", lambda: [1, 2, 3, 4, 5, 6])
-def test_sum(env_async, items):
+def test_sum(env_async, items):
tmpl = env_async.from_string("""{{ items()|sum }}""")
assert tmpl.render(items=items) == "21"
-
-
+
+
@mark_dualiter("items", lambda: [{"value": 23}, {"value": 1}, {"value": 18}])
-def test_sum_attributes(env_async, items):
+def test_sum_attributes(env_async, items):
tmpl = env_async.from_string("""{{ items()|sum('value') }}""")
- assert tmpl.render(items=items)
-
-
-def test_sum_attributes_nested(env_async):
+ assert tmpl.render(items=items)
+
+
+def test_sum_attributes_nested(env_async):
tmpl = env_async.from_string("""{{ values|sum('real.value') }}""")
assert (
tmpl.render(
@@ -205,19 +205,19 @@ def test_sum_attributes_nested(env_async):
)
== "42"
)
-
-
-def test_sum_attributes_tuple(env_async):
+
+
+def test_sum_attributes_tuple(env_async):
tmpl = env_async.from_string("""{{ values.items()|sum('1') }}""")
assert tmpl.render(values={"foo": 23, "bar": 1, "baz": 18}) == "42"
-
-
+
+
@mark_dualiter("items", lambda: range(10))
-def test_slice(env_async, items):
+def test_slice(env_async, items):
tmpl = env_async.from_string(
"{{ items()|slice(3)|list }}|{{ items()|slice(3, 'X')|list }}"
)
- out = tmpl.render(items=items)
+ out = tmpl.render(items=items)
assert out == (
"[[0, 1, 2, 3], [4, 5, 6], [7, 8, 9]]|"
"[[0, 1, 2, 3], [4, 5, 6, 'X'], [7, 8, 9, 'X']]"
diff --git a/contrib/python/Jinja2/py2/tests/test_bytecode_cache.py b/contrib/python/Jinja2/py2/tests/test_bytecode_cache.py
index c7882b1a2d..9a98dc4baa 100644
--- a/contrib/python/Jinja2/py2/tests/test_bytecode_cache.py
+++ b/contrib/python/Jinja2/py2/tests/test_bytecode_cache.py
@@ -1,78 +1,78 @@
-# -*- coding: utf-8 -*-
-import pytest
-
-from jinja2 import Environment
+# -*- coding: utf-8 -*-
+import pytest
+
+from jinja2 import Environment
from jinja2.bccache import Bucket
from jinja2.bccache import FileSystemBytecodeCache
from jinja2.bccache import MemcachedBytecodeCache
-from jinja2.exceptions import TemplateNotFound
-
-
-@pytest.fixture
+from jinja2.exceptions import TemplateNotFound
+
+
+@pytest.fixture
def env(package_loader, tmp_path):
bytecode_cache = FileSystemBytecodeCache(str(tmp_path))
return Environment(loader=package_loader, bytecode_cache=bytecode_cache)
-
-
-class TestByteCodeCache(object):
- def test_simple(self, env):
+
+
+class TestByteCodeCache(object):
+ def test_simple(self, env):
tmpl = env.get_template("test.html")
assert tmpl.render().strip() == "BAR"
pytest.raises(TemplateNotFound, env.get_template, "missing.html")
-
-
-class MockMemcached(object):
- class Error(Exception):
- pass
-
- key = None
- value = None
- timeout = None
-
- def get(self, key):
- return self.value
-
- def set(self, key, value, timeout=None):
- self.key = key
- self.value = value
- self.timeout = timeout
-
- def get_side_effect(self, key):
- raise self.Error()
-
- def set_side_effect(self, *args):
- raise self.Error()
-
-
-class TestMemcachedBytecodeCache(object):
- def test_dump_load(self):
- memcached = MockMemcached()
- m = MemcachedBytecodeCache(memcached)
-
+
+
+class MockMemcached(object):
+ class Error(Exception):
+ pass
+
+ key = None
+ value = None
+ timeout = None
+
+ def get(self, key):
+ return self.value
+
+ def set(self, key, value, timeout=None):
+ self.key = key
+ self.value = value
+ self.timeout = timeout
+
+ def get_side_effect(self, key):
+ raise self.Error()
+
+ def set_side_effect(self, *args):
+ raise self.Error()
+
+
+class TestMemcachedBytecodeCache(object):
+ def test_dump_load(self):
+ memcached = MockMemcached()
+ m = MemcachedBytecodeCache(memcached)
+
b = Bucket(None, "key", "")
b.code = "code"
- m.dump_bytecode(b)
+ m.dump_bytecode(b)
assert memcached.key == "jinja2/bytecode/key"
-
+
b = Bucket(None, "key", "")
- m.load_bytecode(b)
+ m.load_bytecode(b)
assert b.code == "code"
-
- def test_exception(self):
- memcached = MockMemcached()
- memcached.get = memcached.get_side_effect
- memcached.set = memcached.set_side_effect
- m = MemcachedBytecodeCache(memcached)
+
+ def test_exception(self):
+ memcached = MockMemcached()
+ memcached.get = memcached.get_side_effect
+ memcached.set = memcached.set_side_effect
+ m = MemcachedBytecodeCache(memcached)
b = Bucket(None, "key", "")
b.code = "code"
-
- m.dump_bytecode(b)
- m.load_bytecode(b)
-
- m.ignore_memcache_errors = False
-
- with pytest.raises(MockMemcached.Error):
- m.dump_bytecode(b)
-
- with pytest.raises(MockMemcached.Error):
- m.load_bytecode(b)
+
+ m.dump_bytecode(b)
+ m.load_bytecode(b)
+
+ m.ignore_memcache_errors = False
+
+ with pytest.raises(MockMemcached.Error):
+ m.dump_bytecode(b)
+
+ with pytest.raises(MockMemcached.Error):
+ m.load_bytecode(b)
diff --git a/contrib/python/Jinja2/py2/tests/test_core_tags.py b/contrib/python/Jinja2/py2/tests/test_core_tags.py
index 1bd96c41e9..0c4f4ac0ba 100644
--- a/contrib/python/Jinja2/py2/tests/test_core_tags.py
+++ b/contrib/python/Jinja2/py2/tests/test_core_tags.py
@@ -1,42 +1,42 @@
-# -*- coding: utf-8 -*-
+# -*- coding: utf-8 -*-
import pytest
-
+
from jinja2 import DictLoader
from jinja2 import Environment
from jinja2 import TemplateRuntimeError
from jinja2 import TemplateSyntaxError
from jinja2 import UndefinedError
-
-
-@pytest.fixture
-def env_trim():
- return Environment(trim_blocks=True)
-
-
-class TestForLoop(object):
- def test_simple(self, env):
+
+
+@pytest.fixture
+def env_trim():
+ return Environment(trim_blocks=True)
+
+
+class TestForLoop(object):
+ def test_simple(self, env):
tmpl = env.from_string("{% for item in seq %}{{ item }}{% endfor %}")
assert tmpl.render(seq=list(range(10))) == "0123456789"
-
- def test_else(self, env):
+
+ def test_else(self, env):
tmpl = env.from_string("{% for item in seq %}XXX{% else %}...{% endfor %}")
assert tmpl.render() == "..."
-
- def test_else_scoping_item(self, env):
+
+ def test_else_scoping_item(self, env):
tmpl = env.from_string("{% for item in [] %}{% else %}{{ item }}{% endfor %}")
assert tmpl.render(item=42) == "42"
-
- def test_empty_blocks(self, env):
+
+ def test_empty_blocks(self, env):
tmpl = env.from_string("<{% for item in seq %}{% else %}{% endfor %}>")
assert tmpl.render() == "<>"
-
- def test_context_vars(self, env):
- slist = [42, 24]
- for seq in [slist, iter(slist), reversed(slist), (_ for _ in slist)]:
+
+ def test_context_vars(self, env):
+ slist = [42, 24]
+ for seq in [slist, iter(slist), reversed(slist), (_ for _ in slist)]:
tmpl = env.from_string(
"""{% for item in seq -%}
- {{ loop.index }}|{{ loop.index0 }}|{{ loop.revindex }}|{{
- loop.revindex0 }}|{{ loop.first }}|{{ loop.last }}|{{
+ {{ loop.index }}|{{ loop.index0 }}|{{ loop.revindex }}|{{
+ loop.revindex0 }}|{{ loop.first }}|{{ loop.last }}|{{
loop.length }}###{% endfor %}"""
)
one, two, _ = tmpl.render(seq=seq).split("###")
@@ -58,65 +58,65 @@ class TestForLoop(object):
two_last,
two_length,
) = two.split("|")
-
- assert int(one_index) == 1 and int(two_index) == 2
- assert int(one_index0) == 0 and int(two_index0) == 1
- assert int(one_revindex) == 2 and int(two_revindex) == 1
- assert int(one_revindex0) == 1 and int(two_revindex0) == 0
+
+ assert int(one_index) == 1 and int(two_index) == 2
+ assert int(one_index0) == 0 and int(two_index0) == 1
+ assert int(one_revindex) == 2 and int(two_revindex) == 1
+ assert int(one_revindex0) == 1 and int(two_revindex0) == 0
assert one_first == "True" and two_first == "False"
assert one_last == "False" and two_last == "True"
assert one_length == two_length == "2"
-
- def test_cycling(self, env):
+
+ def test_cycling(self, env):
tmpl = env.from_string(
"""{% for item in seq %}{{
- loop.cycle('<1>', '<2>') }}{% endfor %}{%
+ loop.cycle('<1>', '<2>') }}{% endfor %}{%
for item in seq %}{{ loop.cycle(*through) }}{% endfor %}"""
)
output = tmpl.render(seq=list(range(4)), through=("<1>", "<2>"))
assert output == "<1><2>" * 4
-
- def test_lookaround(self, env):
+
+ def test_lookaround(self, env):
tmpl = env.from_string(
"""{% for item in seq -%}
- {{ loop.previtem|default('x') }}-{{ item }}-{{
- loop.nextitem|default('x') }}|
+ {{ loop.previtem|default('x') }}-{{ item }}-{{
+ loop.nextitem|default('x') }}|
{%- endfor %}"""
)
- output = tmpl.render(seq=list(range(4)))
+ output = tmpl.render(seq=list(range(4)))
assert output == "x-0-1|0-1-2|1-2-3|2-3-x|"
-
- def test_changed(self, env):
+
+ def test_changed(self, env):
tmpl = env.from_string(
"""{% for item in seq -%}
- {{ loop.changed(item) }},
+ {{ loop.changed(item) }},
{%- endfor %}"""
)
- output = tmpl.render(seq=[None, None, 1, 2, 2, 3, 4, 4, 4])
+ output = tmpl.render(seq=[None, None, 1, 2, 2, 3, 4, 4, 4])
assert output == "True,False,True,True,False,True,True,False,False,"
-
- def test_scope(self, env):
+
+ def test_scope(self, env):
tmpl = env.from_string("{% for item in seq %}{% endfor %}{{ item }}")
- output = tmpl.render(seq=list(range(10)))
- assert not output
-
- def test_varlen(self, env):
- def inner():
- for item in range(5):
- yield item
+ output = tmpl.render(seq=list(range(10)))
+ assert not output
+
+ def test_varlen(self, env):
+ def inner():
+ for item in range(5):
+ yield item
tmpl = env.from_string("{% for item in iter %}{{ item }}{% endfor %}")
- output = tmpl.render(iter=inner())
+ output = tmpl.render(iter=inner())
assert output == "01234"
-
- def test_noniter(self, env):
+
+ def test_noniter(self, env):
tmpl = env.from_string("{% for item in none %}...{% endfor %}")
- pytest.raises(TypeError, tmpl.render)
-
- def test_recursive(self, env):
+ pytest.raises(TypeError, tmpl.render)
+
+ def test_recursive(self, env):
tmpl = env.from_string(
"""{% for item in seq recursive -%}
- [{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
+ [{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
{%- endfor %}"""
)
assert (
@@ -129,13 +129,13 @@ class TestForLoop(object):
)
== "[1<[1][2]>][2<[1][2]>][3<[a]>]"
)
-
- def test_recursive_lookaround(self, env):
+
+ def test_recursive_lookaround(self, env):
tmpl = env.from_string(
"""{% for item in seq recursive -%}
- [{{ loop.previtem.a if loop.previtem is defined else 'x' }}.{{
- item.a }}.{{ loop.nextitem.a if loop.nextitem is defined else 'x'
- }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
+ [{{ loop.previtem.a if loop.previtem is defined else 'x' }}.{{
+ item.a }}.{{ loop.nextitem.a if loop.nextitem is defined else 'x'
+ }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
{%- endfor %}"""
)
assert (
@@ -148,8 +148,8 @@ class TestForLoop(object):
)
== "[x.1.2<[x.1.2][1.2.x]>][1.2.3<[x.1.2][1.2.x]>][2.3.x<[x.a.x]>]"
)
-
- def test_recursive_depth0(self, env):
+
+ def test_recursive_depth0(self, env):
tmpl = env.from_string(
"""{% for item in seq recursive -%}
[{{ loop.depth0 }}:{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
@@ -165,8 +165,8 @@ class TestForLoop(object):
)
== "[0:1<[1:1][1:2]>][0:2<[1:1][1:2]>][0:3<[1:a]>]"
)
-
- def test_recursive_depth(self, env):
+
+ def test_recursive_depth(self, env):
tmpl = env.from_string(
"""{% for item in seq recursive -%}
[{{ loop.depth }}:{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
@@ -182,63 +182,63 @@ class TestForLoop(object):
)
== "[1:1<[2:1][2:2]>][1:2<[2:1][2:2]>][1:3<[2:a]>]"
)
-
- def test_looploop(self, env):
+
+ def test_looploop(self, env):
tmpl = env.from_string(
"""{% for row in table %}
- {%- set rowloop = loop -%}
- {% for cell in row -%}
- [{{ rowloop.index }}|{{ loop.index }}]
- {%- endfor %}
+ {%- set rowloop = loop -%}
+ {% for cell in row -%}
+ [{{ rowloop.index }}|{{ loop.index }}]
+ {%- endfor %}
{%- endfor %}"""
)
assert tmpl.render(table=["ab", "cd"]) == "[1|1][1|2][2|1][2|2]"
-
- def test_reversed_bug(self, env):
+
+ def test_reversed_bug(self, env):
tmpl = env.from_string(
"{% for i in items %}{{ i }}"
"{% if not loop.last %}"
",{% endif %}{% endfor %}"
)
assert tmpl.render(items=reversed([3, 2, 1])) == "1,2,3"
-
- def test_loop_errors(self, env):
+
+ def test_loop_errors(self, env):
tmpl = env.from_string(
"""{% for item in [1] if loop.index
== 0 %}...{% endfor %}"""
)
- pytest.raises(UndefinedError, tmpl.render)
+ pytest.raises(UndefinedError, tmpl.render)
tmpl = env.from_string(
"""{% for item in [] %}...{% else
%}{{ loop }}{% endfor %}"""
)
assert tmpl.render() == ""
-
- def test_loop_filter(self, env):
+
+ def test_loop_filter(self, env):
tmpl = env.from_string(
"{% for item in range(10) if item is even %}[{{ item }}]{% endfor %}"
)
assert tmpl.render() == "[0][2][4][6][8]"
tmpl = env.from_string(
"""
- {%- for item in range(10) if item is even %}[{{
+ {%- for item in range(10) if item is even %}[{{
loop.index }}:{{ item }}]{% endfor %}"""
)
assert tmpl.render() == "[1:0][2:2][3:4][4:6][5:8]"
-
- def test_loop_unassignable(self, env):
+
+ def test_loop_unassignable(self, env):
pytest.raises(
TemplateSyntaxError, env.from_string, "{% for loop in seq %}...{% endfor %}"
)
-
- def test_scoped_special_var(self, env):
- t = env.from_string(
+
+ def test_scoped_special_var(self, env):
+ t = env.from_string(
"{% for s in seq %}[{{ loop.first }}{% for c in s %}"
"|{{ loop.first }}{% endfor %}]{% endfor %}"
)
assert t.render(seq=("ab", "cd")) == "[True|True|False][False|True|False]"
-
- def test_scoped_loop_var(self, env):
+
+ def test_scoped_loop_var(self, env):
t = env.from_string(
"{% for x in seq %}{{ loop.first }}"
"{% for y in seq %}{% endfor %}{% endfor %}"
@@ -249,278 +249,278 @@ class TestForLoop(object):
"{{ loop.first }}{% endfor %}{% endfor %}"
)
assert t.render(seq="ab") == "TrueFalseTrueFalse"
-
- def test_recursive_empty_loop_iter(self, env):
+
+ def test_recursive_empty_loop_iter(self, env):
t = env.from_string(
"""
- {%- for item in foo recursive -%}{%- endfor -%}
+ {%- for item in foo recursive -%}{%- endfor -%}
"""
)
assert t.render(dict(foo=[])) == ""
-
- def test_call_in_loop(self, env):
+
+ def test_call_in_loop(self, env):
t = env.from_string(
"""
- {%- macro do_something() -%}
- [{{ caller() }}]
- {%- endmacro %}
-
- {%- for i in [1, 2, 3] %}
- {%- call do_something() -%}
- {{ i }}
- {%- endcall %}
- {%- endfor -%}
+ {%- macro do_something() -%}
+ [{{ caller() }}]
+ {%- endmacro %}
+
+ {%- for i in [1, 2, 3] %}
+ {%- call do_something() -%}
+ {{ i }}
+ {%- endcall %}
+ {%- endfor -%}
"""
)
assert t.render() == "[1][2][3]"
-
- def test_scoping_bug(self, env):
+
+ def test_scoping_bug(self, env):
t = env.from_string(
"""
- {%- for item in foo %}...{{ item }}...{% endfor %}
- {%- macro item(a) %}...{{ a }}...{% endmacro %}
- {{- item(2) -}}
+ {%- for item in foo %}...{{ item }}...{% endfor %}
+ {%- macro item(a) %}...{{ a }}...{% endmacro %}
+ {{- item(2) -}}
"""
)
assert t.render(foo=(1,)) == "...1......2..."
-
- def test_unpacking(self, env):
+
+ def test_unpacking(self, env):
tmpl = env.from_string(
"{% for a, b, c in [[1, 2, 3]] %}{{ a }}|{{ b }}|{{ c }}{% endfor %}"
)
assert tmpl.render() == "1|2|3"
-
- def test_intended_scoping_with_set(self, env):
+
+ def test_intended_scoping_with_set(self, env):
tmpl = env.from_string(
"{% for item in seq %}{{ x }}{% set x = item %}{{ x }}{% endfor %}"
)
assert tmpl.render(x=0, seq=[1, 2, 3]) == "010203"
-
+
tmpl = env.from_string(
"{% set x = 9 %}{% for item in seq %}{{ x }}"
"{% set x = item %}{{ x }}{% endfor %}"
)
assert tmpl.render(x=0, seq=[1, 2, 3]) == "919293"
-
-
-class TestIfCondition(object):
- def test_simple(self, env):
+
+
+class TestIfCondition(object):
+ def test_simple(self, env):
tmpl = env.from_string("""{% if true %}...{% endif %}""")
assert tmpl.render() == "..."
-
- def test_elif(self, env):
+
+ def test_elif(self, env):
tmpl = env.from_string(
"""{% if false %}XXX{% elif true
%}...{% else %}XXX{% endif %}"""
)
assert tmpl.render() == "..."
-
- def test_elif_deep(self, env):
+
+ def test_elif_deep(self, env):
elifs = "\n".join("{{% elif a == {0} %}}{0}".format(i) for i in range(1, 1000))
tmpl = env.from_string(
"{{% if a == 0 %}}0{0}{{% else %}}x{{% endif %}}".format(elifs)
)
- for x in (0, 10, 999):
- assert tmpl.render(a=x).strip() == str(x)
+ for x in (0, 10, 999):
+ assert tmpl.render(a=x).strip() == str(x)
assert tmpl.render(a=1000).strip() == "x"
-
- def test_else(self, env):
+
+ def test_else(self, env):
tmpl = env.from_string("{% if false %}XXX{% else %}...{% endif %}")
assert tmpl.render() == "..."
-
- def test_empty(self, env):
+
+ def test_empty(self, env):
tmpl = env.from_string("[{% if true %}{% else %}{% endif %}]")
assert tmpl.render() == "[]"
-
- def test_complete(self, env):
+
+ def test_complete(self, env):
tmpl = env.from_string(
"{% if a %}A{% elif b %}B{% elif c == d %}C{% else %}D{% endif %}"
)
assert tmpl.render(a=0, b=False, c=42, d=42.0) == "C"
-
- def test_no_scope(self, env):
+
+ def test_no_scope(self, env):
tmpl = env.from_string("{% if a %}{% set foo = 1 %}{% endif %}{{ foo }}")
assert tmpl.render(a=True) == "1"
tmpl = env.from_string("{% if true %}{% set foo = 1 %}{% endif %}{{ foo }}")
assert tmpl.render() == "1"
-
-
-class TestMacros(object):
- def test_simple(self, env_trim):
+
+
+class TestMacros(object):
+ def test_simple(self, env_trim):
tmpl = env_trim.from_string(
"""\
-{% macro say_hello(name) %}Hello {{ name }}!{% endmacro %}
+{% macro say_hello(name) %}Hello {{ name }}!{% endmacro %}
{{ say_hello('Peter') }}"""
)
assert tmpl.render() == "Hello Peter!"
-
- def test_scoping(self, env_trim):
+
+ def test_scoping(self, env_trim):
tmpl = env_trim.from_string(
"""\
-{% macro level1(data1) %}
-{% macro level2(data2) %}{{ data1 }}|{{ data2 }}{% endmacro %}
-{{ level2('bar') }}{% endmacro %}
+{% macro level1(data1) %}
+{% macro level2(data2) %}{{ data1 }}|{{ data2 }}{% endmacro %}
+{{ level2('bar') }}{% endmacro %}
{{ level1('foo') }}"""
)
assert tmpl.render() == "foo|bar"
-
- def test_arguments(self, env_trim):
+
+ def test_arguments(self, env_trim):
tmpl = env_trim.from_string(
"""\
-{% macro m(a, b, c='c', d='d') %}{{ a }}|{{ b }}|{{ c }}|{{ d }}{% endmacro %}
+{% macro m(a, b, c='c', d='d') %}{{ a }}|{{ b }}|{{ c }}|{{ d }}{% endmacro %}
{{ m() }}|{{ m('a') }}|{{ m('a', 'b') }}|{{ m(1, 2, 3) }}"""
)
assert tmpl.render() == "||c|d|a||c|d|a|b|c|d|1|2|3|d"
-
- def test_arguments_defaults_nonsense(self, env_trim):
+
+ def test_arguments_defaults_nonsense(self, env_trim):
pytest.raises(
TemplateSyntaxError,
env_trim.from_string,
"""\
{% macro m(a, b=1, c) %}a={{ a }}, b={{ b }}, c={{ c }}{% endmacro %}""",
)
-
- def test_caller_defaults_nonsense(self, env_trim):
+
+ def test_caller_defaults_nonsense(self, env_trim):
pytest.raises(
TemplateSyntaxError,
env_trim.from_string,
"""\
-{% macro a() %}{{ caller() }}{% endmacro %}
+{% macro a() %}{{ caller() }}{% endmacro %}
{% call(x, y=1, z) a() %}{% endcall %}""",
)
-
- def test_varargs(self, env_trim):
+
+ def test_varargs(self, env_trim):
tmpl = env_trim.from_string(
"""\
-{% macro test() %}{{ varargs|join('|') }}{% endmacro %}\
+{% macro test() %}{{ varargs|join('|') }}{% endmacro %}\
{{ test(1, 2, 3) }}"""
)
assert tmpl.render() == "1|2|3"
-
- def test_simple_call(self, env_trim):
+
+ def test_simple_call(self, env_trim):
tmpl = env_trim.from_string(
"""\
-{% macro test() %}[[{{ caller() }}]]{% endmacro %}\
+{% macro test() %}[[{{ caller() }}]]{% endmacro %}\
{% call test() %}data{% endcall %}"""
)
assert tmpl.render() == "[[data]]"
-
- def test_complex_call(self, env_trim):
+
+ def test_complex_call(self, env_trim):
tmpl = env_trim.from_string(
"""\
-{% macro test() %}[[{{ caller('data') }}]]{% endmacro %}\
+{% macro test() %}[[{{ caller('data') }}]]{% endmacro %}\
{% call(data) test() %}{{ data }}{% endcall %}"""
)
assert tmpl.render() == "[[data]]"
-
- def test_caller_undefined(self, env_trim):
+
+ def test_caller_undefined(self, env_trim):
tmpl = env_trim.from_string(
"""\
-{% set caller = 42 %}\
-{% macro test() %}{{ caller is not defined }}{% endmacro %}\
+{% set caller = 42 %}\
+{% macro test() %}{{ caller is not defined }}{% endmacro %}\
{{ test() }}"""
)
assert tmpl.render() == "True"
-
- def test_include(self, env_trim):
- env_trim = Environment(
+
+ def test_include(self, env_trim):
+ env_trim = Environment(
loader=DictLoader(
{"include": "{% macro test(foo) %}[{{ foo }}]{% endmacro %}"}
)
- )
+ )
tmpl = env_trim.from_string('{% from "include" import test %}{{ test("foo") }}')
assert tmpl.render() == "[foo]"
-
- def test_macro_api(self, env_trim):
- tmpl = env_trim.from_string(
+
+ def test_macro_api(self, env_trim):
+ tmpl = env_trim.from_string(
"{% macro foo(a, b) %}{% endmacro %}"
"{% macro bar() %}{{ varargs }}{{ kwargs }}{% endmacro %}"
"{% macro baz() %}{{ caller() }}{% endmacro %}"
)
assert tmpl.module.foo.arguments == ("a", "b")
assert tmpl.module.foo.name == "foo"
- assert not tmpl.module.foo.caller
- assert not tmpl.module.foo.catch_kwargs
- assert not tmpl.module.foo.catch_varargs
- assert tmpl.module.bar.arguments == ()
- assert not tmpl.module.bar.caller
- assert tmpl.module.bar.catch_kwargs
- assert tmpl.module.bar.catch_varargs
- assert tmpl.module.baz.caller
-
- def test_callself(self, env_trim):
+ assert not tmpl.module.foo.caller
+ assert not tmpl.module.foo.catch_kwargs
+ assert not tmpl.module.foo.catch_varargs
+ assert tmpl.module.bar.arguments == ()
+ assert not tmpl.module.bar.caller
+ assert tmpl.module.bar.catch_kwargs
+ assert tmpl.module.bar.catch_varargs
+ assert tmpl.module.baz.caller
+
+ def test_callself(self, env_trim):
tmpl = env_trim.from_string(
"{% macro foo(x) %}{{ x }}{% if x > 1 %}|"
"{{ foo(x - 1) }}{% endif %}{% endmacro %}"
"{{ foo(5) }}"
)
assert tmpl.render() == "5|4|3|2|1"
-
- def test_macro_defaults_self_ref(self, env):
+
+ def test_macro_defaults_self_ref(self, env):
tmpl = env.from_string(
"""
- {%- set x = 42 %}
- {%- macro m(a, b=x, x=23) %}{{ a }}|{{ b }}|{{ x }}{% endmacro -%}
+ {%- set x = 42 %}
+ {%- macro m(a, b=x, x=23) %}{{ a }}|{{ b }}|{{ x }}{% endmacro -%}
"""
)
assert tmpl.module.m(1) == "1||23"
assert tmpl.module.m(1, 2) == "1|2|23"
assert tmpl.module.m(1, 2, 3) == "1|2|3"
assert tmpl.module.m(1, x=7) == "1|7|7"
-
-
-class TestSet(object):
- def test_normal(self, env_trim):
+
+
+class TestSet(object):
+ def test_normal(self, env_trim):
tmpl = env_trim.from_string("{% set foo = 1 %}{{ foo }}")
assert tmpl.render() == "1"
- assert tmpl.module.foo == 1
-
- def test_block(self, env_trim):
+ assert tmpl.module.foo == 1
+
+ def test_block(self, env_trim):
tmpl = env_trim.from_string("{% set foo %}42{% endset %}{{ foo }}")
assert tmpl.render() == "42"
assert tmpl.module.foo == u"42"
-
- def test_block_escaping(self):
- env = Environment(autoescape=True)
+
+ def test_block_escaping(self):
+ env = Environment(autoescape=True)
tmpl = env.from_string(
"{% set foo %}<em>{{ test }}</em>{% endset %}foo: {{ foo }}"
)
assert tmpl.render(test="<unsafe>") == "foo: <em>&lt;unsafe&gt;</em>"
-
- def test_set_invalid(self, env_trim):
+
+ def test_set_invalid(self, env_trim):
pytest.raises(
TemplateSyntaxError, env_trim.from_string, "{% set foo['bar'] = 1 %}"
)
tmpl = env_trim.from_string("{% set foo.bar = 1 %}")
- exc_info = pytest.raises(TemplateRuntimeError, tmpl.render, foo={})
+ exc_info = pytest.raises(TemplateRuntimeError, tmpl.render, foo={})
assert "non-namespace object" in exc_info.value.message
-
- def test_namespace_redefined(self, env_trim):
+
+ def test_namespace_redefined(self, env_trim):
tmpl = env_trim.from_string("{% set ns = namespace() %}{% set ns.bar = 'hi' %}")
exc_info = pytest.raises(TemplateRuntimeError, tmpl.render, namespace=dict)
assert "non-namespace object" in exc_info.value.message
-
- def test_namespace(self, env_trim):
+
+ def test_namespace(self, env_trim):
tmpl = env_trim.from_string(
"{% set ns = namespace() %}{% set ns.bar = '42' %}{{ ns.bar }}"
)
assert tmpl.render() == "42"
-
- def test_namespace_block(self, env_trim):
+
+ def test_namespace_block(self, env_trim):
tmpl = env_trim.from_string(
"{% set ns = namespace() %}{% set ns.bar %}42{% endset %}{{ ns.bar }}"
)
assert tmpl.render() == "42"
-
- def test_init_namespace(self, env_trim):
+
+ def test_init_namespace(self, env_trim):
tmpl = env_trim.from_string(
"{% set ns = namespace(d, self=37) %}"
"{% set ns.b = 42 %}"
"{{ ns.a }}|{{ ns.self }}|{{ ns.b }}"
)
assert tmpl.render(d={"a": 13}) == "13|37|42"
-
- def test_namespace_loop(self, env_trim):
+
+ def test_namespace_loop(self, env_trim):
tmpl = env_trim.from_string(
"{% set ns = namespace(found=false) %}"
"{% for x in range(4) %}"
@@ -532,8 +532,8 @@ class TestSet(object):
)
assert tmpl.render(v=3) == "True"
assert tmpl.render(v=4) == "False"
-
- def test_namespace_macro(self, env_trim):
+
+ def test_namespace_macro(self, env_trim):
tmpl = env_trim.from_string(
"{% set ns = namespace() %}"
"{% set ns.a = 13 %}"
@@ -544,59 +544,59 @@ class TestSet(object):
"{{ ns.a }}|{{ ns.b }}"
)
assert tmpl.render() == "13|37"
-
- def test_block_escaping_filtered(self):
- env = Environment(autoescape=True)
+
+ def test_block_escaping_filtered(self):
+ env = Environment(autoescape=True)
tmpl = env.from_string(
"{% set foo | trim %}<em>{{ test }}</em> {% endset %}foo: {{ foo }}"
)
assert tmpl.render(test="<unsafe>") == "foo: <em>&lt;unsafe&gt;</em>"
-
- def test_block_filtered(self, env_trim):
- tmpl = env_trim.from_string(
+
+ def test_block_filtered(self, env_trim):
+ tmpl = env_trim.from_string(
"{% set foo | trim | length | string %} 42 {% endset %}{{ foo }}"
)
assert tmpl.render() == "2"
assert tmpl.module.foo == u"2"
-
- def test_block_filtered_set(self, env_trim):
- def _myfilter(val, arg):
+
+ def test_block_filtered_set(self, env_trim):
+ def _myfilter(val, arg):
assert arg == " xxx "
- return val
+ return val
env_trim.filters["myfilter"] = _myfilter
- tmpl = env_trim.from_string(
- '{% set a = " xxx " %}'
+ tmpl = env_trim.from_string(
+ '{% set a = " xxx " %}'
"{% set foo | myfilter(a) | trim | length | string %}"
- ' {% set b = " yy " %} 42 {{ a }}{{ b }} '
+ ' {% set b = " yy " %} 42 {{ a }}{{ b }} '
"{% endset %}"
"{{ foo }}"
)
assert tmpl.render() == "11"
assert tmpl.module.foo == u"11"
-
-
-class TestWith(object):
- def test_with(self, env):
+
+
+class TestWith(object):
+ def test_with(self, env):
tmpl = env.from_string(
"""\
- {% with a=42, b=23 -%}
- {{ a }} = {{ b }}
- {% endwith -%}
- {{ a }} = {{ b }}\
+ {% with a=42, b=23 -%}
+ {{ a }} = {{ b }}
+ {% endwith -%}
+ {{ a }} = {{ b }}\
"""
)
assert [x.strip() for x in tmpl.render(a=1, b=2).splitlines()] == [
"42 = 23",
"1 = 2",
]
-
- def test_with_argument_scoping(self, env):
+
+ def test_with_argument_scoping(self, env):
tmpl = env.from_string(
"""\
- {%- with a=1, b=2, c=b, d=e, e=5 -%}
- {{ a }}|{{ b }}|{{ c }}|{{ d }}|{{ e }}
- {%- endwith -%}
+ {%- with a=1, b=2, c=b, d=e, e=5 -%}
+ {{ a }}|{{ b }}|{{ c }}|{{ d }}|{{ e }}
+ {%- endwith -%}
"""
)
assert tmpl.render(b=3, e=4) == "1|2|3|4|5"
diff --git a/contrib/python/Jinja2/py2/tests/test_debug.py b/contrib/python/Jinja2/py2/tests/test_debug.py
index 284b9e91a5..6e15d2ee9c 100644
--- a/contrib/python/Jinja2/py2/tests/test_debug.py
+++ b/contrib/python/Jinja2/py2/tests/test_debug.py
@@ -1,27 +1,27 @@
-# -*- coding: utf-8 -*-
+# -*- coding: utf-8 -*-
import pickle
import re
from traceback import format_exception
-
-import pytest
-
+
+import pytest
+
from jinja2 import ChoiceLoader
from jinja2 import DictLoader
from jinja2 import Environment
from jinja2 import TemplateSyntaxError
-
-
-@pytest.fixture
-def fs_env(filesystem_loader):
+
+
+@pytest.fixture
+def fs_env(filesystem_loader):
"""returns a new environment."""
- return Environment(loader=filesystem_loader)
-
-
-class TestDebug(object):
- def assert_traceback_matches(self, callback, expected_tb):
+ return Environment(loader=filesystem_loader)
+
+
+class TestDebug(object):
+ def assert_traceback_matches(self, callback, expected_tb):
with pytest.raises(Exception) as exc_info:
- callback()
-
+ callback()
+
tb = format_exception(exc_info.type, exc_info.value, exc_info.tb)
m = re.search(expected_tb.strip(), "".join(tb))
assert m is not None, "Traceback did not match:\n\n%s\nexpected:\n%s" % (
@@ -29,50 +29,50 @@ class TestDebug(object):
expected_tb,
)
- def test_runtime_error(self, fs_env):
- def test():
- tmpl.render(fail=lambda: 1 / 0)
+ def test_runtime_error(self, fs_env):
+ def test():
+ tmpl.render(fail=lambda: 1 / 0)
tmpl = fs_env.get_template("broken.html")
self.assert_traceback_matches(
test,
r"""
- File ".*?broken.html", line 2, in (top-level template code|<module>)
- \{\{ fail\(\) \}\}
- File ".*debug?.pyc?", line \d+, in <lambda>
- tmpl\.render\(fail=lambda: 1 / 0\)
-ZeroDivisionError: (int(eger)? )?division (or modulo )?by zero
+ File ".*?broken.html", line 2, in (top-level template code|<module>)
+ \{\{ fail\(\) \}\}
+ File ".*debug?.pyc?", line \d+, in <lambda>
+ tmpl\.render\(fail=lambda: 1 / 0\)
+ZeroDivisionError: (int(eger)? )?division (or modulo )?by zero
""",
)
-
- def test_syntax_error(self, fs_env):
+
+ def test_syntax_error(self, fs_env):
# The trailing .*? is for PyPy 2 and 3, which don't seem to
# clear the exception's original traceback, leaving the syntax
# error in the middle of other compiler frames.
self.assert_traceback_matches(
lambda: fs_env.get_template("syntaxerror.html"),
"""(?sm)
- File ".*?syntaxerror.html", line 4, in (template|<module>)
+ File ".*?syntaxerror.html", line 4, in (template|<module>)
\\{% endif %\\}.*?
(jinja2\\.exceptions\\.)?TemplateSyntaxError: Encountered unknown tag 'endif'. Jinja \
was looking for the following tags: 'endfor' or 'else'. The innermost block that needs \
to be closed is 'for'.
""",
)
-
- def test_regular_syntax_error(self, fs_env):
- def test():
+
+ def test_regular_syntax_error(self, fs_env):
+ def test():
raise TemplateSyntaxError("wtf", 42)
self.assert_traceback_matches(
test,
r"""
- File ".*debug.pyc?", line \d+, in test
+ File ".*debug.pyc?", line \d+, in test
raise TemplateSyntaxError\("wtf", 42\)
-(jinja2\.exceptions\.)?TemplateSyntaxError: wtf
+(jinja2\.exceptions\.)?TemplateSyntaxError: wtf
line 42""",
)
-
+
def test_pickleable_syntax_error(self, fs_env):
original = TemplateSyntaxError("bad template", 42, "test", "test.txt")
unpickled = pickle.loads(pickle.dumps(original))
@@ -95,9 +95,9 @@ to be closed is 'for'.
assert exc_info.value.source is not None
- def test_local_extraction(self):
+ def test_local_extraction(self):
from jinja2.debug import get_template_locals
- from jinja2.runtime import missing
+ from jinja2.runtime import missing
locals = get_template_locals(
{
diff --git a/contrib/python/Jinja2/py2/tests/test_ext.py b/contrib/python/Jinja2/py2/tests/test_ext.py
index 8e4b411e1b..9c51236441 100644
--- a/contrib/python/Jinja2/py2/tests/test_ext.py
+++ b/contrib/python/Jinja2/py2/tests/test_ext.py
@@ -1,8 +1,8 @@
-# -*- coding: utf-8 -*-
+# -*- coding: utf-8 -*-
import re
-
-import pytest
-
+
+import pytest
+
from jinja2 import contextfunction
from jinja2 import DictLoader
from jinja2 import Environment
@@ -10,17 +10,17 @@ from jinja2 import nodes
from jinja2._compat import BytesIO
from jinja2._compat import itervalues
from jinja2._compat import text_type
-from jinja2.exceptions import TemplateAssertionError
-from jinja2.ext import Extension
+from jinja2.exceptions import TemplateAssertionError
+from jinja2.ext import Extension
from jinja2.lexer import count_newlines
from jinja2.lexer import Token
-
-importable_object = 23
-
+
+importable_object = 23
+
_gettext_re = re.compile(r"_\((.*?)\)", re.DOTALL)
-
-
-i18n_templates = {
+
+
+i18n_templates = {
"master.html": '<title>{{ page_title|default(_("missing")) }}</title>'
"{% block body %}{% endblock %}",
"child.html": '{% extends "master.html" %}{% block body %}'
@@ -30,9 +30,9 @@ i18n_templates = {
"plural2.html": "{% trans user_count=get_user_count() %}{{ user_count }}s"
"{% pluralize %}{{ user_count }}p{% endtrans %}",
"stringformat.html": '{{ _("User: %(num)s")|format(num=user_count) }}',
-}
-
-newstyle_i18n_templates = {
+}
+
+newstyle_i18n_templates = {
"master.html": '<title>{{ page_title|default(_("missing")) }}</title>'
"{% block body %}{% endblock %}",
"child.html": '{% extends "master.html" %}{% block body %}'
@@ -49,10 +49,10 @@ newstyle_i18n_templates = {
"novars.html": "{% trans %}%(hello)s{% endtrans %}",
"vars.html": "{% trans %}{{ foo }}%(foo)s{% endtrans %}",
"explicitvars.html": '{% trans foo="42" %}%(foo)s{% endtrans %}',
-}
-
-
-languages = {
+}
+
+
+languages = {
"de": {
"missing": u"fehlend",
"watch out": u"pass auf",
@@ -62,46 +62,46 @@ languages = {
"User: %(count)s": u"Benutzer: %(count)s",
"%(num)s apple": u"%(num)s Apfel",
"%(num)s apples": u"%(num)s Äpfel",
- }
-}
-
-
-@contextfunction
-def gettext(context, string):
+ }
+}
+
+
+@contextfunction
+def gettext(context, string):
language = context.get("LANGUAGE", "en")
- return languages.get(language, {}).get(string, string)
-
-
-@contextfunction
-def ngettext(context, s, p, n):
+ return languages.get(language, {}).get(string, string)
+
+
+@contextfunction
+def ngettext(context, s, p, n):
language = context.get("LANGUAGE", "en")
- if n != 1:
- return languages.get(language, {}).get(p, p)
- return languages.get(language, {}).get(s, s)
-
-
-i18n_env = Environment(
+ if n != 1:
+ return languages.get(language, {}).get(p, p)
+ return languages.get(language, {}).get(s, s)
+
+
+i18n_env = Environment(
loader=DictLoader(i18n_templates), extensions=["jinja2.ext.i18n"]
-)
+)
i18n_env.globals.update({"_": gettext, "gettext": gettext, "ngettext": ngettext})
i18n_env_trimmed = Environment(extensions=["jinja2.ext.i18n"])
i18n_env_trimmed.policies["ext.i18n.trimmed"] = True
i18n_env_trimmed.globals.update(
{"_": gettext, "gettext": gettext, "ngettext": ngettext}
)
-
-newstyle_i18n_env = Environment(
+
+newstyle_i18n_env = Environment(
loader=DictLoader(newstyle_i18n_templates), extensions=["jinja2.ext.i18n"]
-)
-newstyle_i18n_env.install_gettext_callables(gettext, ngettext, newstyle=True)
-
-
-class ExampleExtension(Extension):
+)
+newstyle_i18n_env.install_gettext_callables(gettext, ngettext, newstyle=True)
+
+
+class ExampleExtension(Extension):
tags = set(["test"])
- ext_attr = 42
+ ext_attr = 42
context_reference_node_cls = nodes.ContextReference
-
- def parse(self, parser):
+
+ def parse(self, parser):
return nodes.Output(
[
self.call_method(
@@ -115,102 +115,102 @@ class ExampleExtension(Extension):
)
]
).set_lineno(next(parser.stream).lineno)
-
- def _dump(self, sandboxed, ext_attr, imported_object, context):
+
+ def _dump(self, sandboxed, ext_attr, imported_object, context):
return "%s|%s|%s|%s|%s" % (
- sandboxed,
- ext_attr,
- imported_object,
+ sandboxed,
+ ext_attr,
+ imported_object,
context.blocks,
context.get("test_var"),
- )
-
-
+ )
+
+
class DerivedExampleExtension(ExampleExtension):
context_reference_node_cls = nodes.DerivedContextReference
-class PreprocessorExtension(Extension):
- def preprocess(self, source, name, filename=None):
+class PreprocessorExtension(Extension):
+ def preprocess(self, source, name, filename=None):
return source.replace("[[TEST]]", "({{ foo }})")
-
-
-class StreamFilterExtension(Extension):
- def filter_stream(self, stream):
- for token in stream:
+
+
+class StreamFilterExtension(Extension):
+ def filter_stream(self, stream):
+ for token in stream:
if token.type == "data":
- for t in self.interpolate(token):
- yield t
- else:
- yield token
-
- def interpolate(self, token):
- pos = 0
- end = len(token.value)
- lineno = token.lineno
- while 1:
- match = _gettext_re.search(token.value, pos)
- if match is None:
- break
+ for t in self.interpolate(token):
+ yield t
+ else:
+ yield token
+
+ def interpolate(self, token):
+ pos = 0
+ end = len(token.value)
+ lineno = token.lineno
+ while 1:
+ match = _gettext_re.search(token.value, pos)
+ if match is None:
+ break
value = token.value[pos : match.start()]
- if value:
+ if value:
yield Token(lineno, "data", value)
- lineno += count_newlines(token.value)
+ lineno += count_newlines(token.value)
yield Token(lineno, "variable_begin", None)
yield Token(lineno, "name", "gettext")
yield Token(lineno, "lparen", None)
yield Token(lineno, "string", match.group(1))
yield Token(lineno, "rparen", None)
yield Token(lineno, "variable_end", None)
- pos = match.end()
- if pos < end:
+ pos = match.end()
+ if pos < end:
yield Token(lineno, "data", token.value[pos:])
-
-
-class TestExtensions(object):
- def test_extend_late(self):
- env = Environment()
+
+
+class TestExtensions(object):
+ def test_extend_late(self):
+ env = Environment()
env.add_extension("jinja2.ext.autoescape")
t = env.from_string('{% autoescape true %}{{ "<test>" }}{% endautoescape %}')
assert t.render() == "&lt;test&gt;"
-
- def test_loop_controls(self):
+
+ def test_loop_controls(self):
env = Environment(extensions=["jinja2.ext.loopcontrols"])
-
+
tmpl = env.from_string(
"""
- {%- for item in [1, 2, 3, 4] %}
- {%- if item % 2 == 0 %}{% continue %}{% endif -%}
- {{ item }}
+ {%- for item in [1, 2, 3, 4] %}
+ {%- if item % 2 == 0 %}{% continue %}{% endif -%}
+ {{ item }}
{%- endfor %}"""
)
assert tmpl.render() == "13"
-
+
tmpl = env.from_string(
"""
- {%- for item in [1, 2, 3, 4] %}
- {%- if item > 2 %}{% break %}{% endif -%}
- {{ item }}
+ {%- for item in [1, 2, 3, 4] %}
+ {%- if item > 2 %}{% break %}{% endif -%}
+ {{ item }}
{%- endfor %}"""
)
assert tmpl.render() == "12"
-
- def test_do(self):
+
+ def test_do(self):
env = Environment(extensions=["jinja2.ext.do"])
tmpl = env.from_string(
"""
- {%- set items = [] %}
- {%- for char in "foo" %}
- {%- do items.append(loop.index0 ~ char) %}
+ {%- set items = [] %}
+ {%- for char in "foo" %}
+ {%- do items.append(loop.index0 ~ char) %}
{%- endfor %}{{ items|join(', ') }}"""
)
assert tmpl.render() == "0f, 1o, 2o"
-
- def test_extension_nodes(self):
- env = Environment(extensions=[ExampleExtension])
+
+ def test_extension_nodes(self):
+ env = Environment(extensions=[ExampleExtension])
tmpl = env.from_string("{% test %}")
assert tmpl.render() == "False|42|23|{}|None"
-
+
def test_contextreference_node_passes_context(self):
env = Environment(extensions=[ExampleExtension])
tmpl = env.from_string('{% set test_var="test_content" %}{% test %}')
@@ -223,72 +223,72 @@ class TestExtensions(object):
)
assert tmpl.render() == "False|42|23|{}|test_content"
- def test_identifier(self):
+ def test_identifier(self):
assert ExampleExtension.identifier == __name__ + ".ExampleExtension"
-
- def test_rebinding(self):
- original = Environment(extensions=[ExampleExtension])
- overlay = original.overlay()
- for env in original, overlay:
- for ext in itervalues(env.extensions):
- assert ext.environment is env
-
- def test_preprocessor_extension(self):
- env = Environment(extensions=[PreprocessorExtension])
+
+ def test_rebinding(self):
+ original = Environment(extensions=[ExampleExtension])
+ overlay = original.overlay()
+ for env in original, overlay:
+ for ext in itervalues(env.extensions):
+ assert ext.environment is env
+
+ def test_preprocessor_extension(self):
+ env = Environment(extensions=[PreprocessorExtension])
tmpl = env.from_string("{[[TEST]]}")
assert tmpl.render(foo=42) == "{(42)}"
-
- def test_streamfilter_extension(self):
- env = Environment(extensions=[StreamFilterExtension])
+
+ def test_streamfilter_extension(self):
+ env = Environment(extensions=[StreamFilterExtension])
env.globals["gettext"] = lambda x: x.upper()
tmpl = env.from_string("Foo _(bar) Baz")
- out = tmpl.render()
+ out = tmpl.render()
assert out == "Foo BAR Baz"
-
- def test_extension_ordering(self):
- class T1(Extension):
- priority = 1
-
- class T2(Extension):
- priority = 2
-
- env = Environment(extensions=[T1, T2])
- ext = list(env.iter_extensions())
- assert ext[0].__class__ is T1
- assert ext[1].__class__ is T2
-
+
+ def test_extension_ordering(self):
+ class T1(Extension):
+ priority = 1
+
+ class T2(Extension):
+ priority = 2
+
+ env = Environment(extensions=[T1, T2])
+ ext = list(env.iter_extensions())
+ assert ext[0].__class__ is T1
+ assert ext[1].__class__ is T2
+
def test_debug(self):
env = Environment(extensions=["jinja2.ext.debug"])
t = env.from_string("Hello\n{% debug %}\nGoodbye")
out = t.render()
-
+
for value in ("context", "cycler", "filters", "abs", "tests", "!="):
assert "'{}'".format(value) in out
-class TestInternationalization(object):
- def test_trans(self):
+class TestInternationalization(object):
+ def test_trans(self):
tmpl = i18n_env.get_template("child.html")
assert tmpl.render(LANGUAGE="de") == "<title>fehlend</title>pass auf"
-
- def test_trans_plural(self):
+
+ def test_trans_plural(self):
tmpl = i18n_env.get_template("plural.html")
assert tmpl.render(LANGUAGE="de", user_count=1) == "Ein Benutzer online"
assert tmpl.render(LANGUAGE="de", user_count=2) == "2 Benutzer online"
-
- def test_trans_plural_with_functions(self):
+
+ def test_trans_plural_with_functions(self):
tmpl = i18n_env.get_template("plural2.html")
+
+ def get_user_count():
+ get_user_count.called += 1
+ return 1
- def get_user_count():
- get_user_count.called += 1
- return 1
-
- get_user_count.called = 0
+ get_user_count.called = 0
assert tmpl.render(LANGUAGE="de", get_user_count=get_user_count) == "1s"
- assert get_user_count.called == 1
-
- def test_complex_plural(self):
- tmpl = i18n_env.from_string(
+ assert get_user_count.called == 1
+
+ def test_complex_plural(self):
+ tmpl = i18n_env.from_string(
"{% trans foo=42, count=2 %}{{ count }} item{% "
"pluralize count %}{{ count }} items{% endtrans %}"
)
@@ -298,52 +298,52 @@ class TestInternationalization(object):
i18n_env.from_string,
"{% trans foo %}...{% pluralize bar %}...{% endtrans %}",
)
-
- def test_trans_stringformatting(self):
+
+ def test_trans_stringformatting(self):
tmpl = i18n_env.get_template("stringformat.html")
assert tmpl.render(LANGUAGE="de", user_count=5) == "Benutzer: 5"
-
- def test_trimmed(self):
- tmpl = i18n_env.from_string(
+
+ def test_trimmed(self):
+ tmpl = i18n_env.from_string(
"{%- trans trimmed %} hello\n world {% endtrans -%}"
)
assert tmpl.render() == "hello world"
-
- def test_trimmed_policy(self):
+
+ def test_trimmed_policy(self):
s = "{%- trans %} hello\n world {% endtrans -%}"
- tmpl = i18n_env.from_string(s)
- trimmed_tmpl = i18n_env_trimmed.from_string(s)
+ tmpl = i18n_env.from_string(s)
+ trimmed_tmpl = i18n_env_trimmed.from_string(s)
assert tmpl.render() == " hello\n world "
assert trimmed_tmpl.render() == "hello world"
-
- def test_trimmed_policy_override(self):
- tmpl = i18n_env_trimmed.from_string(
+
+ def test_trimmed_policy_override(self):
+ tmpl = i18n_env_trimmed.from_string(
"{%- trans notrimmed %} hello\n world {% endtrans -%}"
)
assert tmpl.render() == " hello\n world "
-
- def test_trimmed_vars(self):
- tmpl = i18n_env.from_string(
+
+ def test_trimmed_vars(self):
+ tmpl = i18n_env.from_string(
'{%- trans trimmed x="world" %} hello\n {{ x }} {% endtrans -%}'
)
assert tmpl.render() == "hello world"
-
- def test_trimmed_varname_trimmed(self):
- # unlikely variable name, but when used as a variable
- # it should not enable trimming
- tmpl = i18n_env.from_string(
+
+ def test_trimmed_varname_trimmed(self):
+ # unlikely variable name, but when used as a variable
+ # it should not enable trimming
+ tmpl = i18n_env.from_string(
"{%- trans trimmed = 'world' %} hello\n {{ trimmed }} {% endtrans -%}"
)
assert tmpl.render() == " hello\n world "
-
- def test_extract(self):
- from jinja2.ext import babel_extract
+
+ def test_extract(self):
+ from jinja2.ext import babel_extract
source = BytesIO(
"""
- {{ gettext('Hello World') }}
- {% trans %}Hello World{% endtrans %}
- {% trans %}{{ users }} user{% pluralize %}{{ users }} users{% endtrans %}
+ {{ gettext('Hello World') }}
+ {% trans %}Hello World{% endtrans %}
+ {% trans %}{{ users }} user{% pluralize %}{{ users }} users{% endtrans %}
""".encode(
"ascii"
)
@@ -352,17 +352,17 @@ class TestInternationalization(object):
(2, "gettext", u"Hello World", []),
(3, "gettext", u"Hello World", []),
(4, "ngettext", (u"%(users)s user", u"%(users)s users", None), []),
- ]
-
- def test_extract_trimmed(self):
- from jinja2.ext import babel_extract
+ ]
+
+ def test_extract_trimmed(self):
+ from jinja2.ext import babel_extract
source = BytesIO(
"""
- {{ gettext(' Hello \n World') }}
- {% trans trimmed %} Hello \n World{% endtrans %}
- {% trans trimmed %}{{ users }} \n user
- {%- pluralize %}{{ users }} \n users{% endtrans %}
+ {{ gettext(' Hello \n World') }}
+ {% trans trimmed %} Hello \n World{% endtrans %}
+ {% trans trimmed %}{{ users }} \n user
+ {%- pluralize %}{{ users }} \n users{% endtrans %}
""".encode(
"ascii"
)
@@ -371,17 +371,17 @@ class TestInternationalization(object):
(2, "gettext", u" Hello \n World", []),
(4, "gettext", u"Hello World", []),
(6, "ngettext", (u"%(users)s user", u"%(users)s users", None), []),
- ]
-
- def test_extract_trimmed_option(self):
- from jinja2.ext import babel_extract
+ ]
+
+ def test_extract_trimmed_option(self):
+ from jinja2.ext import babel_extract
source = BytesIO(
"""
- {{ gettext(' Hello \n World') }}
- {% trans %} Hello \n World{% endtrans %}
- {% trans %}{{ users }} \n user
- {%- pluralize %}{{ users }} \n users{% endtrans %}
+ {{ gettext(' Hello \n World') }}
+ {% trans %} Hello \n World{% endtrans %}
+ {% trans %}{{ users }} \n user
+ {%- pluralize %}{{ users }} \n users{% endtrans %}
""".encode(
"ascii"
)
@@ -391,18 +391,18 @@ class TestInternationalization(object):
(2, "gettext", u" Hello \n World", []),
(4, "gettext", u"Hello World", []),
(6, "ngettext", (u"%(users)s user", u"%(users)s users", None), []),
- ]
-
- def test_comment_extract(self):
- from jinja2.ext import babel_extract
+ ]
+
+ def test_comment_extract(self):
+ from jinja2.ext import babel_extract
source = BytesIO(
"""
- {# trans first #}
- {{ gettext('Hello World') }}
- {% trans %}Hello World{% endtrans %}{# trans second #}
- {#: third #}
- {% trans %}{{ users }} user{% pluralize %}{{ users }} users{% endtrans %}
+ {# trans first #}
+ {{ gettext('Hello World') }}
+ {% trans %}Hello World{% endtrans %}{# trans second #}
+ {#: third #}
+ {% trans %}{{ users }} user{% pluralize %}{{ users }} users{% endtrans %}
""".encode(
"utf-8"
)
@@ -413,54 +413,54 @@ class TestInternationalization(object):
(3, "gettext", u"Hello World", ["first"]),
(4, "gettext", u"Hello World", ["second"]),
(6, "ngettext", (u"%(users)s user", u"%(users)s users", None), ["third"]),
- ]
-
-
-class TestScope(object):
- def test_basic_scope_behavior(self):
- # This is what the old with statement compiled down to
- class ScopeExt(Extension):
+ ]
+
+
+class TestScope(object):
+ def test_basic_scope_behavior(self):
+ # This is what the old with statement compiled down to
+ class ScopeExt(Extension):
tags = set(["scope"])
-
- def parse(self, parser):
- node = nodes.Scope(lineno=next(parser.stream).lineno)
- assignments = []
+
+ def parse(self, parser):
+ node = nodes.Scope(lineno=next(parser.stream).lineno)
+ assignments = []
while parser.stream.current.type != "block_end":
- lineno = parser.stream.current.lineno
- if assignments:
+ lineno = parser.stream.current.lineno
+ if assignments:
parser.stream.expect("comma")
- target = parser.parse_assign_target()
+ target = parser.parse_assign_target()
parser.stream.expect("assign")
- expr = parser.parse_expression()
- assignments.append(nodes.Assign(target, expr, lineno=lineno))
+ expr = parser.parse_expression()
+ assignments.append(nodes.Assign(target, expr, lineno=lineno))
node.body = assignments + list(
parser.parse_statements(("name:endscope",), drop_needle=True)
)
- return node
-
- env = Environment(extensions=[ScopeExt])
+ return node
+
+ env = Environment(extensions=[ScopeExt])
tmpl = env.from_string(
"""\
- {%- scope a=1, b=2, c=b, d=e, e=5 -%}
- {{ a }}|{{ b }}|{{ c }}|{{ d }}|{{ e }}
- {%- endscope -%}
+ {%- scope a=1, b=2, c=b, d=e, e=5 -%}
+ {{ a }}|{{ b }}|{{ c }}|{{ d }}|{{ e }}
+ {%- endscope -%}
"""
)
assert tmpl.render(b=3, e=4) == "1|2|2|4|5"
-
-
-class TestNewstyleInternationalization(object):
- def test_trans(self):
+
+
+class TestNewstyleInternationalization(object):
+ def test_trans(self):
tmpl = newstyle_i18n_env.get_template("child.html")
assert tmpl.render(LANGUAGE="de") == "<title>fehlend</title>pass auf"
-
- def test_trans_plural(self):
+
+ def test_trans_plural(self):
tmpl = newstyle_i18n_env.get_template("plural.html")
assert tmpl.render(LANGUAGE="de", user_count=1) == "Ein Benutzer online"
assert tmpl.render(LANGUAGE="de", user_count=2) == "2 Benutzer online"
-
- def test_complex_plural(self):
- tmpl = newstyle_i18n_env.from_string(
+
+ def test_complex_plural(self):
+ tmpl = newstyle_i18n_env.from_string(
"{% trans foo=42, count=2 %}{{ count }} item{% "
"pluralize count %}{{ count }} items{% endtrans %}"
)
@@ -470,19 +470,19 @@ class TestNewstyleInternationalization(object):
i18n_env.from_string,
"{% trans foo %}...{% pluralize bar %}...{% endtrans %}",
)
-
- def test_trans_stringformatting(self):
+
+ def test_trans_stringformatting(self):
tmpl = newstyle_i18n_env.get_template("stringformat.html")
assert tmpl.render(LANGUAGE="de", user_count=5) == "Benutzer: 5"
-
- def test_newstyle_plural(self):
+
+ def test_newstyle_plural(self):
tmpl = newstyle_i18n_env.get_template("ngettext.html")
assert tmpl.render(LANGUAGE="de", apples=1) == "1 Apfel"
assert tmpl.render(LANGUAGE="de", apples=5) == u"5 Äpfel"
-
- def test_autoescape_support(self):
+
+ def test_autoescape_support(self):
env = Environment(extensions=["jinja2.ext.autoescape", "jinja2.ext.i18n"])
- env.install_gettext_callables(
+ env.install_gettext_callables(
lambda x: u"<strong>Wert: %(name)s</strong>",
lambda s, p, n: s,
newstyle=True,
@@ -493,63 +493,63 @@ class TestNewstyleInternationalization(object):
)
assert t.render(ae=True) == "<strong>Wert: &lt;test&gt;</strong>"
assert t.render(ae=False) == "<strong>Wert: <test></strong>"
-
- def test_autoescape_macros(self):
+
+ def test_autoescape_macros(self):
env = Environment(autoescape=False, extensions=["jinja2.ext.autoescape"])
- template = (
+ template = (
"{% macro m() %}<html>{% endmacro %}"
"{% autoescape true %}{{ m() }}{% endautoescape %}"
- )
+ )
assert env.from_string(template).render() == "<html>"
-
- def test_num_used_twice(self):
+
+ def test_num_used_twice(self):
tmpl = newstyle_i18n_env.get_template("ngettext_long.html")
assert tmpl.render(apples=5, LANGUAGE="de") == u"5 Äpfel"
-
- def test_num_called_num(self):
+
+ def test_num_called_num(self):
source = newstyle_i18n_env.compile(
"""
- {% trans num=3 %}{{ num }} apple{% pluralize
- %}{{ num }} apples{% endtrans %}
+ {% trans num=3 %}{{ num }} apple{% pluralize
+ %}{{ num }} apples{% endtrans %}
""",
raw=True,
)
- # quite hacky, but the only way to properly test that. The idea is
- # that the generated code does not pass num twice (although that
- # would work) for better performance. This only works on the
- # newstyle gettext of course
+ # quite hacky, but the only way to properly test that. The idea is
+ # that the generated code does not pass num twice (although that
+ # would work) for better performance. This only works on the
+ # newstyle gettext of course
assert (
re.search(r"u?'\%\(num\)s apple', u?'\%\(num\)s " r"apples', 3", source)
is not None
)
-
- def test_trans_vars(self):
+
+ def test_trans_vars(self):
t1 = newstyle_i18n_env.get_template("transvars1.html")
t2 = newstyle_i18n_env.get_template("transvars2.html")
t3 = newstyle_i18n_env.get_template("transvars3.html")
assert t1.render(num=1, LANGUAGE="de") == "Benutzer: 1"
assert t2.render(count=23, LANGUAGE="de") == "Benutzer: 23"
assert t3.render(num=42, LANGUAGE="de") == "Benutzer: 42"
-
- def test_novars_vars_escaping(self):
+
+ def test_novars_vars_escaping(self):
t = newstyle_i18n_env.get_template("novars.html")
assert t.render() == "%(hello)s"
t = newstyle_i18n_env.get_template("vars.html")
assert t.render(foo="42") == "42%(foo)s"
t = newstyle_i18n_env.get_template("explicitvars.html")
assert t.render() == "%(foo)s"
-
-
-class TestAutoEscape(object):
- def test_scoped_setting(self):
+
+
+class TestAutoEscape(object):
+ def test_scoped_setting(self):
env = Environment(extensions=["jinja2.ext.autoescape"], autoescape=True)
tmpl = env.from_string(
"""
- {{ "<HelloWorld>" }}
- {% autoescape false %}
- {{ "<HelloWorld>" }}
- {% endautoescape %}
- {{ "<HelloWorld>" }}
+ {{ "<HelloWorld>" }}
+ {% autoescape false %}
+ {{ "<HelloWorld>" }}
+ {% endautoescape %}
+ {{ "<HelloWorld>" }}
"""
)
assert tmpl.render().split() == [
@@ -557,15 +557,15 @@ class TestAutoEscape(object):
u"<HelloWorld>",
u"&lt;HelloWorld&gt;",
]
-
+
env = Environment(extensions=["jinja2.ext.autoescape"], autoescape=False)
tmpl = env.from_string(
"""
- {{ "<HelloWorld>" }}
- {% autoescape true %}
- {{ "<HelloWorld>" }}
- {% endautoescape %}
- {{ "<HelloWorld>" }}
+ {{ "<HelloWorld>" }}
+ {% autoescape true %}
+ {{ "<HelloWorld>" }}
+ {% endautoescape %}
+ {{ "<HelloWorld>" }}
"""
)
assert tmpl.render().split() == [
@@ -573,83 +573,83 @@ class TestAutoEscape(object):
u"&lt;HelloWorld&gt;",
u"<HelloWorld>",
]
-
- def test_nonvolatile(self):
+
+ def test_nonvolatile(self):
env = Environment(extensions=["jinja2.ext.autoescape"], autoescape=True)
- tmpl = env.from_string('{{ {"foo": "<test>"}|xmlattr|escape }}')
- assert tmpl.render() == ' foo="&lt;test&gt;"'
+ tmpl = env.from_string('{{ {"foo": "<test>"}|xmlattr|escape }}')
+ assert tmpl.render() == ' foo="&lt;test&gt;"'
tmpl = env.from_string(
'{% autoescape false %}{{ {"foo": "<test>"}'
"|xmlattr|escape }}{% endautoescape %}"
)
assert tmpl.render() == " foo=&#34;&amp;lt;test&amp;gt;&#34;"
-
- def test_volatile(self):
+
+ def test_volatile(self):
env = Environment(extensions=["jinja2.ext.autoescape"], autoescape=True)
tmpl = env.from_string(
'{% autoescape foo %}{{ {"foo": "<test>"}'
"|xmlattr|escape }}{% endautoescape %}"
)
assert tmpl.render(foo=False) == " foo=&#34;&amp;lt;test&amp;gt;&#34;"
- assert tmpl.render(foo=True) == ' foo="&lt;test&gt;"'
-
- def test_scoping(self):
+ assert tmpl.render(foo=True) == ' foo="&lt;test&gt;"'
+
+ def test_scoping(self):
env = Environment(extensions=["jinja2.ext.autoescape"])
- tmpl = env.from_string(
- '{% autoescape true %}{% set x = "<x>" %}{{ x }}'
+ tmpl = env.from_string(
+ '{% autoescape true %}{% set x = "<x>" %}{{ x }}'
'{% endautoescape %}{{ x }}{{ "<y>" }}'
)
assert tmpl.render(x=1) == "&lt;x&gt;1<y>"
-
- def test_volatile_scoping(self):
+
+ def test_volatile_scoping(self):
env = Environment(extensions=["jinja2.ext.autoescape"])
tmplsource = """
- {% autoescape val %}
- {% macro foo(x) %}
- [{{ x }}]
- {% endmacro %}
- {{ foo().__class__.__name__ }}
- {% endautoescape %}
- {{ '<testing>' }}
+ {% autoescape val %}
+ {% macro foo(x) %}
+ [{{ x }}]
+ {% endmacro %}
+ {{ foo().__class__.__name__ }}
+ {% endautoescape %}
+ {{ '<testing>' }}
"""
- tmpl = env.from_string(tmplsource)
+ tmpl = env.from_string(tmplsource)
assert tmpl.render(val=True).split()[0] == "Markup"
- assert tmpl.render(val=False).split()[0] == text_type.__name__
-
- # looking at the source we should see <testing> there in raw
- # (and then escaped as well)
+ assert tmpl.render(val=False).split()[0] == text_type.__name__
+
+ # looking at the source we should see <testing> there in raw
+ # (and then escaped as well)
env = Environment(extensions=["jinja2.ext.autoescape"])
- pysource = env.compile(tmplsource, raw=True)
+ pysource = env.compile(tmplsource, raw=True)
assert "<testing>\\n" in pysource
-
+
env = Environment(extensions=["jinja2.ext.autoescape"], autoescape=True)
- pysource = env.compile(tmplsource, raw=True)
+ pysource = env.compile(tmplsource, raw=True)
assert "&lt;testing&gt;\\n" in pysource
-
- def test_overlay_scopes(self):
- class MagicScopeExtension(Extension):
+
+ def test_overlay_scopes(self):
+ class MagicScopeExtension(Extension):
tags = set(["overlay"])
- def parse(self, parser):
- node = nodes.OverlayScope(lineno=next(parser.stream).lineno)
+ def parse(self, parser):
+ node = nodes.OverlayScope(lineno=next(parser.stream).lineno)
node.body = list(
parser.parse_statements(("name:endoverlay",), drop_needle=True)
)
node.context = self.call_method("get_scope")
- return node
+ return node
- def get_scope(self):
+ def get_scope(self):
return {"x": [1, 2, 3]}
-
- env = Environment(extensions=[MagicScopeExtension])
-
+
+ env = Environment(extensions=[MagicScopeExtension])
+
tmpl = env.from_string(
"""
- {{- x }}|{% set z = 99 %}
- {%- overlay %}
- {{- y }}|{{ z }}|{% for item in x %}[{{ item }}]{% endfor %}
- {%- endoverlay %}|
- {{- x -}}
+ {{- x }}|{% set z = 99 %}
+ {%- overlay %}
+ {{- y }}|{{ z }}|{% for item in x %}[{{ item }}]{% endfor %}
+ {%- endoverlay %}|
+ {{- x -}}
"""
)
assert tmpl.render(x=42, y=23) == "42|23|99|[1][2][3]|42"
diff --git a/contrib/python/Jinja2/py2/tests/test_features.py b/contrib/python/Jinja2/py2/tests/test_features.py
index 34b6f200de..d65832923e 100644
--- a/contrib/python/Jinja2/py2/tests/test_features.py
+++ b/contrib/python/Jinja2/py2/tests/test_features.py
@@ -1,42 +1,42 @@
-import sys
-
-import pytest
+import sys
+import pytest
+
from jinja2 import contextfilter
from jinja2 import Environment
from jinja2 import Template
from jinja2._compat import text_type
-
-
+
+
@pytest.mark.skipif(sys.version_info < (3, 5), reason="Requires 3.5 or later")
-def test_generator_stop():
- class X(object):
- def __getattr__(self, name):
- raise StopIteration()
-
+def test_generator_stop():
+ class X(object):
+ def __getattr__(self, name):
+ raise StopIteration()
+
t = Template("a{{ bad.bar() }}b")
- with pytest.raises(RuntimeError):
- t.render(bad=X())
-
-
+ with pytest.raises(RuntimeError):
+ t.render(bad=X())
+
+
@pytest.mark.skipif(sys.version_info[0] > 2, reason="Feature only supported on 2.x")
-def test_ascii_str():
- @contextfilter
- def assert_func(context, value):
+def test_ascii_str():
+ @contextfilter
+ def assert_func(context, value):
assert type(value) is context["expected_type"]
-
- env = Environment()
+
+ env = Environment()
env.filters["assert"] = assert_func
-
+
env.policies["compiler.ascii_str"] = False
- t = env.from_string('{{ "foo"|assert }}')
+ t = env.from_string('{{ "foo"|assert }}')
t.render(expected_type=text_type)
-
+
env.policies["compiler.ascii_str"] = True
- t = env.from_string('{{ "foo"|assert }}')
- t.render(expected_type=str)
-
- for val in True, False:
+ t = env.from_string('{{ "foo"|assert }}')
+ t.render(expected_type=str)
+
+ for val in True, False:
env.policies["compiler.ascii_str"] = val
- t = env.from_string(u'{{ "\N{SNOWMAN}"|assert }}')
+ t = env.from_string(u'{{ "\N{SNOWMAN}"|assert }}')
t.render(expected_type=text_type)
diff --git a/contrib/python/Jinja2/py2/tests/test_filters.py b/contrib/python/Jinja2/py2/tests/test_filters.py
index 388c346212..ae37b1a163 100644
--- a/contrib/python/Jinja2/py2/tests/test_filters.py
+++ b/contrib/python/Jinja2/py2/tests/test_filters.py
@@ -1,26 +1,26 @@
-# -*- coding: utf-8 -*-
+# -*- coding: utf-8 -*-
import random
from collections import namedtuple
-
-import pytest
-
+
+import pytest
+
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
-
-
-@implements_to_string
-class Magic(object):
- def __init__(self, value):
- self.value = value
-
- def __str__(self):
- return text_type(self.value)
-
-
+
+
+@implements_to_string
+class Magic(object):
+ def __init__(self, value):
+ self.value = value
+
+ def __str__(self):
+ return text_type(self.value)
+
+
@implements_to_string
class Magic2(object):
def __init__(self, value1, value2):
@@ -31,26 +31,26 @@ class Magic2(object):
return u"(%s,%s)" % (text_type(self.value1), text_type(self.value2))
-class TestFilter(object):
- def test_filter_calling(self, env):
+class TestFilter(object):
+ def test_filter_calling(self, env):
rv = env.call_filter("sum", [1, 2, 3])
- assert rv == 6
-
- def test_capitalize(self, env):
- tmpl = env.from_string('{{ "foo bar"|capitalize }}')
+ assert rv == 6
+
+ def test_capitalize(self, env):
+ tmpl = env.from_string('{{ "foo bar"|capitalize }}')
assert tmpl.render() == "Foo bar"
-
- def test_center(self, env):
- tmpl = env.from_string('{{ "foo"|center(9) }}')
+
+ def test_center(self, env):
+ tmpl = env.from_string('{{ "foo"|center(9) }}')
assert tmpl.render() == " foo "
-
- def test_default(self, env):
- tmpl = env.from_string(
- "{{ missing|default('no') }}|{{ false|default('no') }}|"
- "{{ false|default('no', true) }}|{{ given|default('no') }}"
- )
+
+ def test_default(self, env):
+ tmpl = env.from_string(
+ "{{ missing|default('no') }}|{{ false|default('no') }}|"
+ "{{ false|default('no', true) }}|{{ given|default('no') }}"
+ )
assert tmpl.render(given="yes") == "no|False|no|yes"
-
+
@pytest.mark.parametrize(
"args,expect",
(
@@ -60,32 +60,32 @@ class TestFilter(object):
("reverse=true", "[('c', 2), ('b', 1), ('AB', 3), ('aa', 0)]"),
),
)
- def test_dictsort(self, env, args, expect):
+ def test_dictsort(self, env, args, expect):
t = env.from_string("{{{{ foo|dictsort({args}) }}}}".format(args=args))
- out = t.render(foo={"aa": 0, "b": 1, "c": 2, "AB": 3})
- assert out == expect
-
- def test_batch(self, env):
+ out = t.render(foo={"aa": 0, "b": 1, "c": 2, "AB": 3})
+ assert out == expect
+
+ def test_batch(self, env):
tmpl = env.from_string("{{ foo|batch(3)|list }}|{{ foo|batch(3, 'X')|list }}")
- out = tmpl.render(foo=list(range(10)))
+ out = tmpl.render(foo=list(range(10)))
assert out == (
"[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]|"
"[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 'X', 'X']]"
)
-
- def test_slice(self, env):
+
+ def test_slice(self, env):
tmpl = env.from_string("{{ foo|slice(3)|list }}|{{ foo|slice(3, 'X')|list }}")
- out = tmpl.render(foo=list(range(10)))
+ out = tmpl.render(foo=list(range(10)))
assert out == (
"[[0, 1, 2, 3], [4, 5, 6], [7, 8, 9]]|"
"[[0, 1, 2, 3], [4, 5, 6, 'X'], [7, 8, 9, 'X']]"
)
-
- def test_escape(self, env):
+
+ def test_escape(self, env):
tmpl = env.from_string("""{{ '<">&'|escape }}""")
- out = tmpl.render()
+ out = tmpl.render()
assert out == "&lt;&#34;&gt;&amp;"
-
+
@pytest.mark.parametrize(
("chars", "expect"), [(None, "..stays.."), (".", " ..stays"), (" .", "stays")]
)
@@ -94,7 +94,7 @@ class TestFilter(object):
out = tmpl.render(foo=" ..stays..", chars=chars)
assert out == expect
- def test_striptags(self, env):
+ def test_striptags(self, env):
tmpl = env.from_string("""{{ foo|striptags }}""")
out = tmpl.render(
foo=' <p>just a small \n <a href="#">'
@@ -102,9 +102,9 @@ class TestFilter(object):
"<!-- <p>and some commented stuff</p> -->"
)
assert out == "just a small example link to a webpage"
-
- def test_filesizeformat(self, env):
- tmpl = env.from_string(
+
+ def test_filesizeformat(self, env):
+ tmpl = env.from_string(
"{{ 100|filesizeformat }}|"
"{{ 1000|filesizeformat }}|"
"{{ 1000000|filesizeformat }}|"
@@ -115,15 +115,15 @@ class TestFilter(object):
"{{ 1000000|filesizeformat(true) }}|"
"{{ 1000000000|filesizeformat(true) }}|"
"{{ 1000000000000|filesizeformat(true) }}"
- )
- out = tmpl.render()
- assert out == (
+ )
+ out = tmpl.render()
+ assert out == (
"100 Bytes|1.0 kB|1.0 MB|1.0 GB|1.0 TB|100 Bytes|"
"1000 Bytes|976.6 KiB|953.7 MiB|931.3 GiB"
- )
-
- def test_filesizeformat_issue59(self, env):
- tmpl = env.from_string(
+ )
+
+ def test_filesizeformat_issue59(self, env):
+ tmpl = env.from_string(
"{{ 300|filesizeformat }}|"
"{{ 3000|filesizeformat }}|"
"{{ 3000000|filesizeformat }}|"
@@ -132,33 +132,33 @@ class TestFilter(object):
"{{ 300|filesizeformat(true) }}|"
"{{ 3000|filesizeformat(true) }}|"
"{{ 3000000|filesizeformat(true) }}"
- )
- out = tmpl.render()
- assert out == (
+ )
+ out = tmpl.render()
+ assert out == (
"300 Bytes|3.0 kB|3.0 MB|3.0 GB|3.0 TB|300 Bytes|2.9 KiB|2.9 MiB"
- )
-
- def test_first(self, env):
+ )
+
+ def test_first(self, env):
tmpl = env.from_string("{{ foo|first }}")
- out = tmpl.render(foo=list(range(10)))
+ out = tmpl.render(foo=list(range(10)))
assert out == "0"
-
+
@pytest.mark.parametrize(
("value", "expect"), (("42", "42.0"), ("abc", "0.0"), ("32.32", "32.32"),)
)
def test_float(self, env, value, expect):
t = env.from_string("{{ '%s'|float }}" % value)
assert t.render() == expect
-
+
def test_float_default(self, env):
t = env.from_string("{{ value|float(default=1.0) }}")
assert t.render(value="abc") == "1.0"
- def test_format(self, env):
+ def test_format(self, env):
tmpl = env.from_string("""{{ "%s|%s"|format("a", "b") }}""")
- out = tmpl.render()
+ out = tmpl.render()
assert out == "a|b"
-
+
@staticmethod
def _test_indent_multiline_template(env, markup=False):
text = "\n".join(["", "foo bar", '"baz"', ""])
@@ -173,21 +173,21 @@ class TestFilter(object):
t = env.from_string("{{ foo|indent(2, true, true) }}")
assert t.render(foo=text) == ' \n foo bar\n "baz"\n '
- def test_indent(self, env):
+ def test_indent(self, env):
self._test_indent_multiline_template(env)
- t = env.from_string('{{ "jinja"|indent }}')
+ t = env.from_string('{{ "jinja"|indent }}')
assert t.render() == "jinja"
- t = env.from_string('{{ "jinja"|indent(first=true) }}')
+ t = env.from_string('{{ "jinja"|indent(first=true) }}')
assert t.render() == " jinja"
- t = env.from_string('{{ "jinja"|indent(blank=true) }}')
+ t = env.from_string('{{ "jinja"|indent(blank=true) }}')
assert t.render() == "jinja"
-
+
def test_indent_markup_input(self, env):
"""
Tests cases where the filter input is a Markup type
"""
self._test_indent_multiline_template(env, markup=True)
-
+
@pytest.mark.parametrize(
("value", "expect"),
(
@@ -214,185 +214,185 @@ class TestFilter(object):
assert t.render(value="abc") == "1"
def test_int_special_method(self, env):
- class IntIsh(object):
- def __int__(self):
- return 42
-
+ class IntIsh(object):
+ def __int__(self):
+ return 42
+
t = env.from_string("{{ value|int }}")
assert t.render(value=IntIsh()) == "42"
-
- def test_join(self, env):
- tmpl = env.from_string('{{ [1, 2, 3]|join("|") }}')
- out = tmpl.render()
+
+ def test_join(self, env):
+ tmpl = env.from_string('{{ [1, 2, 3]|join("|") }}')
+ out = tmpl.render()
assert out == "1|2|3"
-
- env2 = Environment(autoescape=True)
+
+ env2 = Environment(autoescape=True)
tmpl = env2.from_string('{{ ["<foo>", "<span>foo</span>"|safe]|join }}')
assert tmpl.render() == "&lt;foo&gt;<span>foo</span>"
-
- def test_join_attribute(self, env):
+
+ def test_join_attribute(self, env):
User = namedtuple("User", "username")
tmpl = env.from_string("""{{ users|join(', ', 'username') }}""")
assert tmpl.render(users=map(User, ["foo", "bar"])) == "foo, bar"
-
- def test_last(self, env):
+
+ def test_last(self, env):
tmpl = env.from_string("""{{ foo|last }}""")
- out = tmpl.render(foo=list(range(10)))
+ out = tmpl.render(foo=list(range(10)))
assert out == "9"
-
- def test_length(self, env):
+
+ def test_length(self, env):
tmpl = env.from_string("""{{ "hello world"|length }}""")
- out = tmpl.render()
+ out = tmpl.render()
assert out == "11"
-
- def test_lower(self, env):
+
+ def test_lower(self, env):
tmpl = env.from_string("""{{ "FOO"|lower }}""")
- out = tmpl.render()
+ out = tmpl.render()
assert out == "foo"
-
- def test_pprint(self, env):
- from pprint import pformat
+
+ def test_pprint(self, env):
+ from pprint import pformat
tmpl = env.from_string("""{{ data|pprint }}""")
- data = list(range(1000))
- assert tmpl.render(data=data) == pformat(data)
-
- def test_random(self, env, request):
- # restore the random state when the test ends
- state = random.getstate()
- request.addfinalizer(lambda: random.setstate(state))
- # generate the random values from a known seed
+ data = list(range(1000))
+ assert tmpl.render(data=data) == pformat(data)
+
+ def test_random(self, env, request):
+ # restore the random state when the test ends
+ state = random.getstate()
+ request.addfinalizer(lambda: random.setstate(state))
+ # generate the random values from a known seed
random.seed("jinja")
expected = [random.choice("1234567890") for _ in range(10)]
-
- # check that the random sequence is generated again by a template
- # ensures that filter result is not constant folded
+
+ # check that the random sequence is generated again by a template
+ # ensures that filter result is not constant folded
random.seed("jinja")
- t = env.from_string('{{ "1234567890"|random }}')
-
- for value in expected:
- assert t.render() == value
-
- def test_reverse(self, env):
+ t = env.from_string('{{ "1234567890"|random }}')
+
+ for value in expected:
+ assert t.render() == value
+
+ def test_reverse(self, env):
tmpl = env.from_string(
"{{ 'foobar'|reverse|join }}|{{ [1, 2, 3]|reverse|list }}"
)
assert tmpl.render() == "raboof|[3, 2, 1]"
-
- def test_string(self, env):
- x = [1, 2, 3, 4, 5]
+
+ def test_string(self, env):
+ x = [1, 2, 3, 4, 5]
tmpl = env.from_string("""{{ obj|string }}""")
- assert tmpl.render(obj=x) == text_type(x)
-
- def test_title(self, env):
+ assert tmpl.render(obj=x) == text_type(x)
+
+ def test_title(self, env):
tmpl = env.from_string("""{{ "foo bar"|title }}""")
- assert tmpl.render() == "Foo Bar"
+ assert tmpl.render() == "Foo Bar"
tmpl = env.from_string("""{{ "foo's bar"|title }}""")
- assert tmpl.render() == "Foo's Bar"
+ assert tmpl.render() == "Foo's Bar"
tmpl = env.from_string("""{{ "foo bar"|title }}""")
- assert tmpl.render() == "Foo Bar"
+ assert tmpl.render() == "Foo Bar"
tmpl = env.from_string("""{{ "f bar f"|title }}""")
- assert tmpl.render() == "F Bar F"
+ assert tmpl.render() == "F Bar F"
tmpl = env.from_string("""{{ "foo-bar"|title }}""")
- assert tmpl.render() == "Foo-Bar"
+ assert tmpl.render() == "Foo-Bar"
tmpl = env.from_string("""{{ "foo\tbar"|title }}""")
- assert tmpl.render() == "Foo\tBar"
+ assert tmpl.render() == "Foo\tBar"
tmpl = env.from_string("""{{ "FOO\tBAR"|title }}""")
- assert tmpl.render() == "Foo\tBar"
+ assert tmpl.render() == "Foo\tBar"
tmpl = env.from_string("""{{ "foo (bar)"|title }}""")
- assert tmpl.render() == "Foo (Bar)"
+ assert tmpl.render() == "Foo (Bar)"
tmpl = env.from_string("""{{ "foo {bar}"|title }}""")
- assert tmpl.render() == "Foo {Bar}"
+ assert tmpl.render() == "Foo {Bar}"
tmpl = env.from_string("""{{ "foo [bar]"|title }}""")
- assert tmpl.render() == "Foo [Bar]"
+ assert tmpl.render() == "Foo [Bar]"
tmpl = env.from_string("""{{ "foo <bar>"|title }}""")
- assert tmpl.render() == "Foo <Bar>"
-
- class Foo:
- def __str__(self):
+ assert tmpl.render() == "Foo <Bar>"
+
+ class Foo:
+ def __str__(self):
return "foo-bar"
-
+
tmpl = env.from_string("""{{ data|title }}""")
- out = tmpl.render(data=Foo())
+ out = tmpl.render(data=Foo())
assert out == "Foo-Bar"
-
- def test_truncate(self, env):
- tmpl = env.from_string(
- '{{ data|truncate(15, true, ">>>") }}|'
- '{{ data|truncate(15, false, ">>>") }}|'
+
+ def test_truncate(self, env):
+ tmpl = env.from_string(
+ '{{ data|truncate(15, true, ">>>") }}|'
+ '{{ data|truncate(15, false, ">>>") }}|'
"{{ smalldata|truncate(15) }}"
- )
+ )
out = tmpl.render(data="foobar baz bar" * 1000, smalldata="foobar baz bar")
msg = "Current output: %s" % out
assert out == "foobar baz b>>>|foobar baz>>>|foobar baz bar", msg
-
- def test_truncate_very_short(self, env):
- tmpl = env.from_string(
+
+ def test_truncate_very_short(self, env):
+ tmpl = env.from_string(
'{{ "foo bar baz"|truncate(9) }}|{{ "foo bar baz"|truncate(9, true) }}'
- )
- out = tmpl.render()
+ )
+ out = tmpl.render()
assert out == "foo bar baz|foo bar baz", out
-
- def test_truncate_end_length(self, env):
- tmpl = env.from_string('{{ "Joel is a slug"|truncate(7, true) }}')
- out = tmpl.render()
+
+ def test_truncate_end_length(self, env):
+ tmpl = env.from_string('{{ "Joel is a slug"|truncate(7, true) }}')
+ out = tmpl.render()
assert out == "Joel...", "Current output: %s" % out
-
- def test_upper(self, env):
- tmpl = env.from_string('{{ "foo"|upper }}')
+
+ def test_upper(self, env):
+ tmpl = env.from_string('{{ "foo"|upper }}')
assert tmpl.render() == "FOO"
-
- def test_urlize(self, env):
+
+ def test_urlize(self, env):
tmpl = env.from_string('{{ "foo http://www.example.com/ bar"|urlize }}')
- assert tmpl.render() == (
- 'foo <a href="http://www.example.com/" rel="noopener">'
+ assert tmpl.render() == (
+ 'foo <a href="http://www.example.com/" rel="noopener">'
"http://www.example.com/</a> bar"
- )
-
- def test_urlize_rel_policy(self):
- env = Environment()
+ )
+
+ def test_urlize_rel_policy(self):
+ env = Environment()
env.policies["urlize.rel"] = None
tmpl = env.from_string('{{ "foo http://www.example.com/ bar"|urlize }}')
- assert tmpl.render() == (
+ assert tmpl.render() == (
'foo <a href="http://www.example.com/">http://www.example.com/</a> bar'
- )
-
- def test_urlize_target_parameter(self, env):
- tmpl = env.from_string(
- '{{ "foo http://www.example.com/ bar"|urlize(target="_blank") }}'
- )
+ )
+
+ def test_urlize_target_parameter(self, env):
+ tmpl = env.from_string(
+ '{{ "foo http://www.example.com/ bar"|urlize(target="_blank") }}'
+ )
assert (
tmpl.render()
== 'foo <a href="http://www.example.com/" rel="noopener" target="_blank">'
"http://www.example.com/</a> bar"
)
-
- def test_wordcount(self, env):
- tmpl = env.from_string('{{ "foo bar baz"|wordcount }}')
+
+ def test_wordcount(self, env):
+ 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):
+ def test_block(self, env):
tmpl = env.from_string("{% filter lower|escape %}<HEHE>{% endfilter %}")
assert tmpl.render() == "&lt;hehe&gt;"
-
- def test_chaining(self, env):
+
+ def test_chaining(self, env):
tmpl = env.from_string("""{{ ['<foo>', '<bar>']|first|upper|escape }}""")
assert tmpl.render() == "&lt;FOO&gt;"
-
- def test_sum(self, env):
+
+ def test_sum(self, env):
tmpl = env.from_string("""{{ [1, 2, 3, 4, 5, 6]|sum }}""")
assert tmpl.render() == "21"
-
- def test_sum_attributes(self, env):
+
+ def test_sum_attributes(self, env):
tmpl = env.from_string("""{{ values|sum('value') }}""")
assert tmpl.render(values=[{"value": 23}, {"value": 1}, {"value": 18}]) == "42"
-
- def test_sum_attributes_nested(self, env):
+
+ def test_sum_attributes_nested(self, env):
tmpl = env.from_string("""{{ values|sum('real.value') }}""")
assert (
tmpl.render(
@@ -404,58 +404,58 @@ class TestFilter(object):
)
== "42"
)
-
- def test_sum_attributes_tuple(self, env):
+
+ def test_sum_attributes_tuple(self, env):
tmpl = env.from_string("""{{ values.items()|sum('1') }}""")
assert tmpl.render(values={"foo": 23, "bar": 1, "baz": 18}) == "42"
-
- def test_abs(self, env):
+
+ def test_abs(self, env):
tmpl = env.from_string("""{{ -1|abs }}|{{ 1|abs }}""")
assert tmpl.render() == "1|1", tmpl.render()
-
- def test_round_positive(self, env):
+
+ def test_round_positive(self, env):
tmpl = env.from_string(
"{{ 2.7|round }}|{{ 2.1|round }}|"
"{{ 2.1234|round(3, 'floor') }}|"
"{{ 2.1|round(0, 'ceil') }}"
)
assert tmpl.render() == "3.0|2.0|2.123|3.0", tmpl.render()
-
- def test_round_negative(self, env):
+
+ def test_round_negative(self, env):
tmpl = env.from_string(
"{{ 21.3|round(-1)}}|"
"{{ 21.3|round(-1, 'ceil')}}|"
"{{ 21.3|round(-1, 'floor')}}"
)
assert tmpl.render() == "20.0|30.0|20.0", tmpl.render()
-
- def test_xmlattr(self, env):
- tmpl = env.from_string(
- "{{ {'foo': 42, 'bar': 23, 'fish': none, "
+
+ def test_xmlattr(self, env):
+ tmpl = env.from_string(
+ "{{ {'foo': 42, 'bar': 23, 'fish': none, "
"'spam': missing, 'blub:blub': '<?>'}|xmlattr }}"
)
- out = tmpl.render().split()
- assert len(out) == 3
- assert 'foo="42"' in out
- assert 'bar="23"' in out
- assert 'blub:blub="&lt;?&gt;"' in out
-
- def test_sort1(self, env):
+ out = tmpl.render().split()
+ assert len(out) == 3
+ assert 'foo="42"' in out
+ assert 'bar="23"' in out
+ assert 'blub:blub="&lt;?&gt;"' in out
+
+ def test_sort1(self, env):
tmpl = env.from_string("{{ [2, 3, 1]|sort }}|{{ [2, 3, 1]|sort(true) }}")
assert tmpl.render() == "[1, 2, 3]|[3, 2, 1]"
-
- def test_sort2(self, env):
- tmpl = env.from_string('{{ "".join(["c", "A", "b", "D"]|sort) }}')
+
+ def test_sort2(self, env):
+ tmpl = env.from_string('{{ "".join(["c", "A", "b", "D"]|sort) }}')
assert tmpl.render() == "AbcD"
-
- def test_sort3(self, env):
+
+ def test_sort3(self, env):
tmpl = env.from_string("""{{ ['foo', 'Bar', 'blah']|sort }}""")
- assert tmpl.render() == "['Bar', 'blah', 'foo']"
-
- def test_sort4(self, env):
+ assert tmpl.render() == "['Bar', 'blah', 'foo']"
+
+ def test_sort4(self, env):
tmpl = env.from_string("""{{ items|sort(attribute='value')|join }}""")
assert tmpl.render(items=map(Magic, [3, 2, 4, 1])) == "1234"
-
+
def test_sort5(self, env):
tmpl = env.from_string("""{{ items|sort(attribute='value.0')|join }}""")
assert tmpl.render(items=map(Magic, [[3], [2], [4], [1]])) == "[1][2][3][4]"
@@ -496,18 +496,18 @@ class TestFilter(object):
== "([2],[1])([2],[2])([2],[5])([3],[1])"
)
- def test_unique(self, env):
- t = env.from_string('{{ "".join(["b", "A", "a", "b"]|unique) }}')
- assert t.render() == "bA"
-
- def test_unique_case_sensitive(self, env):
- t = env.from_string('{{ "".join(["b", "A", "a", "b"]|unique(true)) }}')
- assert t.render() == "bAa"
-
- def test_unique_attribute(self, env):
- t = env.from_string("{{ items|unique(attribute='value')|join }}")
+ def test_unique(self, env):
+ t = env.from_string('{{ "".join(["b", "A", "a", "b"]|unique) }}')
+ assert t.render() == "bA"
+
+ def test_unique_case_sensitive(self, env):
+ t = env.from_string('{{ "".join(["b", "A", "a", "b"]|unique(true)) }}')
+ assert t.render() == "bAa"
+
+ def test_unique_attribute(self, env):
+ t = env.from_string("{{ items|unique(attribute='value')|join }}")
assert t.render(items=map(Magic, [3, 2, 4, 1, 2])) == "3241"
-
+
@pytest.mark.parametrize(
"source,expect",
(
@@ -519,86 +519,86 @@ class TestFilter(object):
("{{ []|max }}", ""),
),
)
- def test_min_max(self, env, source, expect):
- t = env.from_string(source)
- assert t.render() == expect
-
+ def test_min_max(self, env, source, expect):
+ t = env.from_string(source)
+ assert t.render() == expect
+
@pytest.mark.parametrize("name,expect", (("min", "1"), ("max", "9"),))
- def test_min_max_attribute(self, env, name, expect):
+ def test_min_max_attribute(self, env, name, expect):
t = env.from_string("{{ items|" + name + '(attribute="value") }}')
- assert t.render(items=map(Magic, [5, 1, 9])) == expect
-
- def test_groupby(self, env):
+ assert t.render(items=map(Magic, [5, 1, 9])) == expect
+
+ def test_groupby(self, env):
tmpl = env.from_string(
"""
- {%- for grouper, list in [{'foo': 1, 'bar': 2},
- {'foo': 2, 'bar': 3},
- {'foo': 1, 'bar': 1},
- {'foo': 3, 'bar': 4}]|groupby('foo') -%}
- {{ grouper }}{% for x in list %}: {{ x.foo }}, {{ x.bar }}{% endfor %}|
+ {%- for grouper, list in [{'foo': 1, 'bar': 2},
+ {'foo': 2, 'bar': 3},
+ {'foo': 1, 'bar': 1},
+ {'foo': 3, 'bar': 4}]|groupby('foo') -%}
+ {{ grouper }}{% for x in list %}: {{ x.foo }}, {{ x.bar }}{% endfor %}|
{%- endfor %}"""
)
assert tmpl.render().split("|") == ["1: 1, 2: 1, 1", "2: 2, 3", "3: 3, 4", ""]
-
- def test_groupby_tuple_index(self, env):
+
+ def test_groupby_tuple_index(self, env):
tmpl = env.from_string(
"""
- {%- for grouper, list in [('a', 1), ('a', 2), ('b', 1)]|groupby(0) -%}
- {{ grouper }}{% for x in list %}:{{ x.1 }}{% endfor %}|
+ {%- for grouper, list in [('a', 1), ('a', 2), ('b', 1)]|groupby(0) -%}
+ {{ grouper }}{% for x in list %}:{{ x.1 }}{% endfor %}|
{%- endfor %}"""
)
assert tmpl.render() == "a:1:2|b:1|"
-
- def test_groupby_multidot(self, env):
+
+ def test_groupby_multidot(self, env):
Date = namedtuple("Date", "day,month,year")
Article = namedtuple("Article", "title,date")
- articles = [
+ articles = [
Article("aha", Date(1, 1, 1970)),
Article("interesting", Date(2, 1, 1970)),
Article("really?", Date(3, 1, 1970)),
Article("totally not", Date(1, 1, 1971)),
- ]
+ ]
tmpl = env.from_string(
"""
- {%- for year, list in articles|groupby('date.year') -%}
- {{ year }}{% for x in list %}[{{ x.title }}]{% endfor %}|
+ {%- for year, list in articles|groupby('date.year') -%}
+ {{ year }}{% for x in list %}[{{ x.title }}]{% endfor %}|
{%- endfor %}"""
)
assert tmpl.render(articles=articles).split("|") == [
"1970[aha][interesting][really?]",
"1971[totally not]",
"",
- ]
-
- def test_filtertag(self, env):
+ ]
+
+ def test_filtertag(self, env):
tmpl = env.from_string(
"{% filter upper|replace('FOO', 'foo') %}foobar{% endfilter %}"
)
assert tmpl.render() == "fooBAR"
-
- def test_replace(self, env):
- env = Environment()
- tmpl = env.from_string('{{ string|replace("o", 42) }}')
+
+ def test_replace(self, env):
+ env = Environment()
+ tmpl = env.from_string('{{ string|replace("o", 42) }}')
assert tmpl.render(string="<foo>") == "<f4242>"
- env = Environment(autoescape=True)
- tmpl = env.from_string('{{ string|replace("o", 42) }}')
+ env = Environment(autoescape=True)
+ tmpl = env.from_string('{{ string|replace("o", 42) }}')
assert tmpl.render(string="<foo>") == "&lt;f4242&gt;"
- tmpl = env.from_string('{{ string|replace("<", 42) }}')
+ tmpl = env.from_string('{{ string|replace("<", 42) }}')
assert tmpl.render(string="<foo>") == "42foo&gt;"
- tmpl = env.from_string('{{ string|replace("o", ">x<") }}')
+ tmpl = env.from_string('{{ string|replace("o", ">x<") }}')
assert tmpl.render(string=Markup("foo")) == "f&gt;x&lt;&gt;x&lt;"
-
- def test_forceescape(self, env):
+
+ def test_forceescape(self, env):
tmpl = env.from_string("{{ x|forceescape }}")
assert tmpl.render(x=Markup("<div />")) == u"&lt;div /&gt;"
-
- def test_safe(self, env):
- env = Environment(autoescape=True)
- tmpl = env.from_string('{{ "<div>foo</div>"|safe }}')
+
+ def test_safe(self, env):
+ env = Environment(autoescape=True)
+ tmpl = env.from_string('{{ "<div>foo</div>"|safe }}')
assert tmpl.render() == "<div>foo</div>"
- tmpl = env.from_string('{{ "<div>foo</div>" }}')
+ tmpl = env.from_string('{{ "<div>foo</div>" }}')
assert tmpl.render() == "&lt;div&gt;foo&lt;/div&gt;"
-
+
@pytest.mark.parametrize(
("value", "expect"),
[
@@ -616,32 +616,32 @@ class TestFilter(object):
e = Environment(autoescape=True)
t = e.from_string("{{ value|urlencode }}")
assert t.render(value=value) == expect
-
- def test_simple_map(self, env):
- env = Environment()
- tmpl = env.from_string('{{ ["1", "2", "3"]|map("int")|sum }}')
+
+ def test_simple_map(self, env):
+ env = Environment()
+ tmpl = env.from_string('{{ ["1", "2", "3"]|map("int")|sum }}')
assert tmpl.render() == "6"
-
+
def test_map_sum(self, env):
tmpl = env.from_string('{{ [[1,2], [3], [4,5,6]]|map("sum")|list }}')
assert tmpl.render() == "[3, 3, 15]"
- def test_attribute_map(self, env):
+ def test_attribute_map(self, env):
User = namedtuple("User", "name")
- env = Environment()
- users = [
+ env = Environment()
+ users = [
User("john"),
User("jane"),
User("mike"),
- ]
- tmpl = env.from_string('{{ users|map(attribute="name")|join("|") }}')
+ ]
+ tmpl = env.from_string('{{ users|map(attribute="name")|join("|") }}')
assert tmpl.render(users=users) == "john|jane|mike"
-
- def test_empty_map(self, env):
- env = Environment()
- tmpl = env.from_string('{{ none|map("upper")|list }}')
+
+ def test_empty_map(self, env):
+ env = Environment()
+ tmpl = env.from_string('{{ none|map("upper")|list }}')
assert tmpl.render() == "[]"
-
+
def test_map_default(self, env):
Fullname = namedtuple("Fullname", "firstname,lastname")
Firstname = namedtuple("Firstname", "firstname")
@@ -657,86 +657,86 @@ class TestFilter(object):
]
assert tmpl.render(users=users) == "lennon, edwards, None, smith"
- def test_simple_select(self, env):
- env = Environment()
- tmpl = env.from_string('{{ [1, 2, 3, 4, 5]|select("odd")|join("|") }}')
+ def test_simple_select(self, env):
+ env = Environment()
+ tmpl = env.from_string('{{ [1, 2, 3, 4, 5]|select("odd")|join("|") }}')
assert tmpl.render() == "1|3|5"
-
- def test_bool_select(self, env):
- env = Environment()
+
+ def test_bool_select(self, env):
+ env = Environment()
tmpl = env.from_string('{{ [none, false, 0, 1, 2, 3, 4, 5]|select|join("|") }}')
assert tmpl.render() == "1|2|3|4|5"
-
- def test_simple_reject(self, env):
- env = Environment()
- tmpl = env.from_string('{{ [1, 2, 3, 4, 5]|reject("odd")|join("|") }}')
+
+ def test_simple_reject(self, env):
+ env = Environment()
+ tmpl = env.from_string('{{ [1, 2, 3, 4, 5]|reject("odd")|join("|") }}')
assert tmpl.render() == "2|4"
-
- def test_bool_reject(self, env):
- env = Environment()
+
+ def test_bool_reject(self, env):
+ env = Environment()
tmpl = env.from_string('{{ [none, false, 0, 1, 2, 3, 4, 5]|reject|join("|") }}')
assert tmpl.render() == "None|False|0"
-
- def test_simple_select_attr(self, env):
+
+ def test_simple_select_attr(self, env):
User = namedtuple("User", "name,is_active")
- env = Environment()
- users = [
+ env = Environment()
+ users = [
User("john", True),
User("jane", True),
User("mike", False),
- ]
- tmpl = env.from_string(
+ ]
+ tmpl = env.from_string(
'{{ users|selectattr("is_active")|map(attribute="name")|join("|") }}'
- )
+ )
assert tmpl.render(users=users) == "john|jane"
-
- def test_simple_reject_attr(self, env):
+
+ def test_simple_reject_attr(self, env):
User = namedtuple("User", "name,is_active")
- env = Environment()
- users = [
+ env = Environment()
+ users = [
User("john", True),
User("jane", True),
User("mike", False),
- ]
+ ]
tmpl = env.from_string(
'{{ users|rejectattr("is_active")|map(attribute="name")|join("|") }}'
)
assert tmpl.render(users=users) == "mike"
-
- def test_func_select_attr(self, env):
+
+ def test_func_select_attr(self, env):
User = namedtuple("User", "id,name")
- env = Environment()
- users = [
+ env = Environment()
+ users = [
User(1, "john"),
User(2, "jane"),
User(3, "mike"),
- ]
+ ]
tmpl = env.from_string(
'{{ users|selectattr("id", "odd")|map(attribute="name")|join("|") }}'
)
assert tmpl.render(users=users) == "john|mike"
-
- def test_func_reject_attr(self, env):
+
+ def test_func_reject_attr(self, env):
User = namedtuple("User", "id,name")
- env = Environment()
- users = [
+ env = Environment()
+ users = [
User(1, "john"),
User(2, "jane"),
User(3, "mike"),
- ]
+ ]
tmpl = env.from_string(
'{{ users|rejectattr("id", "odd")|map(attribute="name")|join("|") }}'
)
assert tmpl.render(users=users) == "jane"
-
- def test_json_dump(self):
- env = Environment(autoescape=True)
+
+ def test_json_dump(self):
+ env = Environment(autoescape=True)
t = env.from_string("{{ x|tojson }}")
assert t.render(x={"foo": "bar"}) == '{"foo": "bar"}'
assert t.render(x="\"ba&r'") == r'"\"ba\u0026r\u0027"'
assert t.render(x="<bar>") == r'"\u003cbar\u003e"'
-
- def my_dumps(value, **options):
+
+ def my_dumps(value, **options):
assert options == {"foo": "bar"}
return "42"
diff --git a/contrib/python/Jinja2/py2/tests/test_idtracking.py b/contrib/python/Jinja2/py2/tests/test_idtracking.py
index 4c79ee6c47..2cb8d2dc65 100644
--- a/contrib/python/Jinja2/py2/tests/test_idtracking.py
+++ b/contrib/python/Jinja2/py2/tests/test_idtracking.py
@@ -1,9 +1,9 @@
-from jinja2 import nodes
-from jinja2.idtracking import symbols_for_node
-
-
-def test_basics():
- for_loop = nodes.For(
+from jinja2 import nodes
+from jinja2.idtracking import symbols_for_node
+
+
+def test_basics():
+ for_loop = nodes.For(
nodes.Name("foo", "store"),
nodes.Name("seq", "load"),
[nodes.Output([nodes.Name("foo", "load")])],
@@ -14,33 +14,33 @@ def test_basics():
tmpl = nodes.Template(
[nodes.Assign(nodes.Name("foo", "store"), nodes.Name("bar", "load")), for_loop]
)
-
- sym = symbols_for_node(tmpl)
- assert sym.refs == {
+
+ sym = symbols_for_node(tmpl)
+ assert sym.refs == {
"foo": "l_0_foo",
"bar": "l_0_bar",
"seq": "l_0_seq",
- }
- assert sym.loads == {
+ }
+ assert sym.loads == {
"l_0_foo": ("undefined", None),
"l_0_bar": ("resolve", "bar"),
"l_0_seq": ("resolve", "seq"),
- }
-
- sym = symbols_for_node(for_loop, sym)
- assert sym.refs == {
+ }
+
+ sym = symbols_for_node(for_loop, sym)
+ assert sym.refs == {
"foo": "l_1_foo",
- }
- assert sym.loads == {
+ }
+ assert sym.loads == {
"l_1_foo": ("param", None),
- }
-
-
-def test_complex():
+ }
+
+
+def test_complex():
title_block = nodes.Block(
"title", [nodes.Output([nodes.TemplateData(u"Page Title")])], False
)
-
+
render_title_macro = nodes.Macro(
"render_title",
[nodes.Name("title", "param")],
@@ -97,8 +97,8 @@ def test_complex():
),
],
)
-
- for_loop = nodes.For(
+
+ for_loop = nodes.For(
nodes.Name("item", "store"),
nodes.Name("seq", "load"),
[
@@ -116,7 +116,7 @@ def test_complex():
None,
False,
)
-
+
body_block = nodes.Block(
"body",
[
@@ -138,7 +138,7 @@ def test_complex():
],
False,
)
-
+
tmpl = nodes.Template(
[
nodes.Extends(nodes.Const("layout.html")),
@@ -147,68 +147,68 @@ def test_complex():
body_block,
]
)
-
- tmpl_sym = symbols_for_node(tmpl)
- assert tmpl_sym.refs == {
+
+ tmpl_sym = symbols_for_node(tmpl)
+ assert tmpl_sym.refs == {
"render_title": "l_0_render_title",
- }
- assert tmpl_sym.loads == {
+ }
+ assert tmpl_sym.loads == {
"l_0_render_title": ("undefined", None),
- }
+ }
assert tmpl_sym.stores == set(["render_title"])
- assert tmpl_sym.dump_stores() == {
+ assert tmpl_sym.dump_stores() == {
"render_title": "l_0_render_title",
- }
-
- macro_sym = symbols_for_node(render_title_macro, tmpl_sym)
- assert macro_sym.refs == {
+ }
+
+ macro_sym = symbols_for_node(render_title_macro, tmpl_sym)
+ assert macro_sym.refs == {
"subtitle": "l_1_subtitle",
"something": "l_1_something",
"title": "l_1_title",
"title_upper": "l_1_title_upper",
- }
- assert macro_sym.loads == {
+ }
+ assert macro_sym.loads == {
"l_1_subtitle": ("resolve", "subtitle"),
"l_1_something": ("resolve", "something"),
"l_1_title": ("param", None),
"l_1_title_upper": ("resolve", "title_upper"),
- }
+ }
assert macro_sym.stores == set(["title", "title_upper", "subtitle"])
assert macro_sym.find_ref("render_title") == "l_0_render_title"
- assert macro_sym.dump_stores() == {
+ assert macro_sym.dump_stores() == {
"title": "l_1_title",
"title_upper": "l_1_title_upper",
"subtitle": "l_1_subtitle",
"render_title": "l_0_render_title",
- }
-
- body_sym = symbols_for_node(body_block)
- assert body_sym.refs == {
+ }
+
+ body_sym = symbols_for_node(body_block)
+ assert body_sym.refs == {
"item": "l_0_item",
"seq": "l_0_seq",
"render_title": "l_0_render_title",
- }
- assert body_sym.loads == {
+ }
+ assert body_sym.loads == {
"l_0_item": ("resolve", "item"),
"l_0_seq": ("resolve", "seq"),
"l_0_render_title": ("resolve", "render_title"),
- }
- assert body_sym.stores == set([])
-
- for_sym = symbols_for_node(for_loop, body_sym)
- assert for_sym.refs == {
+ }
+ assert body_sym.stores == set([])
+
+ for_sym = symbols_for_node(for_loop, body_sym)
+ assert for_sym.refs == {
"item": "l_1_item",
- }
- assert for_sym.loads == {
+ }
+ assert for_sym.loads == {
"l_1_item": ("param", None),
- }
+ }
assert for_sym.stores == set(["item"])
- assert for_sym.dump_stores() == {
+ assert for_sym.dump_stores() == {
"item": "l_1_item",
- }
-
-
-def test_if_branching_stores():
+ }
+
+
+def test_if_branching_stores():
tmpl = nodes.Template(
[
nodes.If(
@@ -219,20 +219,20 @@ def test_if_branching_stores():
)
]
)
-
- sym = symbols_for_node(tmpl)
+
+ sym = symbols_for_node(tmpl)
assert sym.refs == {"variable": "l_0_variable", "expression": "l_0_expression"}
assert sym.stores == set(["variable"])
- assert sym.loads == {
+ assert sym.loads == {
"l_0_variable": ("resolve", "variable"),
"l_0_expression": ("resolve", "expression"),
- }
- assert sym.dump_stores() == {
+ }
+ assert sym.dump_stores() == {
"variable": "l_0_variable",
- }
-
-
-def test_if_branching_stores_undefined():
+ }
+
+
+def test_if_branching_stores_undefined():
tmpl = nodes.Template(
[
nodes.Assign(nodes.Name("variable", "store"), nodes.Const(23)),
@@ -244,20 +244,20 @@ def test_if_branching_stores_undefined():
),
]
)
-
- sym = symbols_for_node(tmpl)
+
+ sym = symbols_for_node(tmpl)
assert sym.refs == {"variable": "l_0_variable", "expression": "l_0_expression"}
assert sym.stores == set(["variable"])
- assert sym.loads == {
+ assert sym.loads == {
"l_0_variable": ("undefined", None),
"l_0_expression": ("resolve", "expression"),
- }
- assert sym.dump_stores() == {
+ }
+ assert sym.dump_stores() == {
"variable": "l_0_variable",
- }
-
-
-def test_if_branching_multi_scope():
+ }
+
+
+def test_if_branching_multi_scope():
for_loop = nodes.For(
nodes.Name("item", "store"),
nodes.Name("seq", "load"),
@@ -274,16 +274,16 @@ def test_if_branching_multi_scope():
None,
False,
)
-
+
tmpl = nodes.Template(
[nodes.Assign(nodes.Name("x", "store"), nodes.Const(23)), for_loop]
)
-
- tmpl_sym = symbols_for_node(tmpl)
- for_sym = symbols_for_node(for_loop, tmpl_sym)
+
+ tmpl_sym = symbols_for_node(tmpl)
+ for_sym = symbols_for_node(for_loop, tmpl_sym)
assert for_sym.stores == set(["item", "x"])
- assert for_sym.loads == {
+ assert for_sym.loads == {
"l_1_x": ("alias", "l_0_x"),
"l_1_item": ("param", None),
"l_1_expression": ("resolve", "expression"),
- }
+ }
diff --git a/contrib/python/Jinja2/py2/tests/test_imports.py b/contrib/python/Jinja2/py2/tests/test_imports.py
index fad2edafb6..7f8eb6ef31 100644
--- a/contrib/python/Jinja2/py2/tests/test_imports.py
+++ b/contrib/python/Jinja2/py2/tests/test_imports.py
@@ -1,15 +1,15 @@
-# -*- coding: utf-8 -*-
-import pytest
-
+# -*- coding: utf-8 -*-
+import pytest
+
from jinja2 import DictLoader
from jinja2 import Environment
from jinja2.exceptions import TemplateNotFound
from jinja2.exceptions import TemplatesNotFound
from jinja2.exceptions import TemplateSyntaxError
-
-
-@pytest.fixture
-def test_env():
+
+
+@pytest.fixture
+def test_env():
env = Environment(
loader=DictLoader(
dict(
@@ -20,128 +20,128 @@ def test_env():
)
)
env.globals["bar"] = 23
- return env
-
-
-class TestImports(object):
- def test_context_imports(self, test_env):
- t = test_env.from_string('{% import "module" as m %}{{ m.test() }}')
+ return env
+
+
+class TestImports(object):
+ def test_context_imports(self, test_env):
+ t = test_env.from_string('{% import "module" as m %}{{ m.test() }}')
assert t.render(foo=42) == "[|23]"
- t = test_env.from_string(
- '{% import "module" as m without context %}{{ m.test() }}'
- )
+ t = test_env.from_string(
+ '{% import "module" as m without context %}{{ m.test() }}'
+ )
assert t.render(foo=42) == "[|23]"
- t = test_env.from_string(
- '{% import "module" as m with context %}{{ m.test() }}'
- )
+ t = test_env.from_string(
+ '{% import "module" as m with context %}{{ m.test() }}'
+ )
assert t.render(foo=42) == "[42|23]"
- t = test_env.from_string('{% from "module" import test %}{{ test() }}')
+ t = test_env.from_string('{% from "module" import test %}{{ test() }}')
assert t.render(foo=42) == "[|23]"
- t = test_env.from_string(
- '{% from "module" import test without context %}{{ test() }}'
- )
+ t = test_env.from_string(
+ '{% from "module" import test without context %}{{ test() }}'
+ )
assert t.render(foo=42) == "[|23]"
- t = test_env.from_string(
- '{% from "module" import test with context %}{{ test() }}'
- )
+ t = test_env.from_string(
+ '{% from "module" import test with context %}{{ test() }}'
+ )
assert t.render(foo=42) == "[42|23]"
-
- def test_import_needs_name(self, test_env):
- test_env.from_string('{% from "foo" import bar %}')
- test_env.from_string('{% from "foo" import bar, baz %}')
-
- with pytest.raises(TemplateSyntaxError):
- test_env.from_string('{% from "foo" import %}')
-
- def test_no_trailing_comma(self, test_env):
- with pytest.raises(TemplateSyntaxError):
- test_env.from_string('{% from "foo" import bar, %}')
-
- with pytest.raises(TemplateSyntaxError):
- test_env.from_string('{% from "foo" import bar,, %}')
-
- with pytest.raises(TemplateSyntaxError):
- test_env.from_string('{% from "foo" import, %}')
-
- def test_trailing_comma_with_context(self, test_env):
- test_env.from_string('{% from "foo" import bar, baz with context %}')
- test_env.from_string('{% from "foo" import bar, baz, with context %}')
- test_env.from_string('{% from "foo" import bar, with context %}')
- test_env.from_string('{% from "foo" import bar, with, context %}')
- test_env.from_string('{% from "foo" import bar, with with context %}')
-
- with pytest.raises(TemplateSyntaxError):
- test_env.from_string('{% from "foo" import bar,, with context %}')
-
- with pytest.raises(TemplateSyntaxError):
- test_env.from_string('{% from "foo" import bar with context, %}')
-
- def test_exports(self, test_env):
+
+ def test_import_needs_name(self, test_env):
+ test_env.from_string('{% from "foo" import bar %}')
+ test_env.from_string('{% from "foo" import bar, baz %}')
+
+ with pytest.raises(TemplateSyntaxError):
+ test_env.from_string('{% from "foo" import %}')
+
+ def test_no_trailing_comma(self, test_env):
+ with pytest.raises(TemplateSyntaxError):
+ test_env.from_string('{% from "foo" import bar, %}')
+
+ with pytest.raises(TemplateSyntaxError):
+ test_env.from_string('{% from "foo" import bar,, %}')
+
+ with pytest.raises(TemplateSyntaxError):
+ test_env.from_string('{% from "foo" import, %}')
+
+ def test_trailing_comma_with_context(self, test_env):
+ test_env.from_string('{% from "foo" import bar, baz with context %}')
+ test_env.from_string('{% from "foo" import bar, baz, with context %}')
+ test_env.from_string('{% from "foo" import bar, with context %}')
+ test_env.from_string('{% from "foo" import bar, with, context %}')
+ test_env.from_string('{% from "foo" import bar, with with context %}')
+
+ with pytest.raises(TemplateSyntaxError):
+ test_env.from_string('{% from "foo" import bar,, with context %}')
+
+ with pytest.raises(TemplateSyntaxError):
+ test_env.from_string('{% from "foo" import bar with context, %}')
+
+ def test_exports(self, test_env):
m = test_env.from_string(
"""
- {% macro toplevel() %}...{% endmacro %}
- {% macro __private() %}...{% endmacro %}
- {% set variable = 42 %}
- {% for item in [1] %}
- {% macro notthere() %}{% endmacro %}
- {% endfor %}
+ {% macro toplevel() %}...{% endmacro %}
+ {% macro __private() %}...{% endmacro %}
+ {% set variable = 42 %}
+ {% for item in [1] %}
+ {% macro notthere() %}{% endmacro %}
+ {% endfor %}
"""
).module
assert m.toplevel() == "..."
assert not hasattr(m, "__missing")
- assert m.variable == 42
+ assert m.variable == 42
assert not hasattr(m, "notthere")
-
-
-class TestIncludes(object):
- def test_context_include(self, test_env):
- t = test_env.from_string('{% include "header" %}')
+
+
+class TestIncludes(object):
+ def test_context_include(self, test_env):
+ t = test_env.from_string('{% include "header" %}')
assert t.render(foo=42) == "[42|23]"
- t = test_env.from_string('{% include "header" with context %}')
+ t = test_env.from_string('{% include "header" with context %}')
assert t.render(foo=42) == "[42|23]"
- t = test_env.from_string('{% include "header" without context %}')
+ t = test_env.from_string('{% include "header" without context %}')
assert t.render(foo=42) == "[|23]"
-
- def test_choice_includes(self, test_env):
- t = test_env.from_string('{% include ["missing", "header"] %}')
+
+ def test_choice_includes(self, test_env):
+ t = test_env.from_string('{% include ["missing", "header"] %}')
assert t.render(foo=42) == "[42|23]"
-
+
t = test_env.from_string('{% include ["missing", "missing2"] ignore missing %}')
assert t.render(foo=42) == ""
-
- t = test_env.from_string('{% include ["missing", "missing2"] %}')
- pytest.raises(TemplateNotFound, t.render)
+
+ t = test_env.from_string('{% include ["missing", "missing2"] %}')
+ pytest.raises(TemplateNotFound, t.render)
with pytest.raises(TemplatesNotFound) as e:
- t.render()
-
+ t.render()
+
assert e.value.templates == ["missing", "missing2"]
assert e.value.name == "missing2"
- def test_includes(t, **ctx):
+ def test_includes(t, **ctx):
ctx["foo"] = 42
assert t.render(ctx) == "[42|23]"
-
- t = test_env.from_string('{% include ["missing", "header"] %}')
- test_includes(t)
+
+ t = test_env.from_string('{% include ["missing", "header"] %}')
+ test_includes(t)
t = test_env.from_string("{% include x %}")
test_includes(t, x=["missing", "header"])
- t = test_env.from_string('{% include [x, "header"] %}')
+ t = test_env.from_string('{% include [x, "header"] %}')
test_includes(t, x="missing")
t = test_env.from_string("{% include x %}")
test_includes(t, x="header")
t = test_env.from_string("{% include [x] %}")
test_includes(t, x="header")
-
- def test_include_ignoring_missing(self, test_env):
- t = test_env.from_string('{% include "missing" %}')
- pytest.raises(TemplateNotFound, t.render)
+
+ def test_include_ignoring_missing(self, test_env):
+ t = test_env.from_string('{% include "missing" %}')
+ pytest.raises(TemplateNotFound, t.render)
for extra in "", "with context", "without context":
t = test_env.from_string(
'{% include "missing" ignore missing ' + extra + " %}"
)
assert t.render() == ""
-
- def test_context_include_with_overrides(self, test_env):
+
+ def test_context_include_with_overrides(self, test_env):
env = Environment(
loader=DictLoader(
dict(
@@ -150,23 +150,23 @@ class TestIncludes(object):
)
)
)
- assert env.get_template("main").render() == "123"
-
- def test_unoptimized_scopes(self, test_env):
+ assert env.get_template("main").render() == "123"
+
+ def test_unoptimized_scopes(self, test_env):
t = test_env.from_string(
"""
- {% macro outer(o) %}
- {% macro inner() %}
- {% include "o_printer" %}
- {% endmacro %}
- {{ inner() }}
- {% endmacro %}
- {{ outer("FOO") }}
+ {% macro outer(o) %}
+ {% macro inner() %}
+ {% include "o_printer" %}
+ {% endmacro %}
+ {{ inner() }}
+ {% endmacro %}
+ {{ outer("FOO") }}
"""
)
assert t.render().strip() == "(FOO)"
-
- def test_import_from_with_context(self):
+
+ def test_import_from_with_context(self):
env = Environment(
loader=DictLoader({"a": "{% macro x() %}{{ foobar }}{% endmacro %}"})
)
diff --git a/contrib/python/Jinja2/py2/tests/test_inheritance.py b/contrib/python/Jinja2/py2/tests/test_inheritance.py
index e513d2e3eb..27baaef7a4 100644
--- a/contrib/python/Jinja2/py2/tests/test_inheritance.py
+++ b/contrib/python/Jinja2/py2/tests/test_inheritance.py
@@ -1,63 +1,63 @@
-# -*- coding: utf-8 -*-
-import pytest
-
+# -*- coding: utf-8 -*-
+import pytest
+
from jinja2 import DictLoader
from jinja2 import Environment
from jinja2 import TemplateRuntimeError
-
+
LAYOUTTEMPLATE = """\
-|{% block block1 %}block 1 from layout{% endblock %}
-|{% block block2 %}block 2 from layout{% endblock %}
-|{% block block3 %}
-{% block block4 %}nested block 4 from layout{% endblock %}
+|{% block block1 %}block 1 from layout{% endblock %}
+|{% block block2 %}block 2 from layout{% endblock %}
+|{% block block3 %}
+{% block block4 %}nested block 4 from layout{% endblock %}
{% endblock %}|"""
-
+
LEVEL1TEMPLATE = """\
-{% extends "layout" %}
+{% extends "layout" %}
{% block block1 %}block 1 from level1{% endblock %}"""
-
+
LEVEL2TEMPLATE = """\
-{% extends "level1" %}
-{% block block2 %}{% block block5 %}nested block 5 from level2{%
+{% extends "level1" %}
+{% block block2 %}{% block block5 %}nested block 5 from level2{%
endblock %}{% endblock %}"""
-
+
LEVEL3TEMPLATE = """\
-{% extends "level2" %}
-{% block block5 %}block 5 from level3{% endblock %}
-{% block block4 %}block 4 from level3{% endblock %}
+{% extends "level2" %}
+{% block block5 %}block 5 from level3{% endblock %}
+{% block block4 %}block 4 from level3{% endblock %}
"""
-
+
LEVEL4TEMPLATE = """\
-{% extends "level3" %}
-{% block block3 %}block 3 from level4{% endblock %}
+{% extends "level3" %}
+{% block block3 %}block 3 from level4{% endblock %}
"""
-
+
WORKINGTEMPLATE = """\
-{% extends "layout" %}
-{% block block1 %}
- {% if false %}
- {% block block2 %}
- this should workd
- {% endblock %}
- {% endif %}
-{% endblock %}
+{% extends "layout" %}
+{% block block1 %}
+ {% if false %}
+ {% block block2 %}
+ this should workd
+ {% endblock %}
+ {% endif %}
+{% endblock %}
"""
-
+
DOUBLEEXTENDS = """\
-{% extends "layout" %}
-{% extends "layout" %}
-{% block block1 %}
- {% if false %}
- {% block block2 %}
- this should workd
- {% endblock %}
- {% endif %}
-{% endblock %}
+{% extends "layout" %}
+{% extends "layout" %}
+{% block block1 %}
+ {% if false %}
+ {% block block2 %}
+ this should workd
+ {% endblock %}
+ {% endif %}
+{% endblock %}
"""
-
-
-@pytest.fixture
-def env():
+
+
+@pytest.fixture
+def env():
return Environment(
loader=DictLoader(
{
@@ -72,41 +72,41 @@ def env():
),
trim_blocks=True,
)
-
-
-class TestInheritance(object):
- def test_layout(self, env):
+
+
+class TestInheritance(object):
+ def test_layout(self, env):
tmpl = env.get_template("layout")
assert tmpl.render() == (
"|block 1 from layout|block 2 from layout|nested block 4 from layout|"
)
-
- def test_level1(self, env):
+
+ def test_level1(self, env):
tmpl = env.get_template("level1")
assert tmpl.render() == (
"|block 1 from level1|block 2 from layout|nested block 4 from layout|"
)
-
- def test_level2(self, env):
+
+ def test_level2(self, env):
tmpl = env.get_template("level2")
assert tmpl.render() == (
"|block 1 from level1|nested block 5 from "
"level2|nested block 4 from layout|"
)
-
- def test_level3(self, env):
+
+ def test_level3(self, env):
tmpl = env.get_template("level3")
assert tmpl.render() == (
"|block 1 from level1|block 5 from level3|block 4 from level3|"
)
-
- def test_level4(self, env):
+
+ def test_level4(self, env):
tmpl = env.get_template("level4")
assert tmpl.render() == (
"|block 1 from level1|block 5 from level3|block 3 from level4|"
)
-
- def test_super(self, env):
+
+ def test_super(self, env):
env = Environment(
loader=DictLoader(
{
@@ -122,17 +122,17 @@ class TestInheritance(object):
)
tmpl = env.get_template("c")
assert tmpl.render() == "--INTRO--|BEFORE|[(INNER)]|AFTER"
-
- def test_working(self, env):
+
+ def test_working(self, env):
env.get_template("working")
-
- def test_reuse_blocks(self, env):
+
+ def test_reuse_blocks(self, env):
tmpl = env.from_string(
"{{ self.foo() }}|{% block foo %}42{% endblock %}|{{ self.foo() }}"
)
assert tmpl.render() == "42|42|42"
-
- def test_preserve_blocks(self, env):
+
+ def test_preserve_blocks(self, env):
env = Environment(
loader=DictLoader(
{
@@ -144,8 +144,8 @@ class TestInheritance(object):
)
tmpl = env.get_template("b")
assert tmpl.render() == "BA"
-
- def test_dynamic_inheritance(self, env):
+
+ def test_dynamic_inheritance(self, env):
env = Environment(
loader=DictLoader(
{
@@ -156,10 +156,10 @@ class TestInheritance(object):
)
)
tmpl = env.get_template("child")
- for m in range(1, 3):
+ for m in range(1, 3):
assert tmpl.render(master="master%d" % m) == "MASTER%dCHILD" % m
-
- def test_multi_inheritance(self, env):
+
+ def test_multi_inheritance(self, env):
env = Environment(
loader=DictLoader(
{
@@ -174,8 +174,8 @@ class TestInheritance(object):
assert tmpl.render(master="master2") == "MASTER2CHILD"
assert tmpl.render(master="master1") == "MASTER1CHILD"
assert tmpl.render() == "MASTER1CHILD"
-
- def test_scoped_block(self, env):
+
+ def test_scoped_block(self, env):
env = Environment(
loader=DictLoader(
{
@@ -188,8 +188,8 @@ class TestInheritance(object):
"{% extends 'master.html' %}{% block item %}{{ item }}{% endblock %}"
)
assert t.render(seq=list(range(5))) == "[0][1][2][3][4]"
-
- def test_super_in_scoped_block(self, env):
+
+ def test_super_in_scoped_block(self, env):
env = Environment(
loader=DictLoader(
{
@@ -203,70 +203,70 @@ class TestInheritance(object):
"{{ super() }}|{{ item * 2 }}{% endblock %}"
)
assert t.render(seq=list(range(5))) == "[0|0][1|2][2|4][3|6][4|8]"
-
- def test_scoped_block_after_inheritance(self, env):
+
+ def test_scoped_block_after_inheritance(self, env):
env = Environment(
loader=DictLoader(
{
"layout.html": """
- {% block useless %}{% endblock %}
+ {% block useless %}{% endblock %}
""",
"index.html": """
- {%- extends 'layout.html' %}
- {% from 'helpers.html' import foo with context %}
- {% block useless %}
- {% for x in [1, 2, 3] %}
- {% block testing scoped %}
- {{ foo(x) }}
- {% endblock %}
- {% endfor %}
- {% endblock %}
+ {%- extends 'layout.html' %}
+ {% from 'helpers.html' import foo with context %}
+ {% block useless %}
+ {% for x in [1, 2, 3] %}
+ {% block testing scoped %}
+ {{ foo(x) }}
+ {% endblock %}
+ {% endfor %}
+ {% endblock %}
""",
"helpers.html": """
- {% macro foo(x) %}{{ the_foo + x }}{% endmacro %}
+ {% macro foo(x) %}{{ the_foo + x }}{% endmacro %}
""",
}
)
)
rv = env.get_template("index.html").render(the_foo=42).split()
assert rv == ["43", "44", "45"]
-
-
-class TestBugFix(object):
- def test_fixed_macro_scoping_bug(self, env):
+
+
+class TestBugFix(object):
+ def test_fixed_macro_scoping_bug(self, env):
assert (
Environment(
loader=DictLoader(
{
"test.html": """\
- {% extends 'details.html' %}
-
- {% macro my_macro() %}
- my_macro
- {% endmacro %}
-
- {% block inner_box %}
- {{ my_macro() }}
- {% endblock %}
+ {% extends 'details.html' %}
+
+ {% macro my_macro() %}
+ my_macro
+ {% endmacro %}
+
+ {% block inner_box %}
+ {{ my_macro() }}
+ {% endblock %}
""",
"details.html": """\
- {% extends 'standard.html' %}
-
- {% macro my_macro() %}
- my_macro
- {% endmacro %}
-
- {% block content %}
- {% block outer_box %}
- outer_box
- {% block inner_box %}
- inner_box
- {% endblock %}
- {% endblock %}
- {% endblock %}
+ {% extends 'standard.html' %}
+
+ {% macro my_macro() %}
+ my_macro
+ {% endmacro %}
+
+ {% block content %}
+ {% block outer_box %}
+ outer_box
+ {% block inner_box %}
+ inner_box
+ {% endblock %}
+ {% endblock %}
+ {% endblock %}
""",
"standard.html": """
- {% block content %}&nbsp;{% endblock %}
+ {% block content %}&nbsp;{% endblock %}
""",
}
)
@@ -276,10 +276,10 @@ class TestBugFix(object):
.split()
== [u"outer_box", u"my_macro"]
)
-
- def test_double_extends(self, env):
- """Ensures that a template with more than 1 {% extends ... %} usage
- raises a ``TemplateError``.
- """
+
+ def test_double_extends(self, env):
+ """Ensures that a template with more than 1 {% extends ... %} usage
+ raises a ``TemplateError``.
+ """
with pytest.raises(TemplateRuntimeError, match="extended multiple times"):
env.get_template("doublee").render()
diff --git a/contrib/python/Jinja2/py2/tests/test_lexnparse.py b/contrib/python/Jinja2/py2/tests/test_lexnparse.py
index 83ae75e05c..9e83a34621 100644
--- a/contrib/python/Jinja2/py2/tests/test_lexnparse.py
+++ b/contrib/python/Jinja2/py2/tests/test_lexnparse.py
@@ -1,6 +1,6 @@
-# -*- coding: utf-8 -*-
-import pytest
-
+# -*- coding: utf-8 -*-
+import pytest
+
from jinja2 import Environment
from jinja2 import nodes
from jinja2 import Template
@@ -14,59 +14,59 @@ from jinja2.lexer import TOKEN_BLOCK_BEGIN
from jinja2.lexer import TOKEN_BLOCK_END
from jinja2.lexer import TOKEN_EOF
from jinja2.lexer import TokenStream
+
+
+# how does a string look like in jinja syntax?
+if PY2:
+ def jinja_string_repr(string):
+ return repr(string)[1:]
-# how does a string look like in jinja syntax?
-if PY2:
-
- def jinja_string_repr(string):
- return repr(string)[1:]
-
-
-else:
- jinja_string_repr = repr
-
-class TestTokenStream(object):
+else:
+ jinja_string_repr = repr
+
+
+class TestTokenStream(object):
test_tokens = [
Token(1, TOKEN_BLOCK_BEGIN, ""),
Token(2, TOKEN_BLOCK_END, ""),
]
-
- def test_simple(self, env):
- ts = TokenStream(self.test_tokens, "foo", "bar")
- assert ts.current.type is TOKEN_BLOCK_BEGIN
- assert bool(ts)
- assert not bool(ts.eos)
- next(ts)
- assert ts.current.type is TOKEN_BLOCK_END
- assert bool(ts)
- assert not bool(ts.eos)
- next(ts)
- assert ts.current.type is TOKEN_EOF
- assert not bool(ts)
- assert bool(ts.eos)
-
- def test_iter(self, env):
+
+ def test_simple(self, env):
+ ts = TokenStream(self.test_tokens, "foo", "bar")
+ assert ts.current.type is TOKEN_BLOCK_BEGIN
+ assert bool(ts)
+ assert not bool(ts.eos)
+ next(ts)
+ assert ts.current.type is TOKEN_BLOCK_END
+ assert bool(ts)
+ assert not bool(ts.eos)
+ next(ts)
+ assert ts.current.type is TOKEN_EOF
+ assert not bool(ts)
+ assert bool(ts.eos)
+
+ def test_iter(self, env):
token_types = [t.type for t in TokenStream(self.test_tokens, "foo", "bar")]
assert token_types == [
"block_begin",
"block_end",
- ]
-
-
-class TestLexer(object):
- def test_raw1(self, env):
- tmpl = env.from_string(
+ ]
+
+
+class TestLexer(object):
+ def test_raw1(self, env):
+ tmpl = env.from_string(
"{% raw %}foo{% endraw %}|"
"{%raw%}{{ bar }}|{% baz %}{% endraw %}"
)
assert tmpl.render() == "foo|{{ bar }}|{% baz %}"
-
- def test_raw2(self, env):
+
+ def test_raw2(self, env):
tmpl = env.from_string("1 {%- raw -%} 2 {%- endraw -%} 3")
assert tmpl.render() == "123"
-
+
def test_raw3(self, env):
# The second newline after baz exists because it is AFTER the
# {% raw %} and is ignored.
@@ -83,71 +83,71 @@ class TestLexer(object):
)
assert tmpl.render() == "bar2 spaces\n spacefoo"
- def test_balancing(self, env):
+ def test_balancing(self, env):
env = Environment("{%", "%}", "${", "}")
tmpl = env.from_string(
"""{% for item in seq
%}${{'foo': item}|upper}{% endfor %}"""
)
assert tmpl.render(seq=list(range(3))) == "{'FOO': 0}{'FOO': 1}{'FOO': 2}"
-
- def test_comments(self, env):
+
+ def test_comments(self, env):
env = Environment("<!--", "-->", "{", "}")
tmpl = env.from_string(
"""\
-<ul>
-<!--- for item in seq -->
- <li>{item}</li>
-<!--- endfor -->
+<ul>
+<!--- for item in seq -->
+ <li>{item}</li>
+<!--- endfor -->
</ul>"""
)
assert tmpl.render(seq=list(range(3))) == (
"<ul>\n <li>0</li>\n <li>1</li>\n <li>2</li>\n</ul>"
)
-
- def test_string_escapes(self, env):
+
+ def test_string_escapes(self, env):
for char in u"\0", u"\u2668", u"\xe4", u"\t", u"\r", u"\n":
tmpl = env.from_string("{{ %s }}" % jinja_string_repr(char))
- assert tmpl.render() == char
+ assert tmpl.render() == char
assert env.from_string('{{ "\N{HOT SPRINGS}" }}').render() == u"\u2668"
-
- def test_bytefallback(self, env):
- from pprint import pformat
-
+
+ def test_bytefallback(self, env):
+ from pprint import pformat
+
tmpl = env.from_string(u"""{{ 'foo'|pprint }}|{{ 'bär'|pprint }}""")
assert tmpl.render() == pformat("foo") + "|" + pformat(u"bär")
- def test_operators(self, env):
- from jinja2.lexer import operators
+ def test_operators(self, env):
+ from jinja2.lexer import operators
- for test, expect in iteritems(operators):
+ for test, expect in iteritems(operators):
if test in "([{}])":
- continue
+ continue
stream = env.lexer.tokenize("{{ %s }}" % test)
- next(stream)
- assert stream.current.type == expect
-
- def test_normalizing(self, env):
+ next(stream)
+ assert stream.current.type == expect
+
+ def test_normalizing(self, env):
for seq in "\r", "\r\n", "\n":
- env = Environment(newline_sequence=seq)
+ env = Environment(newline_sequence=seq)
tmpl = env.from_string("1\n2\r\n3\n4\n")
- result = tmpl.render()
+ result = tmpl.render()
assert result.replace(seq, "X") == "1X2X3X4"
-
- def test_trailing_newline(self, env):
- for keep in [True, False]:
- env = Environment(keep_trailing_newline=keep)
- for template, expected in [
+
+ def test_trailing_newline(self, env):
+ for keep in [True, False]:
+ env = Environment(keep_trailing_newline=keep)
+ for template, expected in [
("", {}),
("no\nnewline", {}),
("with\nnewline\n", {False: "with\nnewline"}),
("with\nseveral\n\n\n", {False: "with\nseveral\n\n"}),
]:
- tmpl = env.from_string(template)
- expect = expected.get(keep, template)
- result = tmpl.render()
- assert result == expect, (keep, template, result, expect)
-
+ tmpl = env.from_string(template)
+ expect = expected.get(keep, template)
+ result = tmpl.render()
+ assert result == expect, (keep, template, result, expect)
+
@pytest.mark.parametrize(
"name,valid2,valid3",
(
@@ -169,15 +169,15 @@ class TestLexer(object):
(u"a\xb7", False, True),
),
)
- def test_name(self, env, name, valid2, valid3):
+ def test_name(self, env, name, valid2, valid3):
t = u"{{ " + name + u" }}"
-
- if (valid2 and PY2) or (valid3 and not PY2):
- # valid for version being tested, shouldn't raise
- env.from_string(t)
- else:
- pytest.raises(TemplateSyntaxError, env.from_string, t)
-
+
+ if (valid2 and PY2) or (valid3 and not PY2):
+ # valid for version being tested, shouldn't raise
+ env.from_string(t)
+ else:
+ pytest.raises(TemplateSyntaxError, env.from_string, t)
+
def test_lineno_with_strip(self, env):
tokens = env.lex(
"""\
@@ -195,110 +195,110 @@ class TestLexer(object):
if token_type == "name" and value == "item":
assert lineno == 5
break
+
-
-class TestParser(object):
- def test_php_syntax(self, env):
+class TestParser(object):
+ def test_php_syntax(self, env):
env = Environment("<?", "?>", "<?=", "?>", "<!--", "-->")
tmpl = env.from_string(
"""\
-<!-- I'm a comment, I'm not interesting -->\
-<? for item in seq -?>
- <?= item ?>
+<!-- I'm a comment, I'm not interesting -->\
+<? for item in seq -?>
+ <?= item ?>
<?- endfor ?>"""
)
assert tmpl.render(seq=list(range(5))) == "01234"
-
- def test_erb_syntax(self, env):
+
+ def test_erb_syntax(self, env):
env = Environment("<%", "%>", "<%=", "%>", "<%#", "%>")
tmpl = env.from_string(
"""\
-<%# I'm a comment, I'm not interesting %>\
-<% for item in seq -%>
- <%= item %>
+<%# I'm a comment, I'm not interesting %>\
+<% for item in seq -%>
+ <%= item %>
<%- endfor %>"""
)
assert tmpl.render(seq=list(range(5))) == "01234"
-
- def test_comment_syntax(self, env):
+
+ def test_comment_syntax(self, env):
env = Environment("<!--", "-->", "${", "}", "<!--#", "-->")
tmpl = env.from_string(
"""\
-<!--# I'm a comment, I'm not interesting -->\
-<!-- for item in seq --->
- ${item}
+<!--# I'm a comment, I'm not interesting -->\
+<!-- for item in seq --->
+ ${item}
<!--- endfor -->"""
)
assert tmpl.render(seq=list(range(5))) == "01234"
-
- def test_balancing(self, env):
+
+ def test_balancing(self, env):
tmpl = env.from_string("""{{{'foo':'bar'}.foo}}""")
assert tmpl.render() == "bar"
-
- def test_start_comment(self, env):
+
+ def test_start_comment(self, env):
tmpl = env.from_string(
"""{# foo comment
-and bar comment #}
-{% macro blub() %}foo{% endmacro %}
+and bar comment #}
+{% macro blub() %}foo{% endmacro %}
{{ blub() }}"""
)
assert tmpl.render().strip() == "foo"
-
- def test_line_syntax(self, env):
+
+ def test_line_syntax(self, env):
env = Environment("<%", "%>", "${", "}", "<%#", "%>", "%")
tmpl = env.from_string(
"""\
-<%# regular comment %>
-% for item in seq:
- ${item}
+<%# regular comment %>
+% for item in seq:
+ ${item}
% endfor"""
)
- assert [
- int(x.strip()) for x in tmpl.render(seq=list(range(5))).split()
- ] == list(range(5))
-
+ assert [
+ int(x.strip()) for x in tmpl.render(seq=list(range(5))).split()
+ ] == list(range(5))
+
env = Environment("<%", "%>", "${", "}", "<%#", "%>", "%", "##")
tmpl = env.from_string(
"""\
-<%# regular comment %>
-% for item in seq:
- ${item} ## the rest of the stuff
+<%# regular comment %>
+% for item in seq:
+ ${item} ## the rest of the stuff
% endfor"""
)
- assert [
- int(x.strip()) for x in tmpl.render(seq=list(range(5))).split()
- ] == list(range(5))
-
- def test_line_syntax_priority(self, env):
- # XXX: why is the whitespace there in front of the newline?
+ assert [
+ int(x.strip()) for x in tmpl.render(seq=list(range(5))).split()
+ ] == list(range(5))
+
+ def test_line_syntax_priority(self, env):
+ # XXX: why is the whitespace there in front of the newline?
env = Environment("{%", "%}", "${", "}", "/*", "*/", "##", "#")
tmpl = env.from_string(
"""\
-/* ignore me.
- I'm a multiline comment */
-## for item in seq:
-* ${item} # this is just extra stuff
+/* ignore me.
+ I'm a multiline comment */
+## for item in seq:
+* ${item} # this is just extra stuff
## endfor"""
)
assert tmpl.render(seq=[1, 2]).strip() == "* 1\n* 2"
env = Environment("{%", "%}", "${", "}", "/*", "*/", "#", "##")
tmpl = env.from_string(
"""\
-/* ignore me.
- I'm a multiline comment */
-# for item in seq:
-* ${item} ## this is just extra stuff
- ## extra stuff i just want to ignore
+/* ignore me.
+ I'm a multiline comment */
+# for item in seq:
+* ${item} ## this is just extra stuff
+ ## extra stuff i just want to ignore
# endfor"""
)
assert tmpl.render(seq=[1, 2]).strip() == "* 1\n\n* 2"
-
- def test_error_messages(self, env):
- def assert_error(code, expected):
+
+ def test_error_messages(self, env):
+ def assert_error(code, expected):
with pytest.raises(TemplateSyntaxError, match=expected):
- Template(code)
-
- assert_error(
+ Template(code)
+
+ assert_error(
"{% for item in seq %}...{% endif %}",
"Encountered unknown tag 'endif'. Jinja was looking "
"for the following tags: 'endfor' or 'else'. The "
@@ -306,11 +306,11 @@ and bar comment #}
)
assert_error(
"{% if foo %}{% for item in seq %}...{% endfor %}{% endfor %}",
- "Encountered unknown tag 'endfor'. Jinja was looking for "
- "the following tags: 'elif' or 'else' or 'endif'. The "
+ "Encountered unknown tag 'endfor'. Jinja was looking for "
+ "the following tags: 'elif' or 'else' or 'endif'. The "
"innermost block that needs to be closed is 'if'.",
)
- assert_error(
+ assert_error(
"{% if foo %}",
"Unexpected end of template. Jinja was looking for the "
"following tags: 'elif' or 'else' or 'endif'. The "
@@ -324,51 +324,51 @@ and bar comment #}
)
assert_error(
"{% block foo-bar-baz %}",
- "Block names in Jinja have to be valid Python identifiers "
+ "Block names in Jinja have to be valid Python identifiers "
"and may not contain hyphens, use an underscore instead.",
)
assert_error("{% unknown_tag %}", "Encountered unknown tag 'unknown_tag'.")
-
-
-class TestSyntax(object):
- def test_call(self, env):
- env = Environment()
+
+
+class TestSyntax(object):
+ def test_call(self, env):
+ env = Environment()
env.globals["foo"] = lambda a, b, c, e, g: a + b + c + e + g
tmpl = env.from_string("{{ foo('a', c='d', e='f', *['b'], **{'g': 'h'}) }}")
assert tmpl.render() == "abdfh"
-
- def test_slicing(self, env):
+
+ def test_slicing(self, env):
tmpl = env.from_string("{{ [1, 2, 3][:] }}|{{ [1, 2, 3][::-1] }}")
assert tmpl.render() == "[1, 2, 3]|[3, 2, 1]"
-
- def test_attr(self, env):
- tmpl = env.from_string("{{ foo.bar }}|{{ foo['bar'] }}")
+
+ def test_attr(self, env):
+ tmpl = env.from_string("{{ foo.bar }}|{{ foo['bar'] }}")
assert tmpl.render(foo={"bar": 42}) == "42|42"
-
- def test_subscript(self, env):
- tmpl = env.from_string("{{ foo[0] }}|{{ foo[-1] }}")
+
+ def test_subscript(self, env):
+ tmpl = env.from_string("{{ foo[0] }}|{{ foo[-1] }}")
assert tmpl.render(foo=[0, 1, 2]) == "0|2"
-
- def test_tuple(self, env):
+
+ def test_tuple(self, env):
tmpl = env.from_string("{{ () }}|{{ (1,) }}|{{ (1, 2) }}")
assert tmpl.render() == "()|(1,)|(1, 2)"
-
- def test_math(self, env):
+
+ def test_math(self, env):
tmpl = env.from_string("{{ (1 + 1 * 2) - 3 / 2 }}|{{ 2**3 }}")
assert tmpl.render() == "1.5|8"
-
- def test_div(self, env):
+
+ def test_div(self, env):
tmpl = env.from_string("{{ 3 // 2 }}|{{ 3 / 2 }}|{{ 3 % 2 }}")
assert tmpl.render() == "1|1.5|1"
-
- def test_unary(self, env):
+
+ def test_unary(self, env):
tmpl = env.from_string("{{ +3 }}|{{ -3 }}")
assert tmpl.render() == "3|-3"
-
- def test_concat(self, env):
- tmpl = env.from_string("{{ [1, 2] ~ 'foo' }}")
+
+ def test_concat(self, env):
+ tmpl = env.from_string("{{ [1, 2] ~ 'foo' }}")
assert tmpl.render() == "[1, 2]foo"
-
+
@pytest.mark.parametrize(
("a", "op", "b"),
[
@@ -383,7 +383,7 @@ class TestSyntax(object):
def test_compare(self, env, a, op, b):
t = env.from_string("{{ %d %s %d }}" % (a, op, b))
assert t.render() == "True"
-
+
def test_compare_parens(self, env):
t = env.from_string("{{ i * (j < 5) }}")
assert t.render(i=2, j=3) == "2"
@@ -403,15 +403,15 @@ class TestSyntax(object):
t = env.from_string(src)
assert t.render(a=4, b=2, c=3) == expect
- def test_inop(self, env):
+ def test_inop(self, env):
tmpl = env.from_string("{{ 1 in [1, 2, 3] }}|{{ 1 not in [1, 2, 3] }}")
assert tmpl.render() == "True|False"
-
+
@pytest.mark.parametrize("value", ("[]", "{}", "()"))
def test_collection_literal(self, env, value):
t = env.from_string("{{ %s }}" % value)
assert t.render() == value
-
+
@pytest.mark.parametrize(
("value", "expect"),
(
@@ -433,39 +433,39 @@ class TestSyntax(object):
t = env.from_string("{{ %s }}" % value)
assert t.render() == expect
- def test_bool(self, env):
+ def test_bool(self, env):
tmpl = env.from_string(
"{{ true and false }}|{{ false or true }}|{{ not false }}"
)
assert tmpl.render() == "False|True|True"
-
- def test_grouping(self, env):
- tmpl = env.from_string(
+
+ def test_grouping(self, env):
+ tmpl = env.from_string(
"{{ (true and false) or (false and true) and not false }}"
)
assert tmpl.render() == "False"
-
- def test_django_attr(self, env):
+
+ def test_django_attr(self, env):
tmpl = env.from_string("{{ [1, 2, 3].0 }}|{{ [[1]].0.0 }}")
assert tmpl.render() == "1|1"
-
- def test_conditional_expression(self, env):
+
+ def test_conditional_expression(self, env):
tmpl = env.from_string("""{{ 0 if true else 1 }}""")
assert tmpl.render() == "0"
-
- def test_short_conditional_expression(self, env):
+
+ def test_short_conditional_expression(self, env):
tmpl = env.from_string("<{{ 1 if false }}>")
assert tmpl.render() == "<>"
-
+
tmpl = env.from_string("<{{ (1 if false).bar }}>")
- pytest.raises(UndefinedError, tmpl.render)
-
- def test_filter_priority(self, env):
- tmpl = env.from_string('{{ "foo"|upper + "bar"|upper }}')
+ pytest.raises(UndefinedError, tmpl.render)
+
+ def test_filter_priority(self, env):
+ tmpl = env.from_string('{{ "foo"|upper + "bar"|upper }}')
assert tmpl.render() == "FOOBAR"
-
- def test_function_calls(self, env):
- tests = [
+
+ def test_function_calls(self, env):
+ tests = [
(True, "*foo, bar"),
(True, "*foo, *bar"),
(True, "**foo, *bar"),
@@ -481,17 +481,17 @@ class TestSyntax(object):
(False, "*foo, **bar"),
(False, "*foo, bar=42, **baz"),
(False, "foo, *args, bar=23, **baz"),
- ]
- for should_fail, sig in tests:
- if should_fail:
+ ]
+ for should_fail, sig in tests:
+ if should_fail:
pytest.raises(
TemplateSyntaxError, env.from_string, "{{ foo(%s) }}" % sig
)
- else:
+ else:
env.from_string("foo(%s)" % sig)
-
- def test_tuple_expr(self, env):
- for tmpl in [
+
+ def test_tuple_expr(self, env):
+ for tmpl in [
"{{ () }}",
"{{ (1, 2) }}",
"{{ (1, 2,) }}",
@@ -500,107 +500,107 @@ class TestSyntax(object):
"{% for foo, bar in seq %}...{% endfor %}",
"{% for x in foo, bar %}...{% endfor %}",
"{% for x in foo, %}...{% endfor %}",
- ]:
- assert env.from_string(tmpl)
-
- def test_trailing_comma(self, env):
+ ]:
+ assert env.from_string(tmpl)
+
+ def test_trailing_comma(self, env):
tmpl = env.from_string("{{ (1, 2,) }}|{{ [1, 2,] }}|{{ {1: 2,} }}")
assert tmpl.render().lower() == "(1, 2)|[1, 2]|{1: 2}"
-
- def test_block_end_name(self, env):
+
+ def test_block_end_name(self, env):
env.from_string("{% block foo %}...{% endblock foo %}")
pytest.raises(
TemplateSyntaxError, env.from_string, "{% block x %}{% endblock y %}"
)
-
- def test_constant_casing(self, env):
- for const in True, False, None:
+
+ def test_constant_casing(self, env):
+ for const in True, False, None:
tmpl = env.from_string(
"{{ %s }}|{{ %s }}|{{ %s }}"
% (str(const), str(const).lower(), str(const).upper())
)
assert tmpl.render() == "%s|%s|" % (const, const)
-
- def test_test_chaining(self, env):
+
+ def test_test_chaining(self, env):
pytest.raises(
TemplateSyntaxError, env.from_string, "{{ foo is string is sequence }}"
)
assert env.from_string("{{ 42 is string or 42 is number }}").render() == "True"
-
- def test_string_concatenation(self, env):
- tmpl = env.from_string('{{ "foo" "bar" "baz" }}')
+
+ def test_string_concatenation(self, env):
+ tmpl = env.from_string('{{ "foo" "bar" "baz" }}')
assert tmpl.render() == "foobarbaz"
-
- def test_notin(self, env):
- bar = range(100)
+
+ def test_notin(self, env):
+ bar = range(100)
tmpl = env.from_string("""{{ not 42 in bar }}""")
assert tmpl.render(bar=bar) == "False"
-
- def test_operator_precedence(self, env):
+
+ def test_operator_precedence(self, env):
tmpl = env.from_string("""{{ 2 * 3 + 4 % 2 + 1 - 2 }}""")
- assert tmpl.render() == text_type(2 * 3 + 4 % 2 + 1 - 2)
-
- def test_implicit_subscribed_tuple(self, env):
- class Foo(object):
- def __getitem__(self, x):
- return x
-
+ assert tmpl.render() == text_type(2 * 3 + 4 % 2 + 1 - 2)
+
+ def test_implicit_subscribed_tuple(self, env):
+ class Foo(object):
+ def __getitem__(self, x):
+ return x
+
t = env.from_string("{{ foo[1, 2] }}")
assert t.render(foo=Foo()) == u"(1, 2)"
- def test_raw2(self, env):
+ def test_raw2(self, env):
tmpl = env.from_string("{% raw %}{{ FOO }} and {% BAR %}{% endraw %}")
assert tmpl.render() == "{{ FOO }} and {% BAR %}"
-
- def test_const(self, env):
- tmpl = env.from_string(
+
+ def test_const(self, env):
+ tmpl = env.from_string(
"{{ true }}|{{ false }}|{{ none }}|"
"{{ none is defined }}|{{ missing is defined }}"
)
assert tmpl.render() == "True|False|None|True|False"
-
- def test_neg_filter_priority(self, env):
+
+ def test_neg_filter_priority(self, env):
node = env.parse("{{ -1|foo }}")
- assert isinstance(node.body[0].nodes[0], nodes.Filter)
- assert isinstance(node.body[0].nodes[0].node, nodes.Neg)
-
- def test_const_assign(self, env):
+ assert isinstance(node.body[0].nodes[0], nodes.Filter)
+ assert isinstance(node.body[0].nodes[0].node, nodes.Neg)
+
+ def test_const_assign(self, env):
constass1 = """{% set true = 42 %}"""
constass2 = """{% for none in seq %}{% endfor %}"""
- for tmpl in constass1, constass2:
- pytest.raises(TemplateSyntaxError, env.from_string, tmpl)
-
- def test_localset(self, env):
+ for tmpl in constass1, constass2:
+ pytest.raises(TemplateSyntaxError, env.from_string, tmpl)
+
+ def test_localset(self, env):
tmpl = env.from_string(
"""{% set foo = 0 %}\
-{% for item in [1, 2] %}{% set foo = 1 %}{% endfor %}\
+{% for item in [1, 2] %}{% set foo = 1 %}{% endfor %}\
{{ foo }}"""
)
assert tmpl.render() == "0"
-
- def test_parse_unary(self, env):
- tmpl = env.from_string('{{ -foo["bar"] }}')
+
+ def test_parse_unary(self, env):
+ tmpl = env.from_string('{{ -foo["bar"] }}')
assert tmpl.render(foo={"bar": 42}) == "-42"
- tmpl = env.from_string('{{ -foo["bar"]|abs }}')
+ tmpl = env.from_string('{{ -foo["bar"]|abs }}')
assert tmpl.render(foo={"bar": 42}) == "42"
-
-
-class TestLstripBlocks(object):
- def test_lstrip(self, env):
- env = Environment(lstrip_blocks=True, trim_blocks=False)
+
+
+class TestLstripBlocks(object):
+ def test_lstrip(self, env):
+ env = Environment(lstrip_blocks=True, trim_blocks=False)
tmpl = env.from_string(""" {% if True %}\n {% endif %}""")
- assert tmpl.render() == "\n"
-
- def test_lstrip_trim(self, env):
- env = Environment(lstrip_blocks=True, trim_blocks=True)
+ assert tmpl.render() == "\n"
+
+ def test_lstrip_trim(self, env):
+ env = Environment(lstrip_blocks=True, trim_blocks=True)
tmpl = env.from_string(""" {% if True %}\n {% endif %}""")
- assert tmpl.render() == ""
-
- def test_no_lstrip(self, env):
- env = Environment(lstrip_blocks=True, trim_blocks=False)
+ assert tmpl.render() == ""
+
+ def test_no_lstrip(self, env):
+ env = Environment(lstrip_blocks=True, trim_blocks=False)
tmpl = env.from_string(""" {%+ if True %}\n {%+ endif %}""")
- assert tmpl.render() == " \n "
-
+ assert tmpl.render() == " \n "
+
def test_lstrip_blocks_false_with_no_lstrip(self, env):
# Test that + is a NOP (but does not cause an error) if lstrip_blocks=False
env = Environment(lstrip_blocks=False, trim_blocks=False)
@@ -609,51 +609,51 @@ class TestLstripBlocks(object):
tmpl = env.from_string(""" {%+ if True %}\n {%+ endif %}""")
assert tmpl.render() == " \n "
- def test_lstrip_endline(self, env):
- env = Environment(lstrip_blocks=True, trim_blocks=False)
+ def test_lstrip_endline(self, env):
+ env = Environment(lstrip_blocks=True, trim_blocks=False)
tmpl = env.from_string(""" hello{% if True %}\n goodbye{% endif %}""")
- assert tmpl.render() == " hello\n goodbye"
-
- def test_lstrip_inline(self, env):
- env = Environment(lstrip_blocks=True, trim_blocks=False)
+ assert tmpl.render() == " hello\n goodbye"
+
+ def test_lstrip_inline(self, env):
+ env = Environment(lstrip_blocks=True, trim_blocks=False)
tmpl = env.from_string(""" {% if True %}hello {% endif %}""")
assert tmpl.render() == "hello "
-
- def test_lstrip_nested(self, env):
- env = Environment(lstrip_blocks=True, trim_blocks=False)
- tmpl = env.from_string(
+
+ def test_lstrip_nested(self, env):
+ env = Environment(lstrip_blocks=True, trim_blocks=False)
+ tmpl = env.from_string(
""" {% if True %}a {% if True %}b {% endif %}c {% endif %}"""
)
assert tmpl.render() == "a b c "
-
- def test_lstrip_left_chars(self, env):
- env = Environment(lstrip_blocks=True, trim_blocks=False)
+
+ def test_lstrip_left_chars(self, env):
+ env = Environment(lstrip_blocks=True, trim_blocks=False)
tmpl = env.from_string(
""" abc {% if True %}
hello{% endif %}"""
)
assert tmpl.render() == " abc \n hello"
-
- def test_lstrip_embeded_strings(self, env):
- env = Environment(lstrip_blocks=True, trim_blocks=False)
+
+ def test_lstrip_embeded_strings(self, env):
+ env = Environment(lstrip_blocks=True, trim_blocks=False)
tmpl = env.from_string(""" {% set x = " {% str %} " %}{{ x }}""")
assert tmpl.render() == " {% str %} "
-
- def test_lstrip_preserve_leading_newlines(self, env):
- env = Environment(lstrip_blocks=True, trim_blocks=False)
+
+ def test_lstrip_preserve_leading_newlines(self, env):
+ env = Environment(lstrip_blocks=True, trim_blocks=False)
tmpl = env.from_string("""\n\n\n{% set hello = 1 %}""")
assert tmpl.render() == "\n\n\n"
-
- def test_lstrip_comment(self, env):
- env = Environment(lstrip_blocks=True, trim_blocks=False)
+
+ def test_lstrip_comment(self, env):
+ env = Environment(lstrip_blocks=True, trim_blocks=False)
tmpl = env.from_string(
""" {# if True #}
-hello
+hello
{#endif#}"""
)
assert tmpl.render() == "\nhello\n"
-
- def test_lstrip_angle_bracket_simple(self, env):
+
+ def test_lstrip_angle_bracket_simple(self, env):
env = Environment(
"<%",
"%>",
@@ -668,8 +668,8 @@ hello
)
tmpl = env.from_string(""" <% if True %>hello <% endif %>""")
assert tmpl.render() == "hello "
-
- def test_lstrip_angle_bracket_comment(self, env):
+
+ def test_lstrip_angle_bracket_comment(self, env):
env = Environment(
"<%",
"%>",
@@ -684,8 +684,8 @@ hello
)
tmpl = env.from_string(""" <%# if True %>hello <%# endif %>""")
assert tmpl.render() == "hello "
-
- def test_lstrip_angle_bracket(self, env):
+
+ def test_lstrip_angle_bracket(self, env):
env = Environment(
"<%",
"%>",
@@ -700,14 +700,14 @@ hello
)
tmpl = env.from_string(
"""\
- <%# regular comment %>
- <% for item in seq %>
-${item} ## the rest of the stuff
+ <%# regular comment %>
+ <% for item in seq %>
+${item} ## the rest of the stuff
<% endfor %>"""
)
assert tmpl.render(seq=range(5)) == "".join("%s\n" % x for x in range(5))
-
- def test_lstrip_angle_bracket_compact(self, env):
+
+ def test_lstrip_angle_bracket_compact(self, env):
env = Environment(
"<%",
"%>",
@@ -722,13 +722,13 @@ ${item} ## the rest of the stuff
)
tmpl = env.from_string(
"""\
- <%#regular comment%>
- <%for item in seq%>
-${item} ## the rest of the stuff
+ <%#regular comment%>
+ <%for item in seq%>
+${item} ## the rest of the stuff
<%endfor%>"""
)
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(
@@ -821,95 +821,95 @@ ${item} ## the rest of the stuff
out = tmpl.render(x=1, y=2)
assert out == "1 2"
- def test_php_syntax_with_manual(self, env):
+ def test_php_syntax_with_manual(self, env):
env = Environment(
"<?", "?>", "<?=", "?>", "<!--", "-->", lstrip_blocks=True, trim_blocks=True
)
tmpl = env.from_string(
"""\
- <!-- I'm a comment, I'm not interesting -->
- <? for item in seq -?>
- <?= item ?>
+ <!-- I'm a comment, I'm not interesting -->
+ <? for item in seq -?>
+ <?= item ?>
<?- endfor ?>"""
)
assert tmpl.render(seq=range(5)) == "01234"
-
- def test_php_syntax(self, env):
+
+ def test_php_syntax(self, env):
env = Environment(
"<?", "?>", "<?=", "?>", "<!--", "-->", lstrip_blocks=True, trim_blocks=True
)
tmpl = env.from_string(
"""\
- <!-- I'm a comment, I'm not interesting -->
- <? for item in seq ?>
- <?= item ?>
+ <!-- I'm a comment, I'm not interesting -->
+ <? for item in seq ?>
+ <?= item ?>
<? endfor ?>"""
)
assert tmpl.render(seq=range(5)) == "".join(
" %s\n" % x for x in range(5)
)
-
- def test_php_syntax_compact(self, env):
+
+ def test_php_syntax_compact(self, env):
env = Environment(
"<?", "?>", "<?=", "?>", "<!--", "-->", lstrip_blocks=True, trim_blocks=True
)
tmpl = env.from_string(
"""\
- <!-- I'm a comment, I'm not interesting -->
- <?for item in seq?>
- <?=item?>
+ <!-- I'm a comment, I'm not interesting -->
+ <?for item in seq?>
+ <?=item?>
<?endfor?>"""
)
assert tmpl.render(seq=range(5)) == "".join(
" %s\n" % x for x in range(5)
)
-
- def test_erb_syntax(self, env):
+
+ def test_erb_syntax(self, env):
env = Environment(
"<%", "%>", "<%=", "%>", "<%#", "%>", lstrip_blocks=True, trim_blocks=True
)
- # env.from_string('')
- # for n,r in env.lexer.rules.iteritems():
- # print n
- # print env.lexer.rules['root'][0][0].pattern
- # print "'%s'" % tmpl.render(seq=range(5))
+ # env.from_string('')
+ # for n,r in env.lexer.rules.iteritems():
+ # print n
+ # print env.lexer.rules['root'][0][0].pattern
+ # print "'%s'" % tmpl.render(seq=range(5))
tmpl = env.from_string(
"""\
-<%# I'm a comment, I'm not interesting %>
- <% for item in seq %>
- <%= item %>
- <% endfor %>
+<%# I'm a comment, I'm not interesting %>
+ <% for item in seq %>
+ <%= item %>
+ <% endfor %>
"""
)
assert tmpl.render(seq=range(5)) == "".join(" %s\n" % x for x in range(5))
-
- def test_erb_syntax_with_manual(self, env):
+
+ def test_erb_syntax_with_manual(self, env):
env = Environment(
"<%", "%>", "<%=", "%>", "<%#", "%>", lstrip_blocks=True, trim_blocks=True
)
tmpl = env.from_string(
"""\
-<%# I'm a comment, I'm not interesting %>
- <% for item in seq -%>
- <%= item %>
+<%# I'm a comment, I'm not interesting %>
+ <% for item in seq -%>
+ <%= item %>
<%- endfor %>"""
)
assert tmpl.render(seq=range(5)) == "01234"
-
- def test_erb_syntax_no_lstrip(self, env):
+
+ def test_erb_syntax_no_lstrip(self, env):
env = Environment(
"<%", "%>", "<%=", "%>", "<%#", "%>", lstrip_blocks=True, trim_blocks=True
)
tmpl = env.from_string(
"""\
-<%# I'm a comment, I'm not interesting %>
- <%+ for item in seq -%>
- <%= item %>
+<%# I'm a comment, I'm not interesting %>
+ <%+ for item in seq -%>
+ <%= item %>
<%- endfor %>"""
)
assert tmpl.render(seq=range(5)) == " 01234"
-
- def test_comment_syntax(self, env):
+
+ def test_comment_syntax(self, env):
env = Environment(
"<!--",
"-->",
@@ -922,9 +922,9 @@ ${item} ## the rest of the stuff
)
tmpl = env.from_string(
"""\
-<!--# I'm a comment, I'm not interesting -->\
-<!-- for item in seq --->
- ${item}
+<!--# I'm a comment, I'm not interesting -->\
+<!-- for item in seq --->
+ ${item}
<!--- endfor -->"""
)
assert tmpl.render(seq=range(5)) == "01234"
diff --git a/contrib/python/Jinja2/py2/tests/test_loader.py b/contrib/python/Jinja2/py2/tests/test_loader.py
index c613186606..3fa5423774 100644
--- a/contrib/python/Jinja2/py2/tests/test_loader.py
+++ b/contrib/python/Jinja2/py2/tests/test_loader.py
@@ -1,11 +1,11 @@
-# -*- coding: utf-8 -*-
-import os
+# -*- coding: utf-8 -*-
+import os
import shutil
-import sys
-import tempfile
+import sys
+import tempfile
import time
-import weakref
-
+import weakref
+
import pytest
from jinja2 import Environment
@@ -13,24 +13,24 @@ from jinja2 import loaders
from jinja2._compat import PY2
from jinja2._compat import PYPY
from jinja2.exceptions import TemplateNotFound
-from jinja2.loaders import split_template_path
-
+from jinja2.loaders import split_template_path
+
import yatest.common as yc
+
-
-class TestLoaders(object):
- def test_dict_loader(self, dict_loader):
- env = Environment(loader=dict_loader)
+class TestLoaders(object):
+ def test_dict_loader(self, dict_loader):
+ env = Environment(loader=dict_loader)
tmpl = env.get_template("justdict.html")
assert tmpl.render().strip() == "FOO"
pytest.raises(TemplateNotFound, env.get_template, "missing.html")
-
- def test_package_loader(self, package_loader):
- env = Environment(loader=package_loader)
+
+ def test_package_loader(self, package_loader):
+ env = Environment(loader=package_loader)
tmpl = env.get_template("test.html")
assert tmpl.render().strip() == "BAR"
pytest.raises(TemplateNotFound, env.get_template, "missing.html")
-
+
def test_filesystem_loader_overlapping_names(self, filesystem_loader):
res = os.path.dirname(filesystem_loader.searchpath[0])
t2_dir = os.path.join(res, "templates2")
@@ -40,83 +40,83 @@ class TestLoaders(object):
e.get_template("foo")
# This would raise NotADirectoryError if "t2/foo" wasn't skipped.
e.get_template("foo/test.html")
-
- def test_choice_loader(self, choice_loader):
- env = Environment(loader=choice_loader)
+
+ def test_choice_loader(self, choice_loader):
+ env = Environment(loader=choice_loader)
tmpl = env.get_template("justdict.html")
assert tmpl.render().strip() == "FOO"
tmpl = env.get_template("test.html")
assert tmpl.render().strip() == "BAR"
pytest.raises(TemplateNotFound, env.get_template, "missing.html")
-
- def test_function_loader(self, function_loader):
- env = Environment(loader=function_loader)
+
+ def test_function_loader(self, function_loader):
+ env = Environment(loader=function_loader)
tmpl = env.get_template("justfunction.html")
assert tmpl.render().strip() == "FOO"
pytest.raises(TemplateNotFound, env.get_template, "missing.html")
-
- def test_prefix_loader(self, prefix_loader):
- env = Environment(loader=prefix_loader)
+
+ def test_prefix_loader(self, prefix_loader):
+ env = Environment(loader=prefix_loader)
tmpl = env.get_template("a/test.html")
assert tmpl.render().strip() == "BAR"
tmpl = env.get_template("b/justdict.html")
assert tmpl.render().strip() == "FOO"
pytest.raises(TemplateNotFound, env.get_template, "missing")
-
- def test_caching(self):
- changed = False
-
- class TestLoader(loaders.BaseLoader):
- def get_source(self, environment, template):
+
+ def test_caching(self):
+ changed = False
+
+ class TestLoader(loaders.BaseLoader):
+ def get_source(self, environment, template):
return u"foo", None, lambda: not changed
- env = Environment(loader=TestLoader(), cache_size=-1)
+ env = Environment(loader=TestLoader(), cache_size=-1)
tmpl = env.get_template("template")
assert tmpl is env.get_template("template")
- changed = True
+ changed = True
assert tmpl is not env.get_template("template")
- changed = False
-
- def test_no_cache(self):
+ changed = False
+
+ def test_no_cache(self):
mapping = {"foo": "one"}
- env = Environment(loader=loaders.DictLoader(mapping), cache_size=0)
+ env = Environment(loader=loaders.DictLoader(mapping), cache_size=0)
assert env.get_template("foo") is not env.get_template("foo")
-
- def test_limited_size_cache(self):
+
+ def test_limited_size_cache(self):
mapping = {"one": "foo", "two": "bar", "three": "baz"}
- loader = loaders.DictLoader(mapping)
- env = Environment(loader=loader, cache_size=2)
+ loader = loaders.DictLoader(mapping)
+ env = Environment(loader=loader, cache_size=2)
t1 = env.get_template("one")
t2 = env.get_template("two")
assert t2 is env.get_template("two")
assert t1 is env.get_template("one")
env.get_template("three")
- loader_ref = weakref.ref(loader)
+ loader_ref = weakref.ref(loader)
assert (loader_ref, "one") in env.cache
assert (loader_ref, "two") not in env.cache
assert (loader_ref, "three") in env.cache
-
- def test_cache_loader_change(self):
+
+ def test_cache_loader_change(self):
loader1 = loaders.DictLoader({"foo": "one"})
loader2 = loaders.DictLoader({"foo": "two"})
- env = Environment(loader=loader1, cache_size=2)
+ env = Environment(loader=loader1, cache_size=2)
assert env.get_template("foo").render() == "one"
- env.loader = loader2
+ env.loader = loader2
assert env.get_template("foo").render() == "two"
-
- def test_dict_loader_cache_invalidates(self):
+
+ def test_dict_loader_cache_invalidates(self):
mapping = {"foo": "one"}
- env = Environment(loader=loaders.DictLoader(mapping))
+ env = Environment(loader=loaders.DictLoader(mapping))
assert env.get_template("foo").render() == "one"
mapping["foo"] = "two"
assert env.get_template("foo").render() == "two"
-
- def test_split_template_path(self):
+
+ def test_split_template_path(self):
assert split_template_path("foo/bar") == ["foo", "bar"]
assert split_template_path("./foo/bar") == ["foo", "bar"]
pytest.raises(TemplateNotFound, split_template_path, "../foo")
-
-
+
+
class TestFileSystemLoader(object):
searchpath = os.path.join(
yc.test_source_path(), "res", "templates"
@@ -185,33 +185,33 @@ class TestFileSystemLoader(object):
assert t.render() == expect
-class TestModuleLoader(object):
- archive = None
-
+class TestModuleLoader(object):
+ archive = None
+
def compile_down(self, prefix_loader, zip="deflated", py_compile=False):
- log = []
- self.reg_env = Environment(loader=prefix_loader)
- if zip is not None:
+ log = []
+ self.reg_env = Environment(loader=prefix_loader)
+ if zip is not None:
fd, self.archive = tempfile.mkstemp(suffix=".zip")
- os.close(fd)
- else:
- self.archive = tempfile.mkdtemp()
+ os.close(fd)
+ else:
+ self.archive = tempfile.mkdtemp()
self.reg_env.compile_templates(
self.archive, zip=zip, log_function=log.append, py_compile=py_compile
)
- self.mod_env = Environment(loader=loaders.ModuleLoader(self.archive))
+ self.mod_env = Environment(loader=loaders.ModuleLoader(self.archive))
return "".join(log)
-
- def teardown(self):
+
+ def teardown(self):
if hasattr(self, "mod_env"):
- if os.path.isfile(self.archive):
- os.remove(self.archive)
- else:
- shutil.rmtree(self.archive)
- self.archive = None
-
- def test_log(self, prefix_loader):
- log = self.compile_down(prefix_loader)
+ if os.path.isfile(self.archive):
+ os.remove(self.archive)
+ else:
+ shutil.rmtree(self.archive)
+ self.archive = None
+
+ def test_log(self, prefix_loader):
+ log = self.compile_down(prefix_loader)
assert (
'Compiled "a/foo/test.html" as '
"tmpl_a790caf9d669e39ea4d280d597ec891c4ef0404a" in log
@@ -221,61 +221,61 @@ class TestModuleLoader(object):
'Could not compile "a/syntaxerror.html": '
"Encountered unknown tag 'endif'" in log
)
-
- def _test_common(self):
+
+ def _test_common(self):
tmpl1 = self.reg_env.get_template("a/test.html")
tmpl2 = self.mod_env.get_template("a/test.html")
- assert tmpl1.render() == tmpl2.render()
-
+ assert tmpl1.render() == tmpl2.render()
+
tmpl1 = self.reg_env.get_template("b/justdict.html")
tmpl2 = self.mod_env.get_template("b/justdict.html")
- assert tmpl1.render() == tmpl2.render()
-
- def test_deflated_zip_compile(self, prefix_loader):
+ assert tmpl1.render() == tmpl2.render()
+
+ def test_deflated_zip_compile(self, prefix_loader):
self.compile_down(prefix_loader, zip="deflated")
- self._test_common()
-
- def test_stored_zip_compile(self, prefix_loader):
+ self._test_common()
+
+ def test_stored_zip_compile(self, prefix_loader):
self.compile_down(prefix_loader, zip="stored")
- self._test_common()
-
- def test_filesystem_compile(self, prefix_loader):
- self.compile_down(prefix_loader, zip=None)
- self._test_common()
-
- def test_weak_references(self, prefix_loader):
- self.compile_down(prefix_loader)
+ self._test_common()
+
+ def test_filesystem_compile(self, prefix_loader):
+ self.compile_down(prefix_loader, zip=None)
+ self._test_common()
+
+ def test_weak_references(self, prefix_loader):
+ self.compile_down(prefix_loader)
self.mod_env.get_template("a/test.html")
key = loaders.ModuleLoader.get_template_key("a/test.html")
- name = self.mod_env.loader.module.__name__
-
- assert hasattr(self.mod_env.loader.module, key)
- assert name in sys.modules
-
- # unset all, ensure the module is gone from sys.modules
+ name = self.mod_env.loader.module.__name__
+
+ assert hasattr(self.mod_env.loader.module, key)
+ assert name in sys.modules
+
+ # unset all, ensure the module is gone from sys.modules
self.mod_env = None
+
+ try:
+ import gc
- try:
- import gc
-
- gc.collect()
+ gc.collect()
except BaseException:
- pass
-
- assert name not in sys.modules
-
- # This test only makes sense on non-pypy python 2
- @pytest.mark.skipif(
+ pass
+
+ assert name not in sys.modules
+
+ # This test only makes sense on non-pypy python 2
+ @pytest.mark.skipif(
not (PY2 and not PYPY), reason="This test only makes sense on non-pypy python 2"
)
- def test_byte_compilation(self, prefix_loader):
- log = self.compile_down(prefix_loader, py_compile=True)
- assert 'Byte-compiled "a/test.html"' in log
+ def test_byte_compilation(self, prefix_loader):
+ log = self.compile_down(prefix_loader, py_compile=True)
+ assert 'Byte-compiled "a/test.html"' in log
self.mod_env.get_template("a/test.html")
mod = self.mod_env.loader.module.tmpl_3c4ddf650c1a73df961a6d3d2ce2752f1b8fd490
assert mod.__file__.endswith(".pyc")
-
- def test_choice_loader(self, prefix_loader):
+
+ def test_choice_loader(self, prefix_loader):
self.compile_down(prefix_loader)
self.mod_env.loader = loaders.ChoiceLoader(
[self.mod_env.loader, loaders.DictLoader({"DICT_SOURCE": "DICT_TEMPLATE"})]
@@ -284,7 +284,7 @@ class TestModuleLoader(object):
assert tmpl1.render() == "BAR"
tmpl2 = self.mod_env.get_template("DICT_SOURCE")
assert tmpl2.render() == "DICT_TEMPLATE"
-
+
def test_prefix_loader(self, prefix_loader):
self.compile_down(prefix_loader)
self.mod_env.loader = loaders.PrefixLoader(
@@ -297,15 +297,15 @@ class TestModuleLoader(object):
assert tmpl1.render() == "BAR"
tmpl2 = self.mod_env.get_template("DICT/test.html")
assert tmpl2.render() == "DICT_TEMPLATE"
-
+
@pytest.mark.skipif(PY2, reason="pathlib is not available in Python 2")
def test_path_as_pathlib(self, prefix_loader):
self.compile_down(prefix_loader)
-
+
mod_path = self.mod_env.loader.module.__path__[0]
-
+
import pathlib
-
+
mod_loader = loaders.ModuleLoader(pathlib.Path(mod_path))
self.mod_env = Environment(loader=mod_loader)
diff --git a/contrib/python/Jinja2/py2/tests/test_nativetypes.py b/contrib/python/Jinja2/py2/tests/test_nativetypes.py
index 76871ab5de..ae845a0aa4 100644
--- a/contrib/python/Jinja2/py2/tests/test_nativetypes.py
+++ b/contrib/python/Jinja2/py2/tests/test_nativetypes.py
@@ -1,75 +1,75 @@
-import pytest
-
-from jinja2._compat import text_type
-from jinja2.exceptions import UndefinedError
-from jinja2.nativetypes import NativeEnvironment
+import pytest
+
+from jinja2._compat import text_type
+from jinja2.exceptions import UndefinedError
+from jinja2.nativetypes import NativeEnvironment
from jinja2.nativetypes import NativeTemplate
-from jinja2.runtime import Undefined
-
-
-@pytest.fixture
-def env():
- return NativeEnvironment()
-
-
+from jinja2.runtime import Undefined
+
+
+@pytest.fixture
+def env():
+ return NativeEnvironment()
+
+
def test_is_defined_native_return(env):
t = env.from_string("{{ missing is defined }}")
assert not t.render()
-
-
+
+
def test_undefined_native_return(env):
t = env.from_string("{{ missing }}")
assert isinstance(t.render(), Undefined)
-
-
+
+
def test_adding_undefined_native_return(env):
t = env.from_string("{{ 3 + missing }}")
-
+
with pytest.raises(UndefinedError):
t.render()
-
-
+
+
def test_cast_int(env):
t = env.from_string("{{ value|int }}")
result = t.render(value="3")
assert isinstance(result, int)
assert result == 3
-
-
+
+
def test_list_add(env):
t = env.from_string("{{ a + b }}")
result = t.render(a=["a", "b"], b=["c", "d"])
assert isinstance(result, list)
assert result == ["a", "b", "c", "d"]
-
-
+
+
def test_multi_expression_add(env):
t = env.from_string("{{ a }} + {{ b }}")
result = t.render(a=["a", "b"], b=["c", "d"])
assert not isinstance(result, list)
assert result == "['a', 'b'] + ['c', 'd']"
-
-
+
+
def test_loops(env):
t = env.from_string("{% for x in value %}{{ x }}{% endfor %}")
result = t.render(value=["a", "b", "c", "d"])
assert isinstance(result, text_type)
assert result == "abcd"
-
-
+
+
def test_loops_with_ints(env):
t = env.from_string("{% for x in value %}{{ x }}{% endfor %}")
result = t.render(value=[1, 2, 3, 4])
assert isinstance(result, int)
assert result == 1234
-
-
+
+
def test_loop_look_alike(env):
t = env.from_string("{% for x in value %}{{ x }}{% endfor %}")
result = t.render(value=[1])
assert isinstance(result, int)
assert result == 1
-
+
@pytest.mark.parametrize(
("source", "expect"),
diff --git a/contrib/python/Jinja2/py2/tests/test_regression.py b/contrib/python/Jinja2/py2/tests/test_regression.py
index c5a0d68068..b442ab25c7 100644
--- a/contrib/python/Jinja2/py2/tests/test_regression.py
+++ b/contrib/python/Jinja2/py2/tests/test_regression.py
@@ -1,8 +1,8 @@
-# -*- coding: utf-8 -*-
+# -*- coding: utf-8 -*-
import sys
-
-import pytest
-
+
+import pytest
+
from jinja2 import DictLoader
from jinja2 import Environment
from jinja2 import PrefixLoader
@@ -10,211 +10,211 @@ from jinja2 import Template
from jinja2 import TemplateAssertionError
from jinja2 import TemplateNotFound
from jinja2 import TemplateSyntaxError
-from jinja2._compat import text_type
-
-
-class TestCorner(object):
- def test_assigned_scoping(self, env):
+from jinja2._compat import text_type
+
+
+class TestCorner(object):
+ def test_assigned_scoping(self, env):
t = env.from_string(
"""
- {%- for item in (1, 2, 3, 4) -%}
- [{{ item }}]
- {%- endfor %}
- {{- item -}}
+ {%- for item in (1, 2, 3, 4) -%}
+ [{{ item }}]
+ {%- endfor %}
+ {{- item -}}
"""
)
assert t.render(item=42) == "[1][2][3][4]42"
-
+
t = env.from_string(
"""
- {%- for item in (1, 2, 3, 4) -%}
- [{{ item }}]
- {%- endfor %}
- {%- set item = 42 %}
- {{- item -}}
+ {%- for item in (1, 2, 3, 4) -%}
+ [{{ item }}]
+ {%- endfor %}
+ {%- set item = 42 %}
+ {{- item -}}
"""
)
assert t.render() == "[1][2][3][4]42"
-
+
t = env.from_string(
"""
- {%- set item = 42 %}
- {%- for item in (1, 2, 3, 4) -%}
- [{{ item }}]
- {%- endfor %}
- {{- item -}}
+ {%- set item = 42 %}
+ {%- for item in (1, 2, 3, 4) -%}
+ [{{ item }}]
+ {%- endfor %}
+ {{- item -}}
"""
)
assert t.render() == "[1][2][3][4]42"
-
- def test_closure_scoping(self, env):
+
+ def test_closure_scoping(self, env):
t = env.from_string(
"""
- {%- set wrapper = "<FOO>" %}
- {%- for item in (1, 2, 3, 4) %}
- {%- macro wrapper() %}[{{ item }}]{% endmacro %}
- {{- wrapper() }}
- {%- endfor %}
- {{- wrapper -}}
+ {%- set wrapper = "<FOO>" %}
+ {%- for item in (1, 2, 3, 4) %}
+ {%- macro wrapper() %}[{{ item }}]{% endmacro %}
+ {{- wrapper() }}
+ {%- endfor %}
+ {{- wrapper -}}
"""
)
assert t.render() == "[1][2][3][4]<FOO>"
-
+
t = env.from_string(
"""
- {%- for item in (1, 2, 3, 4) %}
- {%- macro wrapper() %}[{{ item }}]{% endmacro %}
- {{- wrapper() }}
- {%- endfor %}
- {%- set wrapper = "<FOO>" %}
- {{- wrapper -}}
+ {%- for item in (1, 2, 3, 4) %}
+ {%- macro wrapper() %}[{{ item }}]{% endmacro %}
+ {{- wrapper() }}
+ {%- endfor %}
+ {%- set wrapper = "<FOO>" %}
+ {{- wrapper -}}
"""
)
assert t.render() == "[1][2][3][4]<FOO>"
-
+
t = env.from_string(
"""
- {%- for item in (1, 2, 3, 4) %}
- {%- macro wrapper() %}[{{ item }}]{% endmacro %}
- {{- wrapper() }}
- {%- endfor %}
- {{- wrapper -}}
+ {%- for item in (1, 2, 3, 4) %}
+ {%- macro wrapper() %}[{{ item }}]{% endmacro %}
+ {{- wrapper() }}
+ {%- endfor %}
+ {{- wrapper -}}
"""
)
assert t.render(wrapper=23) == "[1][2][3][4]23"
-
-
-class TestBug(object):
- def test_keyword_folding(self, env):
- env = Environment()
+
+
+class TestBug(object):
+ def test_keyword_folding(self, env):
+ env = Environment()
env.filters["testing"] = lambda value, some: value + some
assert (
env.from_string("{{ 'test'|testing(some='stuff') }}").render()
== "teststuff"
)
-
- def test_extends_output_bugs(self, env):
+
+ def test_extends_output_bugs(self, env):
env = Environment(
loader=DictLoader({"parent.html": "(({% block title %}{% endblock %}))"})
)
-
- t = env.from_string(
- '{% if expr %}{% extends "parent.html" %}{% endif %}'
+
+ t = env.from_string(
+ '{% if expr %}{% extends "parent.html" %}{% endif %}'
"[[{% block title %}title{% endblock %}]]"
"{% for item in [1, 2, 3] %}({{ item }}){% endfor %}"
- )
+ )
assert t.render(expr=False) == "[[title]](1)(2)(3)"
assert t.render(expr=True) == "((title))"
-
- def test_urlize_filter_escaping(self, env):
- tmpl = env.from_string('{{ "http://www.example.org/<foo"|urlize }}')
+
+ def test_urlize_filter_escaping(self, env):
+ tmpl = env.from_string('{{ "http://www.example.org/<foo"|urlize }}')
assert (
tmpl.render() == '<a href="http://www.example.org/&lt;foo" rel="noopener">'
"http://www.example.org/&lt;foo</a>"
)
-
- def test_loop_call_loop(self, env):
+
+ def test_loop_call_loop(self, env):
tmpl = env.from_string(
"""
-
- {% macro test() %}
- {{ caller() }}
- {% endmacro %}
-
- {% for num1 in range(5) %}
- {% call test() %}
- {% for num2 in range(10) %}
- {{ loop.index }}
- {% endfor %}
- {% endcall %}
- {% endfor %}
-
+
+ {% macro test() %}
+ {{ caller() }}
+ {% endmacro %}
+
+ {% for num1 in range(5) %}
+ {% call test() %}
+ {% for num2 in range(10) %}
+ {{ loop.index }}
+ {% endfor %}
+ {% endcall %}
+ {% endfor %}
+
"""
)
-
+
assert tmpl.render().split() == [text_type(x) for x in range(1, 11)] * 5
-
- def test_weird_inline_comment(self, env):
+
+ def test_weird_inline_comment(self, env):
env = Environment(line_statement_prefix="%")
pytest.raises(
TemplateSyntaxError,
env.from_string,
"% for item in seq {# missing #}\n...% endfor",
)
-
- def test_old_macro_loop_scoping_bug(self, env):
+
+ def test_old_macro_loop_scoping_bug(self, env):
tmpl = env.from_string(
"{% for i in (1, 2) %}{{ i }}{% endfor %}"
"{% macro i() %}3{% endmacro %}{{ i() }}"
)
assert tmpl.render() == "123"
-
- def test_partial_conditional_assignments(self, env):
+
+ def test_partial_conditional_assignments(self, env):
tmpl = env.from_string("{% if b %}{% set a = 42 %}{% endif %}{{ a }}")
assert tmpl.render(a=23) == "23"
assert tmpl.render(b=True) == "42"
-
- def test_stacked_locals_scoping_bug(self, env):
+
+ def test_stacked_locals_scoping_bug(self, env):
env = Environment(line_statement_prefix="#")
t = env.from_string(
"""\
-# for j in [1, 2]:
-# set x = 1
-# for i in [1, 2]:
-# print x
-# if i % 2 == 0:
-# set x = x + 1
-# endif
-# endfor
-# endfor
-# if a
-# print 'A'
-# elif b
-# print 'B'
-# elif c == d
-# print 'C'
-# else
-# print 'D'
-# endif
+# for j in [1, 2]:
+# set x = 1
+# for i in [1, 2]:
+# print x
+# if i % 2 == 0:
+# set x = x + 1
+# endif
+# endfor
+# endfor
+# if a
+# print 'A'
+# elif b
+# print 'B'
+# elif c == d
+# print 'C'
+# else
+# print 'D'
+# endif
"""
)
assert t.render(a=0, b=False, c=42, d=42.0) == "1111C"
-
- def test_stacked_locals_scoping_bug_twoframe(self, env):
+
+ def test_stacked_locals_scoping_bug_twoframe(self, env):
t = Template(
"""
- {% set x = 1 %}
- {% for item in foo %}
- {% if item == 1 %}
- {% set x = 2 %}
- {% endif %}
- {% endfor %}
- {{ x }}
+ {% set x = 1 %}
+ {% for item in foo %}
+ {% if item == 1 %}
+ {% set x = 2 %}
+ {% endif %}
+ {% endfor %}
+ {{ x }}
"""
)
- rv = t.render(foo=[1]).strip()
+ rv = t.render(foo=[1]).strip()
assert rv == u"1"
-
- def test_call_with_args(self, env):
+
+ def test_call_with_args(self, env):
t = Template(
"""{% macro dump_users(users) -%}
- <ul>
- {%- for user in users -%}
- <li><p>{{ user.username|e }}</p>{{ caller(user) }}</li>
- {%- endfor -%}
- </ul>
- {%- endmacro -%}
-
- {% call(user) dump_users(list_of_user) -%}
- <dl>
- <dl>Realname</dl>
- <dd>{{ user.realname|e }}</dd>
- <dl>Description</dl>
- <dd>{{ user.description }}</dd>
- </dl>
+ <ul>
+ {%- for user in users -%}
+ <li><p>{{ user.username|e }}</p>{{ caller(user) }}</li>
+ {%- endfor -%}
+ </ul>
+ {%- endmacro -%}
+
+ {% call(user) dump_users(list_of_user) -%}
+ <dl>
+ <dl>Realname</dl>
+ <dd>{{ user.realname|e }}</dd>
+ <dl>Description</dl>
+ <dd>{{ user.description }}</dd>
+ </dl>
{% endcall %}"""
)
-
+
assert [
x.strip()
for x in t.render(
@@ -234,20 +234,20 @@ class TestBug(object):
u"<dd>test</dd>",
u"</dl>",
u"</li></ul>",
- ]
-
- def test_empty_if_condition_fails(self, env):
+ ]
+
+ def test_empty_if_condition_fails(self, env):
pytest.raises(TemplateSyntaxError, Template, "{% if %}....{% endif %}")
pytest.raises(
TemplateSyntaxError, Template, "{% if foo %}...{% elif %}...{% endif %}"
)
pytest.raises(TemplateSyntaxError, Template, "{% for x in %}..{% endfor %}")
-
+
def test_recursive_loop_compile(self, env):
Template(
"""
{% for p in foo recursive%}
- {{p.bar}}
+ {{p.bar}}
{% for f in p.fields recursive%}
{{f.baz}}
{{p.bar}}
@@ -255,13 +255,13 @@ class TestBug(object):
{{ loop(f.sub) }}
{% endif %}
{% endfor %}
- {% endfor %}
+ {% endfor %}
"""
)
Template(
"""
{% for p in foo%}
- {{p.bar}}
+ {{p.bar}}
{% for f in p.fields recursive%}
{{f.baz}}
{{p.bar}}
@@ -269,159 +269,159 @@ class TestBug(object):
{{ loop(f.sub) }}
{% endif %}
{% endfor %}
- {% endfor %}
+ {% endfor %}
"""
)
-
- def test_else_loop_bug(self, env):
+
+ def test_else_loop_bug(self, env):
t = Template(
"""
- {% for x in y %}
- {{ loop.index0 }}
- {% else %}
- {% for i in range(3) %}{{ i }}{% endfor %}
- {% endfor %}
+ {% for x in y %}
+ {{ loop.index0 }}
+ {% else %}
+ {% for i in range(3) %}{{ i }}{% endfor %}
+ {% endfor %}
"""
)
assert t.render(y=[]).strip() == "012"
-
- def test_correct_prefix_loader_name(self, env):
+
+ def test_correct_prefix_loader_name(self, env):
env = Environment(loader=PrefixLoader({"foo": DictLoader({})}))
with pytest.raises(TemplateNotFound) as e:
env.get_template("foo/bar.html")
-
+
assert e.value.name == "foo/bar.html"
- def test_contextfunction_callable_classes(self, env):
- from jinja2.utils import contextfunction
-
- class CallableClass(object):
- @contextfunction
- def __call__(self, ctx):
+ def test_contextfunction_callable_classes(self, env):
+ from jinja2.utils import contextfunction
+
+ class CallableClass(object):
+ @contextfunction
+ def __call__(self, ctx):
return ctx.resolve("hello")
-
- tpl = Template("""{{ callableclass() }}""")
+
+ tpl = Template("""{{ callableclass() }}""")
output = tpl.render(callableclass=CallableClass(), hello="TEST")
expected = "TEST"
-
- assert output == expected
-
+
+ assert output == expected
+
@pytest.mark.skipif(sys.version_info[0] > 2, reason="This only works on 2.x")
- def test_old_style_attribute(self, env):
- class Foo:
- x = 42
-
+ def test_old_style_attribute(self, env):
+ class Foo:
+ x = 42
+
assert env.getitem(Foo(), "x") == 42
- def test_block_set_with_extends(self):
+ def test_block_set_with_extends(self):
env = Environment(
loader=DictLoader({"main": "{% block body %}[{{ x }}]{% endblock %}"})
)
- t = env.from_string('{% extends "main" %}{% set x %}42{% endset %}')
+ t = env.from_string('{% extends "main" %}{% set x %}42{% endset %}')
assert t.render() == "[42]"
-
- def test_nested_for_else(self, env):
+
+ def test_nested_for_else(self, env):
tmpl = env.from_string(
"{% for x in y %}{{ loop.index0 }}{% else %}"
"{% for i in range(3) %}{{ i }}{% endfor %}"
"{% endfor %}"
)
assert tmpl.render() == "012"
-
- def test_macro_var_bug(self, env):
+
+ def test_macro_var_bug(self, env):
tmpl = env.from_string(
"""
- {% set i = 1 %}
- {% macro test() %}
- {% for i in range(0, 10) %}{{ i }}{% endfor %}
- {% endmacro %}{{ test() }}
+ {% set i = 1 %}
+ {% macro test() %}
+ {% for i in range(0, 10) %}{{ i }}{% endfor %}
+ {% endmacro %}{{ test() }}
"""
)
assert tmpl.render().strip() == "0123456789"
-
- def test_macro_var_bug_advanced(self, env):
+
+ def test_macro_var_bug_advanced(self, env):
tmpl = env.from_string(
"""
- {% macro outer() %}
- {% set i = 1 %}
- {% macro test() %}
- {% for i in range(0, 10) %}{{ i }}{% endfor %}
- {% endmacro %}{{ test() }}
- {% endmacro %}{{ outer() }}
+ {% macro outer() %}
+ {% set i = 1 %}
+ {% macro test() %}
+ {% for i in range(0, 10) %}{{ i }}{% endfor %}
+ {% endmacro %}{{ test() }}
+ {% endmacro %}{{ outer() }}
"""
)
assert tmpl.render().strip() == "0123456789"
-
- def test_callable_defaults(self):
- env = Environment()
+
+ def test_callable_defaults(self):
+ env = Environment()
env.globals["get_int"] = lambda: 42
t = env.from_string(
"""
- {% macro test(a, b, c=get_int()) -%}
- {{ a + b + c }}
- {%- endmacro %}
- {{ test(1, 2) }}|{{ test(1, 2, 3) }}
+ {% macro test(a, b, c=get_int()) -%}
+ {{ a + b + c }}
+ {%- endmacro %}
+ {{ test(1, 2) }}|{{ test(1, 2, 3) }}
"""
)
assert t.render().strip() == "45|6"
-
- def test_macro_escaping(self):
- env = Environment(
+
+ def test_macro_escaping(self):
+ env = Environment(
autoescape=lambda x: False, extensions=["jinja2.ext.autoescape"]
)
- template = "{% macro m() %}<html>{% endmacro %}"
- template += "{% autoescape true %}{{ m() }}{% endautoescape %}"
- assert env.from_string(template).render()
-
- def test_macro_scoping(self, env):
+ template = "{% macro m() %}<html>{% endmacro %}"
+ template += "{% autoescape true %}{{ m() }}{% endautoescape %}"
+ assert env.from_string(template).render()
+
+ def test_macro_scoping(self, env):
tmpl = env.from_string(
"""
- {% set n=[1,2,3,4,5] %}
- {% for n in [[1,2,3], [3,4,5], [5,6,7]] %}
-
- {% macro x(l) %}
- {{ l.pop() }}
- {% if l %}{{ x(l) }}{% endif %}
- {% endmacro %}
-
- {{ x(n) }}
-
- {% endfor %}
+ {% set n=[1,2,3,4,5] %}
+ {% for n in [[1,2,3], [3,4,5], [5,6,7]] %}
+
+ {% macro x(l) %}
+ {{ l.pop() }}
+ {% if l %}{{ x(l) }}{% endif %}
+ {% endmacro %}
+
+ {{ x(n) }}
+
+ {% endfor %}
"""
)
assert list(map(int, tmpl.render().split())) == [3, 2, 1, 5, 4, 3, 7, 6, 5]
-
- def test_scopes_and_blocks(self):
+
+ def test_scopes_and_blocks(self):
env = Environment(
loader=DictLoader(
{
"a.html": """
- {%- set foo = 'bar' -%}
- {% include 'x.html' -%}
+ {%- set foo = 'bar' -%}
+ {% include 'x.html' -%}
""",
"b.html": """
- {%- set foo = 'bar' -%}
- {% block test %}{% include 'x.html' %}{% endblock -%}
+ {%- set foo = 'bar' -%}
+ {% block test %}{% include 'x.html' %}{% endblock -%}
""",
"c.html": """
- {%- set foo = 'bar' -%}
- {% block test %}{% set foo = foo
- %}{% include 'x.html' %}{% endblock -%}
+ {%- set foo = 'bar' -%}
+ {% block test %}{% set foo = foo
+ %}{% include 'x.html' %}{% endblock -%}
""",
"x.html": """{{ foo }}|{{ test }}""",
}
)
)
-
+
a = env.get_template("a.html")
b = env.get_template("b.html")
c = env.get_template("c.html")
-
+
assert a.render(test="x").strip() == "bar|x"
assert b.render(test="x").strip() == "bar|x"
assert c.render(test="x").strip() == "bar|x"
-
- def test_scopes_and_include(self):
+
+ def test_scopes_and_include(self):
env = Environment(
loader=DictLoader(
{
@@ -433,54 +433,54 @@ class TestBug(object):
)
t = env.get_template("child.html")
assert t.render() == "42"
-
- def test_caller_scoping(self, env):
+
+ def test_caller_scoping(self, env):
t = env.from_string(
"""
- {% macro detail(icon, value) -%}
- {% if value -%}
- <p><span class="fa fa-fw fa-{{ icon }}"></span>
- {%- if caller is undefined -%}
- {{ value }}
- {%- else -%}
- {{ caller(value, *varargs) }}
- {%- endif -%}</p>
- {%- endif %}
- {%- endmacro %}
-
-
- {% macro link_detail(icon, value, href) -%}
- {% call(value, href) detail(icon, value, href) -%}
- <a href="{{ href }}">{{ value }}</a>
- {%- endcall %}
- {%- endmacro %}
+ {% macro detail(icon, value) -%}
+ {% if value -%}
+ <p><span class="fa fa-fw fa-{{ icon }}"></span>
+ {%- if caller is undefined -%}
+ {{ value }}
+ {%- else -%}
+ {{ caller(value, *varargs) }}
+ {%- endif -%}</p>
+ {%- endif %}
+ {%- endmacro %}
+
+
+ {% macro link_detail(icon, value, href) -%}
+ {% call(value, href) detail(icon, value, href) -%}
+ <a href="{{ href }}">{{ value }}</a>
+ {%- endcall %}
+ {%- endmacro %}
"""
)
-
+
assert t.module.link_detail("circle", "Index", "/") == (
'<p><span class="fa fa-fw fa-circle"></span><a href="/">Index</a></p>'
)
-
- def test_variable_reuse(self, env):
+
+ def test_variable_reuse(self, env):
t = env.from_string("{% for x in x.y %}{{ x }}{% endfor %}")
assert t.render(x={"y": [0, 1, 2]}) == "012"
-
+
t = env.from_string("{% for x in x.y %}{{ loop.index0 }}|{{ x }}{% endfor %}")
assert t.render(x={"y": [0, 1, 2]}) == "0|01|12|2"
-
+
t = env.from_string("{% for x in x.y recursive %}{{ x }}{% endfor %}")
assert t.render(x={"y": [0, 1, 2]}) == "012"
-
- def test_double_caller(self, env):
+
+ def test_double_caller(self, env):
t = env.from_string(
"{% macro x(caller=none) %}[{% if caller %}"
"{{ caller() }}{% endif %}]{% endmacro %}"
"{{ x() }}{% call x() %}aha!{% endcall %}"
)
assert t.render() == "[][aha!]"
-
- def test_double_caller_no_default(self, env):
- with pytest.raises(TemplateAssertionError) as exc_info:
+
+ def test_double_caller_no_default(self, env):
+ with pytest.raises(TemplateAssertionError) as exc_info:
env.from_string(
"{% macro x(caller) %}[{% if caller %}"
"{{ caller() }}{% endif %}]{% endmacro %}"
@@ -488,59 +488,59 @@ class TestBug(object):
assert exc_info.match(
r'"caller" argument must be omitted or ' r"be given a default"
)
-
+
t = env.from_string(
"{% macro x(caller=none) %}[{% if caller %}"
"{{ caller() }}{% endif %}]{% endmacro %}"
)
- with pytest.raises(TypeError) as exc_info:
- t.module.x(None, caller=lambda: 42)
+ with pytest.raises(TypeError) as exc_info:
+ t.module.x(None, caller=lambda: 42)
assert exc_info.match(
r"\'x\' was invoked with two values for the " r"special caller argument"
)
-
- def test_macro_blocks(self, env):
+
+ def test_macro_blocks(self, env):
t = env.from_string(
"{% macro x() %}{% block foo %}x{% endblock %}{% endmacro %}{{ x() }}"
)
assert t.render() == "x"
-
- def test_scoped_block(self, env):
+
+ def test_scoped_block(self, env):
t = env.from_string(
"{% set x = 1 %}{% with x = 2 %}{% block y scoped %}"
"{{ x }}{% endblock %}{% endwith %}"
)
assert t.render() == "2"
-
- def test_recursive_loop_filter(self, env):
+
+ def test_recursive_loop_filter(self, env):
t = env.from_string(
"""
- <?xml version="1.0" encoding="UTF-8"?>
- <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
- {%- for page in [site.root] if page.url != this recursive %}
- <url><loc>{{ page.url }}</loc></url>
- {{- loop(page.children) }}
- {%- endfor %}
- </urlset>
+ <?xml version="1.0" encoding="UTF-8"?>
+ <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
+ {%- for page in [site.root] if page.url != this recursive %}
+ <url><loc>{{ page.url }}</loc></url>
+ {{- loop(page.children) }}
+ {%- endfor %}
+ </urlset>
"""
)
sm = t.render(
this="/foo",
site={"root": {"url": "/", "children": [{"url": "/foo"}, {"url": "/bar"}]}},
)
- lines = [x.strip() for x in sm.splitlines() if x.strip()]
- assert lines == [
- '<?xml version="1.0" encoding="UTF-8"?>',
- '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
+ lines = [x.strip() for x in sm.splitlines() if x.strip()]
+ assert lines == [
+ '<?xml version="1.0" encoding="UTF-8"?>',
+ '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
"<url><loc>/</loc></url>",
"<url><loc>/bar</loc></url>",
"</urlset>",
- ]
-
- def test_empty_if(self, env):
+ ]
+
+ def test_empty_if(self, env):
t = env.from_string("{% if foo %}{% else %}42{% endif %}")
assert t.render(foo=False) == "42"
-
+
def test_subproperty_if(self, env):
t = env.from_string(
"{% if object1.subproperty1 is eq object2.subproperty2 %}42{% endif %}"
@@ -552,7 +552,7 @@ class TestBug(object):
== "42"
)
- def test_set_and_include(self):
+ def test_set_and_include(self):
env = Environment(
loader=DictLoader(
{
@@ -562,8 +562,8 @@ class TestBug(object):
)
)
assert env.get_template("main").render() == "foobar"
-
- def test_loop_include(self):
+
+ def test_loop_include(self):
env = Environment(
loader=DictLoader(
{
@@ -573,45 +573,45 @@ class TestBug(object):
)
)
assert env.get_template("main").render() == "123"
-
- def test_grouper_repr(self):
- from jinja2.filters import _GroupTuple
+
+ def test_grouper_repr(self):
+ from jinja2.filters import _GroupTuple
t = _GroupTuple("foo", [1, 2])
assert t.grouper == "foo"
- assert t.list == [1, 2]
- assert repr(t) == "('foo', [1, 2])"
- assert str(t) == "('foo', [1, 2])"
-
- def test_custom_context(self, env):
- from jinja2.runtime import Context
-
- class MyContext(Context):
- pass
-
- class MyEnvironment(Environment):
- context_class = MyContext
-
+ assert t.list == [1, 2]
+ assert repr(t) == "('foo', [1, 2])"
+ assert str(t) == "('foo', [1, 2])"
+
+ def test_custom_context(self, env):
+ from jinja2.runtime import Context
+
+ class MyContext(Context):
+ pass
+
+ class MyEnvironment(Environment):
+ context_class = MyContext
+
loader = DictLoader({"base": "{{ foobar }}", "test": '{% extends "base" %}'})
- env = MyEnvironment(loader=loader)
+ env = MyEnvironment(loader=loader)
assert env.get_template("test").render(foobar="test") == "test"
-
- def test_legacy_custom_context(self, env):
+
+ def test_legacy_custom_context(self, env):
from jinja2.runtime import Context, missing
-
- class MyContext(Context):
- def resolve(self, name):
+
+ class MyContext(Context):
+ def resolve(self, name):
if name == "foo":
- return 42
- return super(MyContext, self).resolve(name)
-
+ return 42
+ return super(MyContext, self).resolve(name)
+
x = MyContext(env, parent={"bar": 23}, name="foo", blocks={})
- assert x._legacy_resolve_mode
+ assert x._legacy_resolve_mode
assert x.resolve_or_missing("foo") == 42
assert x.resolve_or_missing("bar") == 23
assert x.resolve_or_missing("baz") is missing
-
- def test_recursive_loop_bug(self, env):
+
+ def test_recursive_loop_bug(self, env):
tmpl = env.from_string(
"{%- for value in values recursive %}1{% else %}0{% endfor -%}"
)
diff --git a/contrib/python/Jinja2/py2/tests/test_security.py b/contrib/python/Jinja2/py2/tests/test_security.py
index 7e8974c891..76a7ab079f 100644
--- a/contrib/python/Jinja2/py2/tests/test_security.py
+++ b/contrib/python/Jinja2/py2/tests/test_security.py
@@ -1,70 +1,70 @@
-# -*- coding: utf-8 -*-
-import pytest
-
-from jinja2 import Environment
+# -*- coding: utf-8 -*-
+import pytest
+
+from jinja2 import Environment
from jinja2 import escape
from jinja2 import Markup
from jinja2._compat import text_type
from jinja2.exceptions import SecurityError
from jinja2.exceptions import TemplateRuntimeError
from jinja2.exceptions import TemplateSyntaxError
-from jinja2.nodes import EvalContext
+from jinja2.nodes import EvalContext
from jinja2.sandbox import ImmutableSandboxedEnvironment
from jinja2.sandbox import SandboxedEnvironment
from jinja2.sandbox import unsafe
-
-
-class PrivateStuff(object):
- def bar(self):
- return 23
-
- @unsafe
- def foo(self):
- return 42
-
- def __repr__(self):
+
+
+class PrivateStuff(object):
+ def bar(self):
+ return 23
+
+ @unsafe
+ def foo(self):
+ return 42
+
+ def __repr__(self):
return "PrivateStuff"
-
-
-class PublicStuff(object):
+
+
+class PublicStuff(object):
def bar(self):
return 23
-
+
def _foo(self):
return 42
- def __repr__(self):
+ def __repr__(self):
return "PublicStuff"
-
-
-class TestSandbox(object):
- def test_unsafe(self, env):
- env = SandboxedEnvironment()
+
+
+class TestSandbox(object):
+ def test_unsafe(self, env):
+ env = SandboxedEnvironment()
pytest.raises(
SecurityError, env.from_string("{{ foo.foo() }}").render, foo=PrivateStuff()
)
assert env.from_string("{{ foo.bar() }}").render(foo=PrivateStuff()) == "23"
-
+
pytest.raises(
SecurityError, env.from_string("{{ foo._foo() }}").render, foo=PublicStuff()
)
assert env.from_string("{{ foo.bar() }}").render(foo=PublicStuff()) == "23"
assert env.from_string("{{ foo.__class__ }}").render(foo=42) == ""
assert env.from_string("{{ foo.func_code }}").render(foo=lambda: None) == ""
- # security error comes from __class__ already.
+ # security error comes from __class__ already.
pytest.raises(
SecurityError,
env.from_string("{{ foo.__class__.__subclasses__() }}").render,
foo=42,
)
-
- def test_immutable_environment(self, env):
- env = ImmutableSandboxedEnvironment()
+
+ def test_immutable_environment(self, env):
+ env = ImmutableSandboxedEnvironment()
pytest.raises(SecurityError, env.from_string("{{ [].append(23) }}").render)
pytest.raises(SecurityError, env.from_string("{{ {1:2}.clear() }}").render)
-
- def test_restricted(self, env):
- env = SandboxedEnvironment()
+
+ def test_restricted(self, env):
+ env = SandboxedEnvironment()
pytest.raises(
TemplateSyntaxError,
env.from_string,
@@ -75,116 +75,116 @@ class TestSandbox(object):
env.from_string,
"{% for foo, bar.baz in seq %}...{% endfor %}",
)
-
- def test_markup_operations(self, env):
- # adding two strings should escape the unsafe one
- unsafe = '<script type="application/x-some-script">alert("foo");</script>'
+
+ def test_markup_operations(self, env):
+ # adding two strings should escape the unsafe one
+ unsafe = '<script type="application/x-some-script">alert("foo");</script>'
safe = Markup("<em>username</em>")
- assert unsafe + safe == text_type(escape(unsafe)) + text_type(safe)
-
- # string interpolations are safe to use too
+ assert unsafe + safe == text_type(escape(unsafe)) + text_type(safe)
+
+ # string interpolations are safe to use too
assert Markup("<em>%s</em>") % "<bad user>" == "<em>&lt;bad user&gt;</em>"
assert (
Markup("<em>%(username)s</em>") % {"username": "<bad user>"}
== "<em>&lt;bad user&gt;</em>"
)
-
- # an escaped object is markup too
+
+ # an escaped object is markup too
assert type(Markup("foo") + "bar") is Markup
-
- # and it implements __html__ by returning itself
- x = Markup("foo")
- assert x.__html__() is x
-
- # it also knows how to treat __html__ objects
- class Foo(object):
- def __html__(self):
+
+ # and it implements __html__ by returning itself
+ x = Markup("foo")
+ assert x.__html__() is x
+
+ # it also knows how to treat __html__ objects
+ class Foo(object):
+ def __html__(self):
return "<em>awesome</em>"
-
- def __unicode__(self):
+
+ def __unicode__(self):
return "awesome"
-
+
assert Markup(Foo()) == "<em>awesome</em>"
assert (
Markup("<strong>%s</strong>") % Foo() == "<strong><em>awesome</em></strong>"
)
- # escaping and unescaping
+ # escaping and unescaping
assert escape("\"<>&'") == "&#34;&lt;&gt;&amp;&#39;"
- assert Markup("<em>Foo &amp; Bar</em>").striptags() == "Foo & Bar"
- assert Markup("&lt;test&gt;").unescape() == "<test>"
-
- def test_template_data(self, env):
- env = Environment(autoescape=True)
+ assert Markup("<em>Foo &amp; Bar</em>").striptags() == "Foo & Bar"
+ assert Markup("&lt;test&gt;").unescape() == "<test>"
+
+ def test_template_data(self, env):
+ env = Environment(autoescape=True)
t = env.from_string(
"{% macro say_hello(name) %}"
"<p>Hello {{ name }}!</p>{% endmacro %}"
'{{ say_hello("<blink>foo</blink>") }}'
)
escaped_out = "<p>Hello &lt;blink&gt;foo&lt;/blink&gt;!</p>"
- assert t.render() == escaped_out
- assert text_type(t.module) == escaped_out
- assert escape(t.module) == escaped_out
+ assert t.render() == escaped_out
+ assert text_type(t.module) == escaped_out
+ assert escape(t.module) == escaped_out
assert t.module.say_hello("<blink>foo</blink>") == escaped_out
assert (
escape(t.module.say_hello(EvalContext(env), "<blink>foo</blink>"))
== escaped_out
)
assert escape(t.module.say_hello("<blink>foo</blink>")) == escaped_out
-
- def test_attr_filter(self, env):
- env = SandboxedEnvironment()
- tmpl = env.from_string('{{ cls|attr("__subclasses__")() }}')
- pytest.raises(SecurityError, tmpl.render, cls=int)
-
- def test_binary_operator_intercepting(self, env):
- def disable_op(left, right):
+
+ def test_attr_filter(self, env):
+ env = SandboxedEnvironment()
+ tmpl = env.from_string('{{ cls|attr("__subclasses__")() }}')
+ pytest.raises(SecurityError, tmpl.render, cls=int)
+
+ def test_binary_operator_intercepting(self, env):
+ def disable_op(left, right):
raise TemplateRuntimeError("that operator so does not work")
for expr, ctx, rv in ("1 + 2", {}, "3"), ("a + 2", {"a": 2}, "4"):
- env = SandboxedEnvironment()
+ env = SandboxedEnvironment()
env.binop_table["+"] = disable_op
t = env.from_string("{{ %s }}" % expr)
- assert t.render(ctx) == rv
+ assert t.render(ctx) == rv
env.intercepted_binops = frozenset(["+"])
t = env.from_string("{{ %s }}" % expr)
with pytest.raises(TemplateRuntimeError):
- t.render(ctx)
-
- def test_unary_operator_intercepting(self, env):
- def disable_op(arg):
+ t.render(ctx)
+
+ def test_unary_operator_intercepting(self, env):
+ def disable_op(arg):
raise TemplateRuntimeError("that operator so does not work")
for expr, ctx, rv in ("-1", {}, "-1"), ("-a", {"a": 2}, "-2"):
- env = SandboxedEnvironment()
+ env = SandboxedEnvironment()
env.unop_table["-"] = disable_op
t = env.from_string("{{ %s }}" % expr)
- assert t.render(ctx) == rv
+ assert t.render(ctx) == rv
env.intercepted_unops = frozenset(["-"])
t = env.from_string("{{ %s }}" % expr)
with pytest.raises(TemplateRuntimeError):
- t.render(ctx)
-
-
-class TestStringFormat(object):
- def test_basic_format_safety(self):
- env = SandboxedEnvironment()
- t = env.from_string('{{ "a{0.__class__}b".format(42) }}')
+ t.render(ctx)
+
+
+class TestStringFormat(object):
+ def test_basic_format_safety(self):
+ env = SandboxedEnvironment()
+ t = env.from_string('{{ "a{0.__class__}b".format(42) }}')
assert t.render() == "ab"
-
- def test_basic_format_all_okay(self):
- env = SandboxedEnvironment()
- t = env.from_string('{{ "a{0.foo}b".format({"foo": 42}) }}')
+
+ def test_basic_format_all_okay(self):
+ env = SandboxedEnvironment()
+ t = env.from_string('{{ "a{0.foo}b".format({"foo": 42}) }}')
assert t.render() == "a42b"
-
- def test_safe_format_safety(self):
- env = SandboxedEnvironment()
- t = env.from_string('{{ ("a{0.__class__}b{1}"|safe).format(42, "<foo>") }}')
+
+ def test_safe_format_safety(self):
+ env = SandboxedEnvironment()
+ t = env.from_string('{{ ("a{0.__class__}b{1}"|safe).format(42, "<foo>") }}')
assert t.render() == "ab&lt;foo&gt;"
-
- def test_safe_format_all_okay(self):
- env = SandboxedEnvironment()
- t = env.from_string('{{ ("a{0.foo}b{1}"|safe).format({"foo": 42}, "<foo>") }}')
+
+ def test_safe_format_all_okay(self):
+ env = SandboxedEnvironment()
+ t = env.from_string('{{ ("a{0.foo}b{1}"|safe).format({"foo": 42}, "<foo>") }}')
assert t.render() == "a42b&lt;foo&gt;"
diff --git a/contrib/python/Jinja2/py2/tests/test_tests.py b/contrib/python/Jinja2/py2/tests/test_tests.py
index b903e3b1e2..1c41d1ee0c 100644
--- a/contrib/python/Jinja2/py2/tests/test_tests.py
+++ b/contrib/python/Jinja2/py2/tests/test_tests.py
@@ -1,31 +1,31 @@
-# -*- coding: utf-8 -*-
+# -*- coding: utf-8 -*-
import pytest
-
+
from jinja2 import Environment
from jinja2 import Markup
-
-
+
+
class MyDict(dict):
pass
-
-
-class TestTestsCase(object):
- def test_defined(self, env):
+
+
+class TestTestsCase(object):
+ def test_defined(self, env):
tmpl = env.from_string("{{ missing is defined }}|{{ true is defined }}")
assert tmpl.render() == "False|True"
-
- def test_even(self, env):
+
+ def test_even(self, env):
tmpl = env.from_string("""{{ 1 is even }}|{{ 2 is even }}""")
assert tmpl.render() == "False|True"
-
- def test_odd(self, env):
+
+ def test_odd(self, env):
tmpl = env.from_string("""{{ 1 is odd }}|{{ 2 is odd }}""")
assert tmpl.render() == "True|False"
-
- def test_lower(self, env):
+
+ def test_lower(self, env):
tmpl = env.from_string("""{{ "foo" is lower }}|{{ "FOO" is lower }}""")
assert tmpl.render() == "True|False"
-
+
# Test type checks
@pytest.mark.parametrize(
"op,expect",
@@ -112,27 +112,27 @@ class TestTestsCase(object):
def test_types(self, env, op, expect):
t = env.from_string("{{{{ {op} }}}}".format(op=op))
assert t.render(mydict=MyDict(), complex=complex(1, 2)) == str(expect)
-
- def test_upper(self, env):
- tmpl = env.from_string('{{ "FOO" is upper }}|{{ "foo" is upper }}')
+
+ def test_upper(self, env):
+ tmpl = env.from_string('{{ "FOO" is upper }}|{{ "foo" is upper }}')
assert tmpl.render() == "True|False"
-
- def test_equalto(self, env):
- tmpl = env.from_string(
+
+ def test_equalto(self, env):
+ tmpl = env.from_string(
"{{ foo is eq 12 }}|"
"{{ foo is eq 0 }}|"
"{{ foo is eq (3 * 4) }}|"
- '{{ bar is eq "baz" }}|'
- '{{ bar is eq "zab" }}|'
- '{{ bar is eq ("ba" + "z") }}|'
+ '{{ bar is eq "baz" }}|'
+ '{{ bar is eq "zab" }}|'
+ '{{ bar is eq ("ba" + "z") }}|'
"{{ bar is eq bar }}|"
"{{ bar is eq foo }}"
- )
+ )
assert (
tmpl.render(foo=12, bar="baz")
== "True|False|True|True|False|True|True|False"
)
-
+
@pytest.mark.parametrize(
"op,expect",
(
@@ -150,39 +150,39 @@ class TestTestsCase(object):
("ge 3", False),
),
)
- def test_compare_aliases(self, env, op, expect):
+ def test_compare_aliases(self, env, op, expect):
t = env.from_string("{{{{ 2 is {op} }}}}".format(op=op))
- assert t.render() == str(expect)
-
- def test_sameas(self, env):
+ assert t.render() == str(expect)
+
+ def test_sameas(self, env):
tmpl = env.from_string("{{ foo is sameas false }}|{{ 0 is sameas false }}")
assert tmpl.render(foo=False) == "True|False"
-
- def test_no_paren_for_arg1(self, env):
+
+ def test_no_paren_for_arg1(self, env):
tmpl = env.from_string("{{ foo is sameas none }}")
assert tmpl.render(foo=None) == "True"
-
- def test_escaped(self, env):
- env = Environment(autoescape=True)
+
+ def test_escaped(self, env):
+ env = Environment(autoescape=True)
tmpl = env.from_string("{{ x is escaped }}|{{ y is escaped }}")
assert tmpl.render(x="foo", y=Markup("foo")) == "False|True"
-
- def test_greaterthan(self, env):
+
+ def test_greaterthan(self, env):
tmpl = env.from_string("{{ 1 is greaterthan 0 }}|{{ 0 is greaterthan 1 }}")
assert tmpl.render() == "True|False"
-
- def test_lessthan(self, env):
+
+ def test_lessthan(self, env):
tmpl = env.from_string("{{ 0 is lessthan 1 }}|{{ 1 is lessthan 0 }}")
assert tmpl.render() == "True|False"
+
+ def test_multiple_tests(self):
+ items = []
- def test_multiple_tests(self):
- items = []
+ def matching(x, y):
+ items.append((x, y))
+ return False
- def matching(x, y):
- items.append((x, y))
- return False
-
- env = Environment()
+ env = Environment()
env.tests["matching"] = matching
tmpl = env.from_string(
"{{ 'us-west-1' is matching '(us-east-1|ap-northeast-1)'"
@@ -193,8 +193,8 @@ class TestTestsCase(object):
("us-west-1", "(us-east-1|ap-northeast-1)"),
("stage", "(dev|stage)"),
]
-
- def test_in(self, env):
+
+ def test_in(self, env):
tmpl = env.from_string(
'{{ "o" is in "foo" }}|'
'{{ "foo" is in "foo" }}|'
diff --git a/contrib/python/Jinja2/py2/tests/test_utils.py b/contrib/python/Jinja2/py2/tests/test_utils.py
index d9f5bb2783..9878251c4e 100644
--- a/contrib/python/Jinja2/py2/tests/test_utils.py
+++ b/contrib/python/Jinja2/py2/tests/test_utils.py
@@ -1,12 +1,12 @@
-# -*- coding: utf-8 -*-
+# -*- coding: utf-8 -*-
import pickle
import random
from collections import deque
from copy import copy as shallow_copy
-
-import pytest
+
+import pytest
from markupsafe import Markup
-
+
from jinja2._compat import range_type
from jinja2._compat import string_types
from jinja2.utils import consume
@@ -16,19 +16,19 @@ from jinja2.utils import missing
from jinja2.utils import object_type_repr
from jinja2.utils import select_autoescape
from jinja2.utils import urlize
-
-
-class TestLRUCache(object):
- def test_simple(self):
- d = LRUCache(3)
- d["a"] = 1
- d["b"] = 2
- d["c"] = 3
- d["a"]
- d["d"] = 4
- assert len(d) == 3
+
+
+class TestLRUCache(object):
+ def test_simple(self):
+ d = LRUCache(3)
+ d["a"] = 1
+ d["b"] = 2
+ d["c"] = 3
+ d["a"]
+ d["d"] = 4
+ assert len(d) == 3
assert "a" in d and "c" in d and "d" in d and "b" not in d
-
+
def test_itervalue_deprecated(self):
cache = LRUCache(3)
cache["a"] = 1
@@ -50,18 +50,18 @@ class TestLRUCache(object):
values = [v for v in cache.values()]
assert len(values) == 0
- def test_pickleable(self):
- cache = LRUCache(2)
- cache["foo"] = 42
- cache["bar"] = 23
- cache["foo"]
-
- for protocol in range(3):
- copy = pickle.loads(pickle.dumps(cache, protocol))
- assert copy.capacity == cache.capacity
- assert copy._mapping == cache._mapping
- assert copy._queue == cache._queue
-
+ def test_pickleable(self):
+ cache = LRUCache(2)
+ cache["foo"] = 42
+ cache["bar"] = 23
+ cache["foo"]
+
+ for protocol in range(3):
+ copy = pickle.loads(pickle.dumps(cache, protocol))
+ assert copy.capacity == cache.capacity
+ assert copy._mapping == cache._mapping
+ assert copy._queue == cache._queue
+
@pytest.mark.parametrize("copy_func", [LRUCache.copy, shallow_copy])
def test_copy(self, copy_func):
cache = LRUCache(2)
@@ -72,7 +72,7 @@ class TestLRUCache(object):
copy["c"] = 3
assert copy._queue != cache._queue
assert "a" not in copy and "b" in copy and "c" in copy
-
+
def test_clear(self):
d = LRUCache(3)
d["a"] = 1
@@ -118,25 +118,25 @@ class TestLRUCache(object):
assert len(d) == 2
-class TestHelpers(object):
- def test_object_type_repr(self):
- class X(object):
- pass
-
+class TestHelpers(object):
+ def test_object_type_repr(self):
+ class X(object):
+ pass
+
assert object_type_repr(42) == "int object"
assert object_type_repr([]) == "list object"
assert object_type_repr(X()) == "__tests__.test_utils.X object"
assert object_type_repr(None) == "None"
assert object_type_repr(Ellipsis) == "Ellipsis"
- def test_autoescape_select(self):
- func = select_autoescape(
+ def test_autoescape_select(self):
+ func = select_autoescape(
enabled_extensions=("html", ".htm"),
disabled_extensions=("txt",),
default_for_string="STRING",
default="NONE",
- )
-
+ )
+
assert func(None) == "STRING"
assert func("unknown.foo") == "NONE"
assert func("foo.html")
@@ -144,12 +144,12 @@ class TestHelpers(object):
assert not func("foo.txt")
assert func("FOO.HTML")
assert not func("FOO.TXT")
-
-
-class TestEscapeUrlizeTarget(object):
- def test_escape_urlize_target(self):
- url = "http://example.org"
- target = "<script>"
+
+
+class TestEscapeUrlizeTarget(object):
+ def test_escape_urlize_target(self):
+ url = "http://example.org"
+ target = "<script>"
assert urlize(url, target=target) == (
'<a href="http://example.org"'
' target="&lt;script&gt;">'
diff --git a/contrib/python/Jinja2/py2/ya.make b/contrib/python/Jinja2/py2/ya.make
index 5f1bf64811..01de9b26b8 100644
--- a/contrib/python/Jinja2/py2/ya.make
+++ b/contrib/python/Jinja2/py2/ya.make
@@ -1,49 +1,49 @@
# Generated by devtools/yamaker (pypi).
PY2_LIBRARY()
-
+
OWNER(floatdrop g:python-contrib)
VERSION(2.11.3)
-
+
LICENSE(BSD-3-Clause)
-PEERDIR(
- contrib/python/MarkupSafe
+PEERDIR(
+ contrib/python/MarkupSafe
contrib/python/setuptools
-)
-
+)
+
NO_LINT()
-PY_SRCS(
- TOP_LEVEL
- jinja2/__init__.py
- jinja2/_compat.py
- jinja2/_identifier.py
- jinja2/bccache.py
- jinja2/compiler.py
- jinja2/constants.py
- jinja2/debug.py
- jinja2/defaults.py
- jinja2/environment.py
- jinja2/exceptions.py
- jinja2/ext.py
- jinja2/filters.py
- jinja2/idtracking.py
- jinja2/lexer.py
- jinja2/loaders.py
- jinja2/meta.py
- jinja2/nativetypes.py
- jinja2/nodes.py
- jinja2/optimizer.py
- jinja2/parser.py
- jinja2/runtime.py
- jinja2/sandbox.py
- jinja2/tests.py
- jinja2/utils.py
- jinja2/visitor.py
-)
-
+PY_SRCS(
+ TOP_LEVEL
+ jinja2/__init__.py
+ jinja2/_compat.py
+ jinja2/_identifier.py
+ jinja2/bccache.py
+ jinja2/compiler.py
+ jinja2/constants.py
+ jinja2/debug.py
+ jinja2/defaults.py
+ jinja2/environment.py
+ jinja2/exceptions.py
+ jinja2/ext.py
+ jinja2/filters.py
+ jinja2/idtracking.py
+ jinja2/lexer.py
+ jinja2/loaders.py
+ jinja2/meta.py
+ jinja2/nativetypes.py
+ jinja2/nodes.py
+ jinja2/optimizer.py
+ jinja2/parser.py
+ jinja2/runtime.py
+ jinja2/sandbox.py
+ jinja2/tests.py
+ jinja2/utils.py
+ jinja2/visitor.py
+)
+
RESOURCE_FILES(
PREFIX contrib/python/Jinja2/py2/
.dist-info/METADATA
@@ -51,7 +51,7 @@ RESOURCE_FILES(
.dist-info/top_level.txt
)
-END()
+END()
RECURSE_FOR_TESTS(
tests
diff --git a/contrib/python/Jinja2/py3/README.rst b/contrib/python/Jinja2/py3/README.rst
index a197aea647..36db4c1fa7 100644
--- a/contrib/python/Jinja2/py3/README.rst
+++ b/contrib/python/Jinja2/py3/README.rst
@@ -1,12 +1,12 @@
Jinja
=====
-
+
Jinja is a fast, expressive, extensible templating engine. Special
placeholders in the template allow writing code similar to Python
syntax. Then the template is passed data to render the final document.
-
+
It includes:
-
+
- Template inheritance and inclusion.
- Define and import macros within templates.
- HTML templates can use autoescaping to prevent XSS from untrusted
@@ -20,7 +20,7 @@ It includes:
- Exceptions point to the correct line in templates to make debugging
easier.
- Extensible filters, tests, functions, and even syntax.
-
+
Jinja's philosophy is that while application logic belongs in Python if
possible, it shouldn't make the template designer's job difficult by
restricting functionality too much.
@@ -41,19 +41,19 @@ Install and update using `pip`_:
In A Nutshell
-------------
-.. code-block:: jinja
-
+.. code-block:: jinja
+
{% extends "base.html" %}
{% block title %}Members{% endblock %}
- {% block content %}
- <ul>
- {% for user in users %}
- <li><a href="{{ user.url }}">{{ user.username }}</a></li>
- {% endfor %}
- </ul>
- {% endblock %}
-
-
+ {% block content %}
+ <ul>
+ {% for user in users %}
+ <li><a href="{{ user.url }}">{{ user.username }}</a></li>
+ {% endfor %}
+ </ul>
+ {% endblock %}
+
+
Donate
------
@@ -67,7 +67,7 @@ donate today`_.
Links
-----
-
+
- Documentation: https://jinja.palletsprojects.com/
- Changes: https://jinja.palletsprojects.com/changes/
- PyPI Releases: https://pypi.org/project/Jinja2/
diff --git a/contrib/python/Jinja2/py3/jinja2/__init__.py b/contrib/python/Jinja2/py3/jinja2/__init__.py
index 3d5a8600da..7f71dbf9fa 100644
--- a/contrib/python/Jinja2/py3/jinja2/__init__.py
+++ b/contrib/python/Jinja2/py3/jinja2/__init__.py
@@ -1,7 +1,7 @@
"""Jinja is a template engine written in pure Python. It provides a
non-XML syntax that supports inline expressions and an optional
sandboxed environment.
-"""
+"""
from .bccache import BytecodeCache as BytecodeCache
from .bccache import FileSystemBytecodeCache as FileSystemBytecodeCache
from .bccache import MemcachedBytecodeCache as MemcachedBytecodeCache
@@ -42,5 +42,5 @@ from .utils import pass_context as pass_context
from .utils import pass_environment as pass_environment
from .utils import pass_eval_context as pass_eval_context
from .utils import select_autoescape as select_autoescape
-
+
__version__ = "3.0.3"
diff --git a/contrib/python/Jinja2/py3/jinja2/_identifier.py b/contrib/python/Jinja2/py3/jinja2/_identifier.py
index 224d5449d1..b0a761fc2a 100644
--- a/contrib/python/Jinja2/py3/jinja2/_identifier.py
+++ b/contrib/python/Jinja2/py3/jinja2/_identifier.py
@@ -1,6 +1,6 @@
import re
-# generated by scripts/generate_identifier_pattern.py
+# generated by scripts/generate_identifier_pattern.py
pattern = re.compile(
r"[\w·̀-ͯ·҃-֑҇-ׇֽֿׁׂׅׄؐ-ًؚ-ٰٟۖ-ۜ۟-۪ۤۧۨ-ܑۭܰ-݊ަ-ް߫-߳ࠖ-࠙ࠛ-ࠣࠥ-ࠧࠩ-࡙࠭-࡛ࣔ-ࣣ࣡-ःऺ-़ा-ॏ॑-ॗॢॣঁ-ঃ়া-ৄেৈো-্ৗৢৣਁ-ਃ਼ਾ-ੂੇੈੋ-੍ੑੰੱੵઁ-ઃ઼ા-ૅે-ૉો-્ૢૣଁ-ଃ଼ା-ୄେୈୋ-୍ୖୗୢୣஂா-ூெ-ைொ-்ௗఀ-ఃా-ౄె-ైొ-్ౕౖౢౣಁ-ಃ಼ಾ-ೄೆ-ೈೊ-್ೕೖೢೣഁ-ഃാ-ൄെ-ൈൊ-്ൗൢൣංඃ්ා-ුූෘ-ෟෲෳัิ-ฺ็-๎ັິ-ູົຼ່-ໍ༹༘༙༵༷༾༿ཱ-྄྆྇ྍ-ྗྙ-ྼ࿆ါ-ှၖ-ၙၞ-ၠၢ-ၤၧ-ၭၱ-ၴႂ-ႍႏႚ-ႝ፝-፟ᜒ-᜔ᜲ-᜴ᝒᝓᝲᝳ឴-៓៝᠋-᠍ᢅᢆᢩᤠ-ᤫᤰ-᤻ᨗ-ᨛᩕ-ᩞ᩠-᩿᩼᪰-᪽ᬀ-ᬄ᬴-᭄᭫-᭳ᮀ-ᮂᮡ-ᮭ᯦-᯳ᰤ-᰷᳐-᳔᳒-᳨᳭ᳲ-᳴᳸᳹᷀-᷵᷻-᷿‿⁀⁔⃐-⃥⃜⃡-⃰℘℮⳯-⵿⳱ⷠ-〪ⷿ-゙゚〯꙯ꙴ-꙽ꚞꚟ꛰꛱ꠂ꠆ꠋꠣ-ꠧꢀꢁꢴ-ꣅ꣠-꣱ꤦ-꤭ꥇ-꥓ꦀ-ꦃ꦳-꧀ꧥꨩ-ꨶꩃꩌꩍꩻ-ꩽꪰꪲ-ꪴꪷꪸꪾ꪿꫁ꫫ-ꫯꫵ꫶ꯣ-ꯪ꯬꯭ﬞ︀-️︠-︯︳︴﹍-﹏_𐇽𐋠𐍶-𐍺𐨁-𐨃𐨅𐨆𐨌-𐨏𐨸-𐨿𐨺𐫦𐫥𑀀-𑀂𑀸-𑁆𑁿-𑂂𑂰-𑂺𑄀-𑄂𑄧-𑅳𑄴𑆀-𑆂𑆳-𑇊𑇀-𑇌𑈬-𑈷𑈾𑋟-𑋪𑌀-𑌃𑌼𑌾-𑍄𑍇𑍈𑍋-𑍍𑍗𑍢𑍣𑍦-𑍬𑍰-𑍴𑐵-𑑆𑒰-𑓃𑖯-𑖵𑖸-𑗀𑗜𑗝𑘰-𑙀𑚫-𑚷𑜝-𑜫𑰯-𑰶𑰸-𑰿𑲒-𑲧𑲩-𑲶𖫰-𖫴𖬰-𖬶𖽑-𖽾𖾏-𖾒𛲝𛲞𝅥-𝅩𝅭-𝅲𝅻-𝆂𝆅-𝆋𝆪-𝆭𝉂-𝉄𝨀-𝨶𝨻-𝩬𝩵𝪄𝪛-𝪟𝪡-𝪯𞀀-𞀆𞀈-𞀘𞀛-𞀡𞀣𞀤𞀦-𞣐𞀪-𞣖𞥄-𞥊󠄀-󠇯]+" # noqa: B950
)
diff --git a/contrib/python/Jinja2/py3/jinja2/bccache.py b/contrib/python/Jinja2/py3/jinja2/bccache.py
index 3bb61b7c34..f54cc4d3b6 100644
--- a/contrib/python/Jinja2/py3/jinja2/bccache.py
+++ b/contrib/python/Jinja2/py3/jinja2/bccache.py
@@ -1,27 +1,27 @@
"""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.
-
+
Situations where this is useful are often forking web applications that
are initialized on the first request.
-"""
+"""
import errno
import fnmatch
import marshal
-import os
+import os
import pickle
import stat
-import sys
-import tempfile
+import sys
+import tempfile
import typing as t
-from hashlib import sha1
+from hashlib import sha1
from io import BytesIO
from types import CodeType
-
+
if t.TYPE_CHECKING:
import typing_extensions as te
from .environment import Environment
-
+
class _MemcachedClient(te.Protocol):
def get(self, key: str) -> bytes:
...
@@ -39,129 +39,129 @@ bc_magic = (
+ pickle.dumps(bc_version, 2)
+ pickle.dumps((sys.version_info[0] << 24) | sys.version_info[1], 2)
)
-
-
+
+
class Bucket:
- """Buckets are used to store the bytecode for one template. It's created
- and initialized by the bytecode cache and passed to the loading functions.
-
- The buckets get an internal checksum from the cache assigned and use this
- to automatically reject outdated cache material. Individual bytecode
- cache subclasses don't have to care about cache invalidation.
- """
-
+ """Buckets are used to store the bytecode for one template. It's created
+ and initialized by the bytecode cache and passed to the loading functions.
+
+ The buckets get an internal checksum from the cache assigned and use this
+ to automatically reject outdated cache material. Individual bytecode
+ cache subclasses don't have to care about cache invalidation.
+ """
+
def __init__(self, environment: "Environment", key: str, checksum: str) -> None:
- self.environment = environment
- self.key = key
- self.checksum = checksum
- self.reset()
-
+ self.environment = environment
+ self.key = key
+ self.checksum = checksum
+ self.reset()
+
def reset(self) -> None:
- """Resets the bucket (unloads the bytecode)."""
+ """Resets the bucket (unloads the bytecode)."""
self.code: t.Optional[CodeType] = None
-
+
def load_bytecode(self, f: t.BinaryIO) -> None:
- """Loads bytecode from a file or file like object."""
- # make sure the magic header is correct
- magic = f.read(len(bc_magic))
- if magic != bc_magic:
- self.reset()
- return
- # the source code of the file changed, we need to reload
- checksum = pickle.load(f)
- if self.checksum != checksum:
- self.reset()
- return
- # if marshal_load fails then we need to reload
- try:
+ """Loads bytecode from a file or file like object."""
+ # make sure the magic header is correct
+ magic = f.read(len(bc_magic))
+ if magic != bc_magic:
+ self.reset()
+ return
+ # the source code of the file changed, we need to reload
+ checksum = pickle.load(f)
+ if self.checksum != checksum:
+ self.reset()
+ return
+ # if marshal_load fails then we need to reload
+ try:
self.code = marshal.load(f)
- except (EOFError, ValueError, TypeError):
- self.reset()
- return
-
+ except (EOFError, ValueError, TypeError):
+ self.reset()
+ return
+
def write_bytecode(self, f: t.BinaryIO) -> None:
- """Dump the bytecode into the file or file like object passed."""
- if self.code is None:
+ """Dump the bytecode into the file or file like object passed."""
+ if self.code is None:
raise TypeError("can't write empty bucket")
- f.write(bc_magic)
- pickle.dump(self.checksum, f, 2)
+ f.write(bc_magic)
+ pickle.dump(self.checksum, f, 2)
marshal.dump(self.code, f)
-
+
def bytecode_from_string(self, string: bytes) -> None:
"""Load bytecode from bytes."""
- self.load_bytecode(BytesIO(string))
-
+ self.load_bytecode(BytesIO(string))
+
def bytecode_to_string(self) -> bytes:
"""Return the bytecode as bytes."""
- out = BytesIO()
- self.write_bytecode(out)
- return out.getvalue()
-
-
+ out = BytesIO()
+ self.write_bytecode(out)
+ return out.getvalue()
+
+
class BytecodeCache:
- """To implement your own bytecode cache you have to subclass this class
- and override :meth:`load_bytecode` and :meth:`dump_bytecode`. Both of
- these methods are passed a :class:`~jinja2.bccache.Bucket`.
-
- A very basic bytecode cache that saves the bytecode on the file system::
-
- from os import path
-
- class MyCache(BytecodeCache):
-
- def __init__(self, directory):
- self.directory = directory
-
- def load_bytecode(self, bucket):
- filename = path.join(self.directory, bucket.key)
- if path.exists(filename):
- with open(filename, 'rb') as f:
- bucket.load_bytecode(f)
-
- def dump_bytecode(self, bucket):
- filename = path.join(self.directory, bucket.key)
- with open(filename, 'wb') as f:
- bucket.write_bytecode(f)
-
- A more advanced version of a filesystem based bytecode cache is part of
+ """To implement your own bytecode cache you have to subclass this class
+ and override :meth:`load_bytecode` and :meth:`dump_bytecode`. Both of
+ these methods are passed a :class:`~jinja2.bccache.Bucket`.
+
+ A very basic bytecode cache that saves the bytecode on the file system::
+
+ from os import path
+
+ class MyCache(BytecodeCache):
+
+ def __init__(self, directory):
+ self.directory = directory
+
+ def load_bytecode(self, bucket):
+ filename = path.join(self.directory, bucket.key)
+ if path.exists(filename):
+ with open(filename, 'rb') as f:
+ bucket.load_bytecode(f)
+
+ def dump_bytecode(self, bucket):
+ filename = path.join(self.directory, bucket.key)
+ with open(filename, 'wb') as f:
+ bucket.write_bytecode(f)
+
+ A more advanced version of a filesystem based bytecode cache is part of
Jinja.
- """
-
+ """
+
def load_bytecode(self, bucket: Bucket) -> None:
- """Subclasses have to override this method to load bytecode into a
- bucket. If they are not able to find code in the cache for the
- bucket, it must not do anything.
- """
- raise NotImplementedError()
-
+ """Subclasses have to override this method to load bytecode into a
+ bucket. If they are not able to find code in the cache for the
+ bucket, it must not do anything.
+ """
+ raise NotImplementedError()
+
def dump_bytecode(self, bucket: Bucket) -> None:
- """Subclasses have to override this method to write the bytecode
- from a bucket back to the cache. If it unable to do so it must not
- fail silently but raise an exception.
- """
- raise NotImplementedError()
-
+ """Subclasses have to override this method to write the bytecode
+ from a bucket back to the cache. If it unable to do so it must not
+ fail silently but raise an exception.
+ """
+ raise NotImplementedError()
+
def clear(self) -> None:
"""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.
- """
-
+ implemented to allow applications to clear the bytecode cache used
+ by a particular environment.
+ """
+
def get_cache_key(
self, name: str, filename: t.Optional[t.Union[str]] = None
) -> str:
- """Returns the unique hash key for this template name."""
+ """Returns the unique hash key for this template name."""
hash = sha1(name.encode("utf-8"))
- if filename is not None:
+ if filename is not None:
hash.update(f"|{filename}".encode())
- return hash.hexdigest()
-
+ return hash.hexdigest()
+
def get_source_checksum(self, source: str) -> str:
- """Returns a checksum for the source."""
+ """Returns a checksum for the source."""
return sha1(source.encode("utf-8")).hexdigest()
-
+
def get_bucket(
self,
environment: "Environment",
@@ -169,166 +169,166 @@ class BytecodeCache:
filename: t.Optional[str],
source: str,
) -> Bucket:
- """Return a cache bucket for the given template. All arguments are
- mandatory but filename may be `None`.
- """
- key = self.get_cache_key(name, filename)
- checksum = self.get_source_checksum(source)
- bucket = Bucket(environment, key, checksum)
- self.load_bytecode(bucket)
- return bucket
-
+ """Return a cache bucket for the given template. All arguments are
+ mandatory but filename may be `None`.
+ """
+ key = self.get_cache_key(name, filename)
+ checksum = self.get_source_checksum(source)
+ bucket = Bucket(environment, key, checksum)
+ self.load_bytecode(bucket)
+ return bucket
+
def set_bucket(self, bucket: Bucket) -> None:
- """Put the bucket into the cache."""
- self.dump_bytecode(bucket)
-
-
-class FileSystemBytecodeCache(BytecodeCache):
- """A bytecode cache that stores bytecode on the filesystem. It accepts
- two arguments: The directory where the cache items are stored and a
- pattern string that is used to build the filename.
-
- If no directory is specified a default cache directory is selected. On
- Windows the user's temp directory is used, on UNIX systems a directory
- is created for the user in the system temp directory.
-
- The pattern can be used to have multiple separate caches operate on the
- same directory. The default pattern is ``'__jinja2_%s.cache'``. ``%s``
- is replaced with the cache key.
-
- >>> bcc = FileSystemBytecodeCache('/tmp/jinja_cache', '%s.cache')
-
- This bytecode cache supports clearing of the cache using the clear method.
- """
-
+ """Put the bucket into the cache."""
+ self.dump_bytecode(bucket)
+
+
+class FileSystemBytecodeCache(BytecodeCache):
+ """A bytecode cache that stores bytecode on the filesystem. It accepts
+ two arguments: The directory where the cache items are stored and a
+ pattern string that is used to build the filename.
+
+ If no directory is specified a default cache directory is selected. On
+ Windows the user's temp directory is used, on UNIX systems a directory
+ is created for the user in the system temp directory.
+
+ The pattern can be used to have multiple separate caches operate on the
+ same directory. The default pattern is ``'__jinja2_%s.cache'``. ``%s``
+ is replaced with the cache key.
+
+ >>> bcc = FileSystemBytecodeCache('/tmp/jinja_cache', '%s.cache')
+
+ This bytecode cache supports clearing of the cache using the clear method.
+ """
+
def __init__(
self, directory: t.Optional[str] = None, pattern: str = "__jinja2_%s.cache"
) -> None:
- if directory is None:
- directory = self._get_default_cache_dir()
- self.directory = directory
- self.pattern = pattern
-
+ if directory is None:
+ directory = self._get_default_cache_dir()
+ self.directory = directory
+ self.pattern = pattern
+
def _get_default_cache_dir(self) -> str:
def _unsafe_dir() -> "te.NoReturn":
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.
+
+ tmpdir = tempfile.gettempdir()
+
+ # On windows the temporary directory is used specific unless
+ # explicitly forced otherwise. We can just use that.
if os.name == "nt":
- return tmpdir
+ return tmpdir
if not hasattr(os, "getuid"):
- _unsafe_dir()
-
+ _unsafe_dir()
+
dirname = f"_jinja2-cache-{os.getuid()}"
- actual_dir = os.path.join(tmpdir, dirname)
-
- try:
- os.mkdir(actual_dir, stat.S_IRWXU)
- except OSError as e:
- if e.errno != errno.EEXIST:
- raise
- try:
- os.chmod(actual_dir, stat.S_IRWXU)
- actual_dir_stat = os.lstat(actual_dir)
+ actual_dir = os.path.join(tmpdir, dirname)
+
+ try:
+ os.mkdir(actual_dir, stat.S_IRWXU)
+ except OSError as e:
+ if e.errno != errno.EEXIST:
+ raise
+ 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
):
- _unsafe_dir()
- except OSError as e:
- if e.errno != errno.EEXIST:
- raise
-
- actual_dir_stat = os.lstat(actual_dir)
+ _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
):
- _unsafe_dir()
-
- return actual_dir
-
+ _unsafe_dir()
+
+ return actual_dir
+
def _get_cache_filename(self, bucket: Bucket) -> str:
return os.path.join(self.directory, self.pattern % (bucket.key,))
-
+
def load_bytecode(self, bucket: Bucket) -> None:
filename = self._get_cache_filename(bucket)
if os.path.exists(filename):
with open(filename, "rb") as f:
- bucket.load_bytecode(f)
-
+ bucket.load_bytecode(f)
+
def dump_bytecode(self, bucket: Bucket) -> None:
with open(self._get_cache_filename(bucket), "wb") as f:
- bucket.write_bytecode(f)
-
+ bucket.write_bytecode(f)
+
def clear(self) -> None:
- # imported lazily here because google app-engine doesn't support
- # write access on the file system and the function does not exist
- # normally.
- from os import remove
+ # imported lazily here because google app-engine doesn't support
+ # write access on the file system and the function does not exist
+ # normally.
+ from os import remove
files = fnmatch.filter(os.listdir(self.directory), self.pattern % ("*",))
- for filename in files:
- try:
+ for filename in files:
+ try:
remove(os.path.join(self.directory, filename))
- except OSError:
- pass
-
-
-class MemcachedBytecodeCache(BytecodeCache):
- """This class implements a bytecode cache that uses a memcache cache for
- storing the information. It does not enforce a specific memcache library
- (tummy's memcache or cmemcache) but will accept any class that provides
- the minimal interface required.
-
- Libraries compatible with this class:
-
+ except OSError:
+ pass
+
+
+class MemcachedBytecodeCache(BytecodeCache):
+ """This class implements a bytecode cache that uses a memcache cache for
+ storing the information. It does not enforce a specific memcache library
+ (tummy's memcache or cmemcache) but will accept any class that provides
+ the minimal interface required.
+
+ Libraries compatible with this class:
+
- `cachelib <https://github.com/pallets/cachelib>`_
- `python-memcached <https://pypi.org/project/python-memcached/>`_
-
- (Unfortunately the django cache interface is not compatible because it
+
+ (Unfortunately the django cache interface is not compatible because it
does not support storing binary data, only text. You can however pass
- the underlying cache client to the bytecode cache which is available
- as `django.core.cache.cache._client`.)
-
- The minimal interface for the client passed to the constructor is this:
-
- .. class:: MinimalClientInterface
-
- .. method:: set(key, value[, timeout])
-
- Stores the bytecode in the cache. `value` is a string and
- `timeout` the timeout of the key. If timeout is not provided
- a default timeout or no timeout should be assumed, if it's
- provided it's an integer with the number of seconds the cache
- item should exist.
-
- .. method:: get(key)
-
- Returns the value for the cache key. If the item does not
- exist in the cache the return value must be `None`.
-
- The other arguments to the constructor are the prefix for all keys that
- is added before the actual cache key and the timeout for the bytecode in
- the cache system. We recommend a high (or no) timeout.
-
- This bytecode cache does not support clearing of used items in the cache.
- The clear method is a no-operation function.
-
- .. versionadded:: 2.7
- Added support for ignoring memcache errors through the
- `ignore_memcache_errors` parameter.
- """
-
+ the underlying cache client to the bytecode cache which is available
+ as `django.core.cache.cache._client`.)
+
+ The minimal interface for the client passed to the constructor is this:
+
+ .. class:: MinimalClientInterface
+
+ .. method:: set(key, value[, timeout])
+
+ Stores the bytecode in the cache. `value` is a string and
+ `timeout` the timeout of the key. If timeout is not provided
+ a default timeout or no timeout should be assumed, if it's
+ provided it's an integer with the number of seconds the cache
+ item should exist.
+
+ .. method:: get(key)
+
+ Returns the value for the cache key. If the item does not
+ exist in the cache the return value must be `None`.
+
+ The other arguments to the constructor are the prefix for all keys that
+ is added before the actual cache key and the timeout for the bytecode in
+ the cache system. We recommend a high (or no) timeout.
+
+ This bytecode cache does not support clearing of used items in the cache.
+ The clear method is a no-operation function.
+
+ .. versionadded:: 2.7
+ Added support for ignoring memcache errors through the
+ `ignore_memcache_errors` parameter.
+ """
+
def __init__(
self,
client: "_MemcachedClient",
@@ -336,29 +336,29 @@ class MemcachedBytecodeCache(BytecodeCache):
timeout: t.Optional[int] = None,
ignore_memcache_errors: bool = True,
):
- self.client = client
- self.prefix = prefix
- self.timeout = timeout
- self.ignore_memcache_errors = ignore_memcache_errors
-
+ self.client = client
+ self.prefix = prefix
+ self.timeout = timeout
+ self.ignore_memcache_errors = ignore_memcache_errors
+
def load_bytecode(self, bucket: Bucket) -> None:
- try:
- code = self.client.get(self.prefix + bucket.key)
- except Exception:
- if not self.ignore_memcache_errors:
- raise
+ try:
+ code = self.client.get(self.prefix + bucket.key)
+ except Exception:
+ if not self.ignore_memcache_errors:
+ raise
else:
- bucket.bytecode_from_string(code)
-
+ bucket.bytecode_from_string(code)
+
def dump_bytecode(self, bucket: Bucket) -> None:
key = self.prefix + bucket.key
value = bucket.bytecode_to_string()
- try:
+ try:
if self.timeout is not None:
self.client.set(key, value, self.timeout)
else:
self.client.set(key, value)
- except Exception:
- if not self.ignore_memcache_errors:
- raise
+ except Exception:
+ if not self.ignore_memcache_errors:
+ raise
diff --git a/contrib/python/Jinja2/py3/jinja2/compiler.py b/contrib/python/Jinja2/py3/jinja2/compiler.py
index 52fd5b83e2..9b6a9e9ea6 100644
--- a/contrib/python/Jinja2/py3/jinja2/compiler.py
+++ b/contrib/python/Jinja2/py3/jinja2/compiler.py
@@ -3,12 +3,12 @@ import typing as t
from contextlib import contextmanager
from functools import update_wrapper
from io import StringIO
-from itertools import chain
-from keyword import iskeyword as is_python_keyword
-
+from itertools import chain
+from keyword import iskeyword as is_python_keyword
+
from markupsafe import escape
from markupsafe import Markup
-
+
from . import nodes
from .exceptions import TemplateAssertionError
from .idtracking import Symbols
@@ -28,7 +28,7 @@ if t.TYPE_CHECKING:
F = t.TypeVar("F", bound=t.Callable[..., t.Any])
-operators = {
+operators = {
"eq": "==",
"ne": "!=",
"gt": ">",
@@ -37,25 +37,25 @@ operators = {
"lteq": "<=",
"in": "in",
"notin": "not in",
-}
-
-
+}
+
+
def optimizeconst(f: F) -> F:
def new_func(
self: "CodeGenerator", node: nodes.Expr, frame: "Frame", **kwargs: t.Any
) -> t.Any:
- # Only optimize if the frame is not volatile
+ # Only optimize if the frame is not volatile
if self.optimizer is not None and not frame.eval_ctx.volatile:
- new_node = self.optimizer.visit(node, frame.eval_ctx)
+ new_node = self.optimizer.visit(node, frame.eval_ctx)
- if new_node != node:
- return self.visit(new_node, frame)
+ if new_node != node:
+ return self.visit(new_node, frame)
- return f(self, node, frame, **kwargs)
+ return f(self, node, frame, **kwargs)
return update_wrapper(t.cast(F, new_func), f)
-
-
+
+
def _make_binop(op: str) -> t.Callable[["CodeGenerator", nodes.BinExpr, "Frame"], None]:
@optimizeconst
def visitor(self: "CodeGenerator", node: nodes.BinExpr, frame: Frame) -> None:
@@ -107,28 +107,28 @@ def generate(
defer_init: bool = False,
optimized: bool = True,
) -> t.Optional[str]:
- """Generate the python source for a node tree."""
- if not isinstance(node, nodes.Template):
+ """Generate the python source for a node tree."""
+ if not isinstance(node, nodes.Template):
raise TypeError("Can't compile non template nodes")
generator = environment.code_generator_class(
environment, name, filename, stream, defer_init, optimized
)
- generator.visit(node)
+ generator.visit(node)
- if stream is None:
+ if stream is None:
return generator.stream.getvalue() # type: ignore
-
+
return None
-
+
def has_safe_repr(value: t.Any) -> bool:
- """Does the node have a safe representation?"""
- if value is None or value is NotImplemented or value is Ellipsis:
- return True
+ """Does the node have a safe representation?"""
+ if value is None or value is NotImplemented or value is Ellipsis:
+ return True
if type(value) in {bool, int, float, complex, range, str, Markup}:
- return True
+ return True
if type(value) in {tuple, list, set, frozenset}:
return all(has_safe_repr(v) for v in value)
@@ -136,43 +136,43 @@ def has_safe_repr(value: t.Any) -> bool:
if type(value) is dict:
return all(has_safe_repr(k) and has_safe_repr(v) for k, v in value.items())
- return False
-
-
+ return False
+
+
def find_undeclared(
nodes: t.Iterable[nodes.Node], names: t.Iterable[str]
) -> t.Set[str]:
- """Check if the names passed are accessed undeclared. The return value
- is a set of all the undeclared names from the sequence of names found.
- """
- visitor = UndeclaredNameVisitor(names)
- try:
- for node in nodes:
- visitor.visit(node)
- except VisitorExit:
- pass
- return visitor.undeclared
-
-
+ """Check if the names passed are accessed undeclared. The return value
+ is a set of all the undeclared names from the sequence of names found.
+ """
+ visitor = UndeclaredNameVisitor(names)
+ try:
+ for node in nodes:
+ visitor.visit(node)
+ except VisitorExit:
+ pass
+ return visitor.undeclared
+
+
class MacroRef:
def __init__(self, node: t.Union[nodes.Macro, nodes.CallBlock]) -> None:
- self.node = node
- self.accesses_caller = False
- self.accesses_kwargs = False
- self.accesses_varargs = False
-
-
+ self.node = node
+ self.accesses_caller = False
+ self.accesses_kwargs = False
+ self.accesses_varargs = False
+
+
class Frame:
- """Holds compile time information for us."""
-
+ """Holds compile time information for us."""
+
def __init__(
self,
eval_ctx: EvalContext,
parent: t.Optional["Frame"] = None,
level: t.Optional[int] = None,
) -> None:
- self.eval_ctx = eval_ctx
-
+ self.eval_ctx = eval_ctx
+
# the parent of this frame
self.parent = parent
@@ -198,106 +198,106 @@ class Frame:
self.buffer = parent.buffer
self.block = parent.block
- # a toplevel frame is the root + soft frames such as if conditions.
- self.toplevel = False
-
- # the root frame is basically just the outermost frame, so no if
- # conditions. This information is used to optimize inheritance
- # situations.
- self.rootlevel = False
-
+ # a toplevel frame is the root + soft frames such as if conditions.
+ self.toplevel = False
+
+ # the root frame is basically just the outermost frame, so no if
+ # conditions. This information is used to optimize inheritance
+ # situations.
+ self.rootlevel = False
+
# variables set inside of loops and blocks should not affect outer frames,
# but they still needs to be kept track of as part of the active context.
self.loop_frame = False
self.block_frame = False
-
+
# track whether the frame is being used in an if-statement or conditional
# expression as it determines which errors should be raised during runtime
# or compile time.
self.soft_frame = False
-
+
def copy(self) -> "Frame":
- """Create a copy of the current one."""
+ """Create a copy of the current one."""
rv = t.cast(Frame, object.__new__(self.__class__))
- rv.__dict__.update(self.__dict__)
- rv.symbols = self.symbols.copy()
- return rv
-
+ rv.__dict__.update(self.__dict__)
+ rv.symbols = self.symbols.copy()
+ return rv
+
def inner(self, isolated: bool = False) -> "Frame":
- """Return an inner frame."""
- if isolated:
- return Frame(self.eval_ctx, level=self.symbols.level + 1)
- return Frame(self.eval_ctx, self)
-
+ """Return an inner frame."""
+ if isolated:
+ return Frame(self.eval_ctx, level=self.symbols.level + 1)
+ return Frame(self.eval_ctx, self)
+
def soft(self) -> "Frame":
- """Return a soft frame. A soft frame may not be modified as
- standalone thing as it shares the resources with the frame it
- was created of, but it's not a rootlevel frame any longer.
-
+ """Return a soft frame. A soft frame may not be modified as
+ standalone thing as it shares the resources with the frame it
+ was created of, but it's not a rootlevel frame any longer.
+
This is only used to implement if-statements and conditional
expressions.
- """
- rv = self.copy()
- rv.rootlevel = False
+ """
+ rv = self.copy()
+ rv.rootlevel = False
rv.soft_frame = True
- return rv
-
- __copy__ = copy
-
-
-class VisitorExit(RuntimeError):
- """Exception used by the `UndeclaredNameVisitor` to signal a stop."""
-
-
-class DependencyFinderVisitor(NodeVisitor):
- """A visitor that collects filter and test calls."""
-
+ return rv
+
+ __copy__ = copy
+
+
+class VisitorExit(RuntimeError):
+ """Exception used by the `UndeclaredNameVisitor` to signal a stop."""
+
+
+class DependencyFinderVisitor(NodeVisitor):
+ """A visitor that collects filter and test calls."""
+
def __init__(self) -> None:
self.filters: t.Set[str] = set()
self.tests: t.Set[str] = set()
-
+
def visit_Filter(self, node: nodes.Filter) -> None:
- self.generic_visit(node)
- self.filters.add(node.name)
-
+ self.generic_visit(node)
+ self.filters.add(node.name)
+
def visit_Test(self, node: nodes.Test) -> None:
- self.generic_visit(node)
- self.tests.add(node.name)
-
+ self.generic_visit(node)
+ self.tests.add(node.name)
+
def visit_Block(self, node: nodes.Block) -> None:
- """Stop visiting at blocks."""
-
-
-class UndeclaredNameVisitor(NodeVisitor):
- """A visitor that checks if a name is accessed without being
- declared. This is different from the frame visitor as it will
- not stop at closure frames.
- """
-
+ """Stop visiting at blocks."""
+
+
+class UndeclaredNameVisitor(NodeVisitor):
+ """A visitor that checks if a name is accessed without being
+ declared. This is different from the frame visitor as it will
+ not stop at closure frames.
+ """
+
def __init__(self, names: t.Iterable[str]) -> None:
- self.names = set(names)
+ self.names = set(names)
self.undeclared: t.Set[str] = set()
-
+
def visit_Name(self, node: nodes.Name) -> None:
if node.ctx == "load" and node.name in self.names:
- self.undeclared.add(node.name)
- if self.undeclared == self.names:
- raise VisitorExit()
- else:
- self.names.discard(node.name)
-
+ self.undeclared.add(node.name)
+ if self.undeclared == self.names:
+ raise VisitorExit()
+ else:
+ self.names.discard(node.name)
+
def visit_Block(self, node: nodes.Block) -> None:
- """Stop visiting a blocks."""
-
-
-class CompilerExit(Exception):
- """Raised if the compiler encountered a situation where it just
- doesn't make sense to further process the code. Any block that
- raises such an exception is not further processed.
- """
-
-
-class CodeGenerator(NodeVisitor):
+ """Stop visiting a blocks."""
+
+
+class CompilerExit(Exception):
+ """Raised if the compiler encountered a situation where it just
+ doesn't make sense to further process the code. Any block that
+ raises such an exception is not further processed.
+ """
+
+
+class CodeGenerator(NodeVisitor):
def __init__(
self,
environment: "Environment",
@@ -307,234 +307,234 @@ class CodeGenerator(NodeVisitor):
defer_init: bool = False,
optimized: bool = True,
) -> None:
- if stream is None:
+ if stream is None:
stream = StringIO()
- self.environment = environment
- self.name = name
- self.filename = filename
- self.stream = stream
- self.created_block_context = False
- self.defer_init = defer_init
+ self.environment = environment
+ self.name = name
+ self.filename = filename
+ self.stream = stream
+ self.created_block_context = False
+ self.defer_init = defer_init
self.optimizer: t.Optional[Optimizer] = None
- if optimized:
- self.optimizer = Optimizer(environment)
-
- # aliases for imports
+ if optimized:
+ self.optimizer = Optimizer(environment)
+
+ # aliases for imports
self.import_aliases: t.Dict[str, str] = {}
-
- # a registry for all blocks. Because blocks are moved out
- # into the global python scope they are registered here
+
+ # a registry for all blocks. Because blocks are moved out
+ # into the global python scope they are registered here
self.blocks: t.Dict[str, nodes.Block] = {}
-
- # the number of extends statements so far
- self.extends_so_far = 0
-
- # some templates have a rootlevel extends. In this case we
- # can safely assume that we're a child template and do some
- # more optimizations.
- self.has_known_extends = False
-
- # the current line number
- self.code_lineno = 1
-
- # registry of all filters and tests (global, not block local)
+
+ # the number of extends statements so far
+ self.extends_so_far = 0
+
+ # some templates have a rootlevel extends. In this case we
+ # can safely assume that we're a child template and do some
+ # more optimizations.
+ self.has_known_extends = False
+
+ # the current line number
+ self.code_lineno = 1
+
+ # registry of all filters and tests (global, not block local)
self.tests: t.Dict[str, str] = {}
self.filters: t.Dict[str, str] = {}
-
- # the debug information
+
+ # the debug information
self.debug_info: t.List[t.Tuple[int, int]] = []
self._write_debug_info: t.Optional[int] = None
-
- # the number of new lines before the next write()
- self._new_lines = 0
-
- # the line number of the last written statement
- self._last_line = 0
-
- # true if nothing was written so far.
- self._first_write = True
-
- # used by the `temporary_identifier` method to get new
- # unique, temporary identifier
- self._last_identifier = 0
-
- # the current indentation
- self._indentation = 0
-
- # Tracks toplevel assignments
+
+ # the number of new lines before the next write()
+ self._new_lines = 0
+
+ # the line number of the last written statement
+ self._last_line = 0
+
+ # true if nothing was written so far.
+ self._first_write = True
+
+ # used by the `temporary_identifier` method to get new
+ # unique, temporary identifier
+ self._last_identifier = 0
+
+ # the current indentation
+ self._indentation = 0
+
+ # Tracks toplevel assignments
self._assign_stack: t.List[t.Set[str]] = []
-
- # Tracks parameter definition blocks
+
+ # Tracks parameter definition blocks
self._param_def_block: t.List[t.Set[str]] = []
-
- # Tracks the current context.
+
+ # Tracks the current context.
self._context_reference_stack = ["context"]
-
+
@property
def optimized(self) -> bool:
return self.optimizer is not None
- # -- Various compilation helpers
-
+ # -- Various compilation helpers
+
def fail(self, msg: str, lineno: int) -> "te.NoReturn":
- """Fail with a :exc:`TemplateAssertionError`."""
- raise TemplateAssertionError(msg, lineno, self.name, self.filename)
-
+ """Fail with a :exc:`TemplateAssertionError`."""
+ raise TemplateAssertionError(msg, lineno, self.name, self.filename)
+
def temporary_identifier(self) -> str:
- """Get a new unique identifier."""
- self._last_identifier += 1
+ """Get a new unique identifier."""
+ self._last_identifier += 1
return f"t_{self._last_identifier}"
-
+
def buffer(self, frame: Frame) -> None:
- """Enable buffering for the frame from that point onwards."""
- frame.buffer = self.temporary_identifier()
+ """Enable buffering for the frame from that point onwards."""
+ frame.buffer = self.temporary_identifier()
self.writeline(f"{frame.buffer} = []")
-
+
def return_buffer_contents(
self, frame: Frame, force_unescaped: bool = False
) -> None:
- """Return the buffer contents of the frame."""
- if not force_unescaped:
- if frame.eval_ctx.volatile:
+ """Return the buffer contents of the frame."""
+ if not force_unescaped:
+ if frame.eval_ctx.volatile:
self.writeline("if context.eval_ctx.autoescape:")
- self.indent()
+ self.indent()
self.writeline(f"return Markup(concat({frame.buffer}))")
- self.outdent()
+ self.outdent()
self.writeline("else:")
- self.indent()
+ self.indent()
self.writeline(f"return concat({frame.buffer})")
- self.outdent()
- return
- elif frame.eval_ctx.autoescape:
+ self.outdent()
+ return
+ elif frame.eval_ctx.autoescape:
self.writeline(f"return Markup(concat({frame.buffer}))")
- return
+ return
self.writeline(f"return concat({frame.buffer})")
-
+
def indent(self) -> None:
- """Indent by one."""
- self._indentation += 1
-
+ """Indent by one."""
+ self._indentation += 1
+
def outdent(self, step: int = 1) -> None:
- """Outdent by step."""
- self._indentation -= step
-
+ """Outdent by step."""
+ self._indentation -= step
+
def start_write(self, frame: Frame, node: t.Optional[nodes.Node] = None) -> None:
- """Yield or write into the frame buffer."""
- if frame.buffer is None:
+ """Yield or write into the frame buffer."""
+ if frame.buffer is None:
self.writeline("yield ", node)
- else:
+ else:
self.writeline(f"{frame.buffer}.append(", node)
-
+
def end_write(self, frame: Frame) -> None:
- """End the writing process started by `start_write`."""
- if frame.buffer is not None:
+ """End the writing process started by `start_write`."""
+ if frame.buffer is not None:
self.write(")")
-
+
def simple_write(
self, s: str, frame: Frame, node: t.Optional[nodes.Node] = None
) -> None:
- """Simple shortcut for start_write + write + end_write."""
- self.start_write(frame, node)
- self.write(s)
- self.end_write(frame)
-
+ """Simple shortcut for start_write + write + end_write."""
+ self.start_write(frame, node)
+ self.write(s)
+ self.end_write(frame)
+
def blockvisit(self, nodes: t.Iterable[nodes.Node], frame: Frame) -> None:
- """Visit a list of nodes as block in a frame. If the current frame
- is no buffer a dummy ``if 0: yield None`` is written automatically.
- """
- try:
+ """Visit a list of nodes as block in a frame. If the current frame
+ is no buffer a dummy ``if 0: yield None`` is written automatically.
+ """
+ try:
self.writeline("pass")
- for node in nodes:
- self.visit(node, frame)
- except CompilerExit:
- pass
-
+ for node in nodes:
+ self.visit(node, frame)
+ except CompilerExit:
+ pass
+
def write(self, x: str) -> None:
- """Write a string into the output stream."""
- if self._new_lines:
- if not self._first_write:
+ """Write a string into the output stream."""
+ if self._new_lines:
+ if not self._first_write:
self.stream.write("\n" * self._new_lines)
- self.code_lineno += self._new_lines
- if self._write_debug_info is not None:
+ self.code_lineno += self._new_lines
+ if self._write_debug_info is not None:
self.debug_info.append((self._write_debug_info, self.code_lineno))
- self._write_debug_info = None
- self._first_write = False
+ self._write_debug_info = None
+ self._first_write = False
self.stream.write(" " * self._indentation)
- self._new_lines = 0
- self.stream.write(x)
-
+ self._new_lines = 0
+ self.stream.write(x)
+
def writeline(
self, x: str, node: t.Optional[nodes.Node] = None, extra: int = 0
) -> None:
- """Combination of newline and write."""
- self.newline(node, extra)
- self.write(x)
-
+ """Combination of newline and write."""
+ self.newline(node, extra)
+ self.write(x)
+
def newline(self, node: t.Optional[nodes.Node] = None, extra: int = 0) -> None:
- """Add one or more newlines before the next write."""
- self._new_lines = max(self._new_lines, 1 + extra)
- if node is not None and node.lineno != self._last_line:
- self._write_debug_info = node.lineno
- self._last_line = node.lineno
-
+ """Add one or more newlines before the next write."""
+ self._new_lines = max(self._new_lines, 1 + extra)
+ if node is not None and node.lineno != self._last_line:
+ self._write_debug_info = node.lineno
+ self._last_line = node.lineno
+
def signature(
self,
node: t.Union[nodes.Call, nodes.Filter, nodes.Test],
frame: Frame,
extra_kwargs: t.Optional[t.Mapping[str, t.Any]] = None,
) -> None:
- """Writes a function call to the stream for the current node.
- A leading comma is added automatically. The extra keyword
- arguments may not include python keywords otherwise a syntax
+ """Writes a function call to the stream for the current node.
+ A leading comma is added automatically. The extra keyword
+ arguments may not include python keywords otherwise a syntax
error could occur. The extra keyword arguments should be given
- as python dict.
- """
- # if any of the given keyword arguments is a python keyword
- # we have to make sure that no invalid call is created.
+ as python dict.
+ """
+ # if any of the given keyword arguments is a python keyword
+ # we have to make sure that no invalid call is created.
kwarg_workaround = any(
is_python_keyword(t.cast(str, k))
for k in chain((x.key for x in node.kwargs), extra_kwargs or ())
)
-
- for arg in node.args:
+
+ for arg in node.args:
self.write(", ")
- self.visit(arg, frame)
-
- if not kwarg_workaround:
- for kwarg in node.kwargs:
+ self.visit(arg, frame)
+
+ if not kwarg_workaround:
+ for kwarg in node.kwargs:
self.write(", ")
- self.visit(kwarg, frame)
- if extra_kwargs is not None:
+ self.visit(kwarg, frame)
+ if extra_kwargs is not None:
for key, value in extra_kwargs.items():
self.write(f", {key}={value}")
- if node.dyn_args:
+ if node.dyn_args:
self.write(", *")
- self.visit(node.dyn_args, frame)
-
- if kwarg_workaround:
- if node.dyn_kwargs is not None:
+ self.visit(node.dyn_args, frame)
+
+ if kwarg_workaround:
+ if node.dyn_kwargs is not None:
self.write(", **dict({")
- else:
+ else:
self.write(", **{")
- for kwarg in node.kwargs:
+ for kwarg in node.kwargs:
self.write(f"{kwarg.key!r}: ")
- self.visit(kwarg.value, frame)
+ self.visit(kwarg.value, frame)
self.write(", ")
- if extra_kwargs is not None:
+ if extra_kwargs is not None:
for key, value in extra_kwargs.items():
self.write(f"{key!r}: {value}, ")
- if node.dyn_kwargs is not None:
+ if node.dyn_kwargs is not None:
self.write("}, **")
- self.visit(node.dyn_kwargs, frame)
+ self.visit(node.dyn_kwargs, frame)
self.write(")")
- else:
+ else:
self.write("}")
-
- elif node.dyn_kwargs is not None:
+
+ elif node.dyn_kwargs is not None:
self.write(", **")
- self.visit(node.dyn_kwargs, frame)
-
+ self.visit(node.dyn_kwargs, frame)
+
def pull_dependencies(self, nodes: t.Iterable[nodes.Node]) -> None:
"""Find all filter and test names used in the template and
assign them to variables in the compiled namespace. Checking
@@ -546,10 +546,10 @@ class CodeGenerator(NodeVisitor):
Filters and tests in If and CondExpr nodes are checked at
runtime instead of compile time.
"""
- visitor = DependencyFinderVisitor()
+ visitor = DependencyFinderVisitor()
- for node in nodes:
- visitor.visit(node)
+ for node in nodes:
+ visitor.visit(node)
for id_map, names, dependency in (self.filters, visitor.filters, "filters"), (
self.tests,
@@ -577,222 +577,222 @@ class CodeGenerator(NodeVisitor):
)
self.outdent()
self.outdent()
-
+
def enter_frame(self, frame: Frame) -> None:
- undefs = []
+ undefs = []
for target, (action, param) in frame.symbols.loads.items():
- if action == VAR_LOAD_PARAMETER:
- pass
- elif action == VAR_LOAD_RESOLVE:
+ if action == VAR_LOAD_PARAMETER:
+ pass
+ elif action == VAR_LOAD_RESOLVE:
self.writeline(f"{target} = {self.get_resolve_func()}({param!r})")
- elif action == VAR_LOAD_ALIAS:
+ elif action == VAR_LOAD_ALIAS:
self.writeline(f"{target} = {param}")
- elif action == VAR_LOAD_UNDEFINED:
- undefs.append(target)
- else:
+ elif action == VAR_LOAD_UNDEFINED:
+ undefs.append(target)
+ else:
raise NotImplementedError("unknown load instruction")
- if undefs:
+ if undefs:
self.writeline(f"{' = '.join(undefs)} = missing")
-
+
def leave_frame(self, frame: Frame, with_python_scope: bool = False) -> None:
- if not with_python_scope:
- undefs = []
+ if not with_python_scope:
+ undefs = []
for target in frame.symbols.loads:
- undefs.append(target)
- if undefs:
+ undefs.append(target)
+ if undefs:
self.writeline(f"{' = '.join(undefs)} = missing")
-
+
def choose_async(self, async_value: str = "async ", sync_value: str = "") -> str:
return async_value if self.environment.is_async else sync_value
-
+
def func(self, name: str) -> str:
return f"{self.choose_async()}def {name}"
def macro_body(
self, node: t.Union[nodes.Macro, nodes.CallBlock], frame: Frame
) -> t.Tuple[Frame, MacroRef]:
- """Dump the function def of a macro or call block."""
- frame = frame.inner()
- frame.symbols.analyze_node(node)
- macro_ref = MacroRef(node)
-
- explicit_caller = None
- skip_special_params = set()
- args = []
-
- for idx, arg in enumerate(node.args):
+ """Dump the function def of a macro or call block."""
+ frame = frame.inner()
+ frame.symbols.analyze_node(node)
+ macro_ref = MacroRef(node)
+
+ explicit_caller = None
+ skip_special_params = set()
+ args = []
+
+ for idx, arg in enumerate(node.args):
if arg.name == "caller":
- explicit_caller = idx
+ explicit_caller = idx
if arg.name in ("kwargs", "varargs"):
- skip_special_params.add(arg.name)
- args.append(frame.symbols.ref(arg.name))
-
+ skip_special_params.add(arg.name)
+ args.append(frame.symbols.ref(arg.name))
+
undeclared = find_undeclared(node.body, ("caller", "kwargs", "varargs"))
-
+
if "caller" in undeclared:
# In older Jinja versions there was a bug that allowed caller
- # to retain the special behavior even if it was mentioned in
- # the argument list. However thankfully this was only really
- # working if it was the last argument. So we are explicitly
- # checking this now and error out if it is anywhere else in
- # the argument list.
- if explicit_caller is not None:
- try:
- node.defaults[explicit_caller - len(node.args)]
- except IndexError:
+ # to retain the special behavior even if it was mentioned in
+ # the argument list. However thankfully this was only really
+ # working if it was the last argument. So we are explicitly
+ # checking this now and error out if it is anywhere else in
+ # the argument list.
+ if explicit_caller is not None:
+ try:
+ node.defaults[explicit_caller - len(node.args)]
+ except IndexError:
self.fail(
"When defining macros or call blocks the "
'special "caller" argument must be omitted '
"or be given a default.",
node.lineno,
)
- else:
+ else:
args.append(frame.symbols.declare_parameter("caller"))
- macro_ref.accesses_caller = True
+ macro_ref.accesses_caller = True
if "kwargs" in undeclared and "kwargs" not in skip_special_params:
args.append(frame.symbols.declare_parameter("kwargs"))
- macro_ref.accesses_kwargs = True
+ macro_ref.accesses_kwargs = True
if "varargs" in undeclared and "varargs" not in skip_special_params:
args.append(frame.symbols.declare_parameter("varargs"))
- macro_ref.accesses_varargs = True
-
- # macros are delayed, they never require output checks
- frame.require_output_check = False
- frame.symbols.analyze_node(node)
+ macro_ref.accesses_varargs = True
+
+ # macros are delayed, they never require output checks
+ frame.require_output_check = False
+ frame.symbols.analyze_node(node)
self.writeline(f"{self.func('macro')}({', '.join(args)}):", node)
- self.indent()
-
- self.buffer(frame)
- self.enter_frame(frame)
-
- self.push_parameter_definitions(frame)
- for idx, arg in enumerate(node.args):
- ref = frame.symbols.ref(arg.name)
+ self.indent()
+
+ self.buffer(frame)
+ self.enter_frame(frame)
+
+ self.push_parameter_definitions(frame)
+ for idx, arg in enumerate(node.args):
+ ref = frame.symbols.ref(arg.name)
self.writeline(f"if {ref} is missing:")
- self.indent()
- try:
- default = node.defaults[idx - len(node.args)]
- except IndexError:
+ self.indent()
+ try:
+ default = node.defaults[idx - len(node.args)]
+ except IndexError:
self.writeline(
f'{ref} = undefined("parameter {arg.name!r} was not provided",'
f" name={arg.name!r})"
)
- else:
+ else:
self.writeline(f"{ref} = ")
- self.visit(default, frame)
- self.mark_parameter_stored(ref)
- self.outdent()
- self.pop_parameter_definitions()
-
- self.blockvisit(node.body, frame)
- self.return_buffer_contents(frame, force_unescaped=True)
- self.leave_frame(frame, with_python_scope=True)
- self.outdent()
-
- return frame, macro_ref
-
+ self.visit(default, frame)
+ self.mark_parameter_stored(ref)
+ self.outdent()
+ self.pop_parameter_definitions()
+
+ self.blockvisit(node.body, frame)
+ self.return_buffer_contents(frame, force_unescaped=True)
+ self.leave_frame(frame, with_python_scope=True)
+ self.outdent()
+
+ return frame, macro_ref
+
def macro_def(self, macro_ref: MacroRef, frame: Frame) -> None:
- """Dump the macro definition for the def created by macro_body."""
+ """Dump the macro definition for the def created by macro_body."""
arg_tuple = ", ".join(repr(x.name) for x in macro_ref.node.args)
name = getattr(macro_ref.node, "name", None)
- if len(macro_ref.node.args) == 1:
+ if len(macro_ref.node.args) == 1:
arg_tuple += ","
self.write(
f"Macro(environment, macro, {name!r}, ({arg_tuple}),"
f" {macro_ref.accesses_kwargs!r}, {macro_ref.accesses_varargs!r},"
f" {macro_ref.accesses_caller!r}, context.eval_ctx.autoescape)"
)
-
+
def position(self, node: nodes.Node) -> str:
- """Return a human readable position for the node."""
+ """Return a human readable position for the node."""
rv = f"line {node.lineno}"
- if self.name is not None:
+ if self.name is not None:
rv = f"{rv} in {self.name!r}"
- return rv
-
+ return rv
+
def dump_local_context(self, frame: Frame) -> str:
items_kv = ", ".join(
f"{name!r}: {target}"
for name, target in frame.symbols.dump_stores().items()
)
return f"{{{items_kv}}}"
-
+
def write_commons(self) -> None:
- """Writes a common preamble that is used by root and block functions.
- Primarily this sets up common local helpers and enforces a generator
- through a dead branch.
- """
+ """Writes a common preamble that is used by root and block functions.
+ Primarily this sets up common local helpers and enforces a generator
+ through a dead branch.
+ """
self.writeline("resolve = context.resolve_or_missing")
self.writeline("undefined = environment.undefined")
# always use the standard Undefined class for the implicit else of
# conditional expressions
self.writeline("cond_expr_undefined = Undefined")
self.writeline("if 0: yield None")
-
+
def push_parameter_definitions(self, frame: Frame) -> None:
- """Pushes all parameter targets from the given frame into a local
- stack that permits tracking of yet to be assigned parameters. In
- particular this enables the optimization from `visit_Name` to skip
- undefined expressions for parameters in macros as macros can reference
- otherwise unbound parameters.
- """
- self._param_def_block.append(frame.symbols.dump_param_targets())
-
+ """Pushes all parameter targets from the given frame into a local
+ stack that permits tracking of yet to be assigned parameters. In
+ particular this enables the optimization from `visit_Name` to skip
+ undefined expressions for parameters in macros as macros can reference
+ otherwise unbound parameters.
+ """
+ self._param_def_block.append(frame.symbols.dump_param_targets())
+
def pop_parameter_definitions(self) -> None:
- """Pops the current parameter definitions set."""
- self._param_def_block.pop()
-
+ """Pops the current parameter definitions set."""
+ self._param_def_block.pop()
+
def mark_parameter_stored(self, target: str) -> None:
- """Marks a parameter in the current parameter definitions as stored.
- This will skip the enforced undefined checks.
- """
- if self._param_def_block:
- self._param_def_block[-1].discard(target)
-
+ """Marks a parameter in the current parameter definitions as stored.
+ This will skip the enforced undefined checks.
+ """
+ if self._param_def_block:
+ self._param_def_block[-1].discard(target)
+
def push_context_reference(self, target: str) -> None:
- self._context_reference_stack.append(target)
-
+ self._context_reference_stack.append(target)
+
def pop_context_reference(self) -> None:
- self._context_reference_stack.pop()
-
+ self._context_reference_stack.pop()
+
def get_context_ref(self) -> str:
- return self._context_reference_stack[-1]
-
+ return self._context_reference_stack[-1]
+
def get_resolve_func(self) -> str:
- target = self._context_reference_stack[-1]
+ target = self._context_reference_stack[-1]
if target == "context":
return "resolve"
return f"{target}.resolve"
-
+
def derive_context(self, frame: Frame) -> str:
return f"{self.get_context_ref()}.derived({self.dump_local_context(frame)})"
-
+
def parameter_is_undeclared(self, target: str) -> bool:
- """Checks if a given target is an undeclared parameter."""
- if not self._param_def_block:
- return False
- return target in self._param_def_block[-1]
-
+ """Checks if a given target is an undeclared parameter."""
+ if not self._param_def_block:
+ return False
+ return target in self._param_def_block[-1]
+
def push_assign_tracking(self) -> None:
- """Pushes a new layer for assignment tracking."""
- self._assign_stack.append(set())
-
+ """Pushes a new layer for assignment tracking."""
+ self._assign_stack.append(set())
+
def pop_assign_tracking(self, frame: Frame) -> None:
- """Pops the topmost level for assignment tracking and updates the
- context variables if necessary.
- """
- vars = self._assign_stack.pop()
+ """Pops the topmost level for assignment tracking and updates the
+ context variables if necessary.
+ """
+ vars = self._assign_stack.pop()
if (
not frame.block_frame
and not frame.loop_frame
and not frame.toplevel
or not vars
):
- return
+ return
public_names = [x for x in vars if x[:1] != "_"]
- if len(vars) == 1:
- name = next(iter(vars))
- ref = frame.symbols.ref(name)
+ if len(vars) == 1:
+ name = next(iter(vars))
+ ref = frame.symbols.ref(name)
if frame.loop_frame:
self.writeline(f"_loop_vars[{name!r}] = {ref}")
return
@@ -800,125 +800,125 @@ class CodeGenerator(NodeVisitor):
self.writeline(f"_block_vars[{name!r}] = {ref}")
return
self.writeline(f"context.vars[{name!r}] = {ref}")
- else:
+ else:
if frame.loop_frame:
self.writeline("_loop_vars.update({")
elif frame.block_frame:
self.writeline("_block_vars.update({")
else:
self.writeline("context.vars.update({")
- for idx, name in enumerate(vars):
- if idx:
+ for idx, name in enumerate(vars):
+ if idx:
self.write(", ")
- ref = frame.symbols.ref(name)
+ ref = frame.symbols.ref(name)
self.write(f"{name!r}: {ref}")
self.write("})")
if not frame.block_frame and not frame.loop_frame and public_names:
- if len(public_names) == 1:
+ if len(public_names) == 1:
self.writeline(f"context.exported_vars.add({public_names[0]!r})")
- else:
+ else:
names_str = ", ".join(map(repr, public_names))
self.writeline(f"context.exported_vars.update(({names_str}))")
-
- # -- Statement Visitors
-
+
+ # -- Statement Visitors
+
def visit_Template(
self, node: nodes.Template, frame: t.Optional[Frame] = None
) -> None:
assert frame is None, "no root frame allowed"
- eval_ctx = EvalContext(self.environment, self.name)
-
+ eval_ctx = EvalContext(self.environment, self.name)
+
from .runtime import exported, async_exported
-
- if self.environment.is_async:
+
+ if self.environment.is_async:
exported_names = sorted(exported + async_exported)
else:
exported_names = sorted(exported)
-
+
self.writeline("from __future__ import generator_stop") # Python < 3.7
self.writeline("from jinja2.runtime import " + ", ".join(exported_names))
- # if we want a deferred initialization we cannot move the
- # environment into a local name
+ # if we want a deferred initialization we cannot move the
+ # environment into a local name
envenv = "" if self.defer_init else ", environment=environment"
-
- # do we have an extends tag at all? If not, we can save some
- # overhead by just not processing any inheritance code.
- have_extends = node.find(nodes.Extends) is not None
-
- # find all blocks
- for block in node.find_all(nodes.Block):
- if block.name in self.blocks:
+
+ # do we have an extends tag at all? If not, we can save some
+ # overhead by just not processing any inheritance code.
+ have_extends = node.find(nodes.Extends) is not None
+
+ # find all blocks
+ for block in node.find_all(nodes.Block):
+ if block.name in self.blocks:
self.fail(f"block {block.name!r} defined twice", block.lineno)
- self.blocks[block.name] = block
-
- # find all imports and import them
- for import_ in node.find_all(nodes.ImportedName):
- if import_.importname not in self.import_aliases:
- imp = import_.importname
- self.import_aliases[imp] = alias = self.temporary_identifier()
+ self.blocks[block.name] = block
+
+ # find all imports and import them
+ for import_ in node.find_all(nodes.ImportedName):
+ if import_.importname not in self.import_aliases:
+ imp = import_.importname
+ self.import_aliases[imp] = alias = self.temporary_identifier()
if "." in imp:
module, obj = imp.rsplit(".", 1)
self.writeline(f"from {module} import {obj} as {alias}")
- else:
+ else:
self.writeline(f"import {imp} as {alias}")
-
- # add the load name
+
+ # add the load name
self.writeline(f"name = {self.name!r}")
-
- # generate the root render function.
+
+ # generate the root render function.
self.writeline(
f"{self.func('root')}(context, missing=missing{envenv}):", extra=1
)
- self.indent()
- self.write_commons()
-
- # process the root
- frame = Frame(eval_ctx)
+ self.indent()
+ self.write_commons()
+
+ # process the root
+ frame = Frame(eval_ctx)
if "self" in find_undeclared(node.body, ("self",)):
ref = frame.symbols.declare_parameter("self")
self.writeline(f"{ref} = TemplateReference(context)")
- frame.symbols.analyze_node(node)
- frame.toplevel = frame.rootlevel = True
- frame.require_output_check = have_extends and not self.has_known_extends
- if have_extends:
+ frame.symbols.analyze_node(node)
+ frame.toplevel = frame.rootlevel = True
+ frame.require_output_check = have_extends and not self.has_known_extends
+ if have_extends:
self.writeline("parent_template = None")
- self.enter_frame(frame)
- self.pull_dependencies(node.body)
- self.blockvisit(node.body, frame)
- self.leave_frame(frame, with_python_scope=True)
- self.outdent()
-
- # make sure that the parent root is called.
- if have_extends:
- if not self.has_known_extends:
- self.indent()
+ self.enter_frame(frame)
+ self.pull_dependencies(node.body)
+ self.blockvisit(node.body, frame)
+ self.leave_frame(frame, with_python_scope=True)
+ self.outdent()
+
+ # make sure that the parent root is called.
+ if have_extends:
+ if not self.has_known_extends:
+ self.indent()
self.writeline("if parent_template is not None:")
- self.indent()
+ self.indent()
if not self.environment.is_async:
self.writeline("yield from parent_template.root_render_func(context)")
- else:
+ else:
self.writeline(
"async for event in parent_template.root_render_func(context):"
)
- self.indent()
+ self.indent()
self.writeline("yield event")
- self.outdent()
- self.outdent(1 + (not self.has_known_extends))
-
- # at this point we now have the blocks collected and can visit them too.
+ self.outdent()
+ self.outdent(1 + (not self.has_known_extends))
+
+ # at this point we now have the blocks collected and can visit them too.
for name, block in self.blocks.items():
self.writeline(
f"{self.func('block_' + name)}(context, missing=missing{envenv}):",
block,
1,
)
- self.indent()
- self.write_commons()
- # It's important that we do not make this frame a child of the
- # toplevel template. This would cause a variety of
- # interesting issues with identifier tracking.
- block_frame = Frame(eval_ctx)
+ self.indent()
+ self.write_commons()
+ # It's important that we do not make this frame a child of the
+ # toplevel template. This would cause a variety of
+ # interesting issues with identifier tracking.
+ block_frame = Frame(eval_ctx)
block_frame.block_frame = True
undeclared = find_undeclared(block.body, ("self", "super"))
if "self" in undeclared:
@@ -927,38 +927,38 @@ class CodeGenerator(NodeVisitor):
if "super" in undeclared:
ref = block_frame.symbols.declare_parameter("super")
self.writeline(f"{ref} = context.super({name!r}, block_{name})")
- block_frame.symbols.analyze_node(block)
- block_frame.block = name
+ block_frame.symbols.analyze_node(block)
+ block_frame.block = name
self.writeline("_block_vars = {}")
- self.enter_frame(block_frame)
- self.pull_dependencies(block.body)
- self.blockvisit(block.body, block_frame)
- self.leave_frame(block_frame, with_python_scope=True)
- self.outdent()
-
+ self.enter_frame(block_frame)
+ self.pull_dependencies(block.body)
+ self.blockvisit(block.body, block_frame)
+ self.leave_frame(block_frame, with_python_scope=True)
+ self.outdent()
+
blocks_kv_str = ", ".join(f"{x!r}: block_{x}" for x in self.blocks)
self.writeline(f"blocks = {{{blocks_kv_str}}}", extra=1)
debug_kv_str = "&".join(f"{k}={v}" for k, v in self.debug_info)
self.writeline(f"debug_info = {debug_kv_str!r}")
-
+
def visit_Block(self, node: nodes.Block, frame: Frame) -> None:
- """Call a block and register it for the template."""
- level = 0
- if frame.toplevel:
- # if we know that we are a child template, there is no need to
- # check if we are one
- if self.has_known_extends:
- return
- if self.extends_so_far > 0:
+ """Call a block and register it for the template."""
+ level = 0
+ if frame.toplevel:
+ # if we know that we are a child template, there is no need to
+ # check if we are one
+ if self.has_known_extends:
+ return
+ if self.extends_so_far > 0:
self.writeline("if parent_template is None:")
- self.indent()
- level += 1
-
- if node.scoped:
- context = self.derive_context(frame)
- else:
- context = self.get_context_ref()
-
+ self.indent()
+ level += 1
+
+ if node.scoped:
+ context = self.derive_context(frame)
+ else:
+ context = self.get_context_ref()
+
if node.required:
self.writeline(f"if len(context.blocks[{node.name!r}]) <= 1:", node)
self.indent()
@@ -972,125 +972,125 @@ class CodeGenerator(NodeVisitor):
self.writeline(
f"yield from context.blocks[{node.name!r}][0]({context})", node
)
- else:
+ else:
self.writeline(
f"{self.choose_async()}for event in"
f" context.blocks[{node.name!r}][0]({context}):",
node,
)
- self.indent()
+ self.indent()
self.simple_write("event", frame)
- self.outdent()
-
- self.outdent(level)
-
+ self.outdent()
+
+ self.outdent(level)
+
def visit_Extends(self, node: nodes.Extends, frame: Frame) -> None:
- """Calls the extender."""
- if not frame.toplevel:
+ """Calls the extender."""
+ if not frame.toplevel:
self.fail("cannot use extend from a non top-level scope", node.lineno)
-
- # if the number of extends statements in general is zero so
- # far, we don't have to add a check if something extended
- # the template before this one.
- if self.extends_so_far > 0:
-
- # if we have a known extends we just add a template runtime
- # error into the generated code. We could catch that at compile
- # time too, but i welcome it not to confuse users by throwing the
- # same error at different times just "because we can".
- if not self.has_known_extends:
+
+ # if the number of extends statements in general is zero so
+ # far, we don't have to add a check if something extended
+ # the template before this one.
+ if self.extends_so_far > 0:
+
+ # if we have a known extends we just add a template runtime
+ # error into the generated code. We could catch that at compile
+ # time too, but i welcome it not to confuse users by throwing the
+ # same error at different times just "because we can".
+ if not self.has_known_extends:
self.writeline("if parent_template is not None:")
- self.indent()
+ self.indent()
self.writeline('raise TemplateRuntimeError("extended multiple times")')
-
- # if we have a known extends already we don't need that code here
- # as we know that the template execution will end here.
- if self.has_known_extends:
- raise CompilerExit()
- else:
- self.outdent()
-
+
+ # if we have a known extends already we don't need that code here
+ # as we know that the template execution will end here.
+ if self.has_known_extends:
+ raise CompilerExit()
+ else:
+ self.outdent()
+
self.writeline("parent_template = environment.get_template(", node)
- self.visit(node.template, frame)
+ self.visit(node.template, frame)
self.write(f", {self.name!r})")
self.writeline("for name, parent_block in parent_template.blocks.items():")
- self.indent()
+ self.indent()
self.writeline("context.blocks.setdefault(name, []).append(parent_block)")
- self.outdent()
-
- # if this extends statement was in the root level we can take
- # advantage of that information and simplify the generated code
- # in the top level from this point onwards
- if frame.rootlevel:
- self.has_known_extends = True
-
- # and now we have one more
- self.extends_so_far += 1
-
+ self.outdent()
+
+ # if this extends statement was in the root level we can take
+ # advantage of that information and simplify the generated code
+ # in the top level from this point onwards
+ if frame.rootlevel:
+ self.has_known_extends = True
+
+ # and now we have one more
+ self.extends_so_far += 1
+
def visit_Include(self, node: nodes.Include, frame: Frame) -> None:
- """Handles includes."""
- if node.ignore_missing:
+ """Handles includes."""
+ if node.ignore_missing:
self.writeline("try:")
- self.indent()
-
+ self.indent()
+
func_name = "get_or_select_template"
- if isinstance(node.template, nodes.Const):
+ if isinstance(node.template, nodes.Const):
if isinstance(node.template.value, str):
func_name = "get_template"
- elif isinstance(node.template.value, (tuple, list)):
+ elif isinstance(node.template.value, (tuple, list)):
func_name = "select_template"
- elif isinstance(node.template, (nodes.Tuple, nodes.List)):
+ elif isinstance(node.template, (nodes.Tuple, nodes.List)):
func_name = "select_template"
-
+
self.writeline(f"template = environment.{func_name}(", node)
- self.visit(node.template, frame)
+ self.visit(node.template, frame)
self.write(f", {self.name!r})")
- if node.ignore_missing:
- self.outdent()
+ if node.ignore_missing:
+ self.outdent()
self.writeline("except TemplateNotFound:")
- self.indent()
+ self.indent()
self.writeline("pass")
- self.outdent()
+ self.outdent()
self.writeline("else:")
- self.indent()
-
- skip_event_yield = False
- if node.with_context:
+ self.indent()
+
+ skip_event_yield = False
+ if node.with_context:
self.writeline(
f"{self.choose_async()}for event in template.root_render_func("
"template.new_context(context.get_all(), True,"
f" {self.dump_local_context(frame)})):"
)
- elif self.environment.is_async:
+ elif self.environment.is_async:
self.writeline(
"for event in (await template._get_default_module_async())"
"._body_stream:"
)
- else:
+ else:
self.writeline("yield from template._get_default_module()._body_stream")
skip_event_yield = True
-
- if not skip_event_yield:
- self.indent()
+
+ if not skip_event_yield:
+ self.indent()
self.simple_write("event", frame)
- self.outdent()
-
- if node.ignore_missing:
- self.outdent()
-
+ self.outdent()
+
+ if node.ignore_missing:
+ self.outdent()
+
def _import_common(
self, node: t.Union[nodes.Import, nodes.FromImport], frame: Frame
) -> None:
self.write(f"{self.choose_async('await ')}environment.get_template(")
- self.visit(node.template, frame)
+ self.visit(node.template, frame)
self.write(f", {self.name!r}).")
- if node.with_context:
+ if node.with_context:
f_name = f"make_module{self.choose_async('_async')}"
self.write(
f"{f_name}(context.get_all(), True, {self.dump_local_context(frame)})"
)
- else:
+ else:
self.write(f"_get_default_module{self.choose_async('_async')}(context)")
def visit_Import(self, node: nodes.Import, frame: Frame) -> None:
@@ -1103,25 +1103,25 @@ class CodeGenerator(NodeVisitor):
if frame.toplevel and not node.target.startswith("_"):
self.writeline(f"context.exported_vars.discard({node.target!r})")
-
+
def visit_FromImport(self, node: nodes.FromImport, frame: Frame) -> None:
- """Visit named imports."""
- self.newline(node)
+ """Visit named imports."""
+ self.newline(node)
self.write("included_template = ")
self._import_common(node, frame)
- var_names = []
- discarded_names = []
- for name in node.names:
- if isinstance(name, tuple):
- name, alias = name
- else:
- alias = name
+ var_names = []
+ discarded_names = []
+ for name in node.names:
+ if isinstance(name, tuple):
+ name, alias = name
+ else:
+ alias = name
self.writeline(
f"{frame.symbols.ref(alias)} ="
f" getattr(included_template, {name!r}, missing)"
)
self.writeline(f"if {frame.symbols.ref(alias)} is missing:")
- self.indent()
+ self.indent()
message = (
"the template {included_template.__name__!r}"
f" (imported on {self.position(node)})"
@@ -1130,38 +1130,38 @@ class CodeGenerator(NodeVisitor):
self.writeline(
f"{frame.symbols.ref(alias)} = undefined(f{message!r}, name={name!r})"
)
- self.outdent()
- if frame.toplevel:
- var_names.append(alias)
+ self.outdent()
+ if frame.toplevel:
+ var_names.append(alias)
if not alias.startswith("_"):
- discarded_names.append(alias)
-
- if var_names:
- if len(var_names) == 1:
- name = var_names[0]
+ discarded_names.append(alias)
+
+ if var_names:
+ if len(var_names) == 1:
+ name = var_names[0]
self.writeline(f"context.vars[{name!r}] = {frame.symbols.ref(name)}")
- else:
+ else:
names_kv = ", ".join(
f"{name!r}: {frame.symbols.ref(name)}" for name in var_names
)
self.writeline(f"context.vars.update({{{names_kv}}})")
- if discarded_names:
- if len(discarded_names) == 1:
+ if discarded_names:
+ if len(discarded_names) == 1:
self.writeline(f"context.exported_vars.discard({discarded_names[0]!r})")
- else:
+ else:
names_str = ", ".join(map(repr, discarded_names))
self.writeline(
f"context.exported_vars.difference_update(({names_str}))"
)
-
+
def visit_For(self, node: nodes.For, frame: Frame) -> None:
- loop_frame = frame.inner()
+ loop_frame = frame.inner()
loop_frame.loop_frame = True
- test_frame = frame.inner()
- else_frame = frame.inner()
-
- # try to figure out if we have an extended loop. An extended loop
- # is necessary if the loop is in recursive mode if the special loop
+ test_frame = frame.inner()
+ else_frame = frame.inner()
+
+ # try to figure out if we have an extended loop. An extended loop
+ # is necessary if the loop is in recursive mode if the special loop
# variable is accessed in the body if the body is a scoped block.
extended_loop = (
node.recursive
@@ -1169,200 +1169,200 @@ class CodeGenerator(NodeVisitor):
in find_undeclared(node.iter_child_nodes(only=("body",)), ("loop",))
or any(block.scoped for block in node.find_all(nodes.Block))
)
-
- loop_ref = None
- if extended_loop:
+
+ loop_ref = None
+ if extended_loop:
loop_ref = loop_frame.symbols.declare_parameter("loop")
-
+
loop_frame.symbols.analyze_node(node, for_branch="body")
- if node.else_:
+ if node.else_:
else_frame.symbols.analyze_node(node, for_branch="else")
-
- if node.test:
- loop_filter_func = self.temporary_identifier()
+
+ if node.test:
+ loop_filter_func = self.temporary_identifier()
test_frame.symbols.analyze_node(node, for_branch="test")
self.writeline(f"{self.func(loop_filter_func)}(fiter):", node.test)
- self.indent()
- self.enter_frame(test_frame)
+ self.indent()
+ self.enter_frame(test_frame)
self.writeline(self.choose_async("async for ", "for "))
- self.visit(node.target, loop_frame)
+ self.visit(node.target, loop_frame)
self.write(" in ")
self.write(self.choose_async("auto_aiter(fiter)", "fiter"))
self.write(":")
- self.indent()
+ self.indent()
self.writeline("if ", node.test)
- self.visit(node.test, test_frame)
+ self.visit(node.test, test_frame)
self.write(":")
- self.indent()
+ self.indent()
self.writeline("yield ")
- self.visit(node.target, loop_frame)
- self.outdent(3)
- self.leave_frame(test_frame, with_python_scope=True)
-
- # if we don't have an recursive loop we have to find the shadowed
- # variables at that point. Because loops can be nested but the loop
- # variable is a special one we have to enforce aliasing for it.
- if node.recursive:
+ self.visit(node.target, loop_frame)
+ self.outdent(3)
+ self.leave_frame(test_frame, with_python_scope=True)
+
+ # if we don't have an recursive loop we have to find the shadowed
+ # variables at that point. Because loops can be nested but the loop
+ # variable is a special one we have to enforce aliasing for it.
+ if node.recursive:
self.writeline(
f"{self.func('loop')}(reciter, loop_render_func, depth=0):", node
)
- self.indent()
- self.buffer(loop_frame)
-
- # Use the same buffer for the else frame
- else_frame.buffer = loop_frame.buffer
-
- # make sure the loop variable is a special one and raise a template
- # assertion error if a loop tries to write to loop
- if extended_loop:
+ self.indent()
+ self.buffer(loop_frame)
+
+ # Use the same buffer for the else frame
+ else_frame.buffer = loop_frame.buffer
+
+ # make sure the loop variable is a special one and raise a template
+ # assertion error if a loop tries to write to loop
+ if extended_loop:
self.writeline(f"{loop_ref} = missing")
-
- for name in node.find_all(nodes.Name):
+
+ for name in node.find_all(nodes.Name):
if name.ctx == "store" and name.name == "loop":
self.fail(
"Can't assign to special loop variable in for-loop target",
name.lineno,
)
-
- if node.else_:
- iteration_indicator = self.temporary_identifier()
+
+ if node.else_:
+ iteration_indicator = self.temporary_identifier()
self.writeline(f"{iteration_indicator} = 1")
-
+
self.writeline(self.choose_async("async for ", "for "), node)
- self.visit(node.target, loop_frame)
- if extended_loop:
+ self.visit(node.target, loop_frame)
+ if extended_loop:
self.write(f", {loop_ref} in {self.choose_async('Async')}LoopContext(")
- else:
+ else:
self.write(" in ")
-
- if node.test:
+
+ if node.test:
self.write(f"{loop_filter_func}(")
- if node.recursive:
+ if node.recursive:
self.write("reciter")
- else:
- if self.environment.is_async and not extended_loop:
+ else:
+ if self.environment.is_async and not extended_loop:
self.write("auto_aiter(")
- self.visit(node.iter, frame)
- if self.environment.is_async and not extended_loop:
+ self.visit(node.iter, frame)
+ if self.environment.is_async and not extended_loop:
self.write(")")
- if node.test:
+ if node.test:
self.write(")")
-
- if node.recursive:
+
+ if node.recursive:
self.write(", undefined, loop_render_func, depth):")
- else:
+ else:
self.write(", undefined):" if extended_loop else ":")
-
- self.indent()
- self.enter_frame(loop_frame)
-
+
+ self.indent()
+ self.enter_frame(loop_frame)
+
self.writeline("_loop_vars = {}")
- self.blockvisit(node.body, loop_frame)
- if node.else_:
+ self.blockvisit(node.body, loop_frame)
+ if node.else_:
self.writeline(f"{iteration_indicator} = 0")
- self.outdent()
+ self.outdent()
self.leave_frame(
loop_frame, with_python_scope=node.recursive and not node.else_
)
-
- if node.else_:
+
+ if node.else_:
self.writeline(f"if {iteration_indicator}:")
- self.indent()
- self.enter_frame(else_frame)
- self.blockvisit(node.else_, else_frame)
- self.leave_frame(else_frame)
- self.outdent()
-
- # if the node was recursive we have to return the buffer contents
- # and start the iteration code
- if node.recursive:
- self.return_buffer_contents(loop_frame)
- self.outdent()
- self.start_write(frame, node)
+ self.indent()
+ self.enter_frame(else_frame)
+ self.blockvisit(node.else_, else_frame)
+ self.leave_frame(else_frame)
+ self.outdent()
+
+ # if the node was recursive we have to return the buffer contents
+ # and start the iteration code
+ if node.recursive:
+ self.return_buffer_contents(loop_frame)
+ self.outdent()
+ self.start_write(frame, node)
self.write(f"{self.choose_async('await ')}loop(")
- if self.environment.is_async:
+ if self.environment.is_async:
self.write("auto_aiter(")
- self.visit(node.iter, frame)
- if self.environment.is_async:
+ self.visit(node.iter, frame)
+ if self.environment.is_async:
self.write(")")
self.write(", loop)")
- self.end_write(frame)
-
+ self.end_write(frame)
+
# at the end of the iteration, clear any assignments made in the
# loop from the top level
if self._assign_stack:
self._assign_stack[-1].difference_update(loop_frame.symbols.stores)
def visit_If(self, node: nodes.If, frame: Frame) -> None:
- if_frame = frame.soft()
+ if_frame = frame.soft()
self.writeline("if ", node)
- self.visit(node.test, if_frame)
+ self.visit(node.test, if_frame)
self.write(":")
- self.indent()
- self.blockvisit(node.body, if_frame)
- self.outdent()
- for elif_ in node.elif_:
+ self.indent()
+ self.blockvisit(node.body, if_frame)
+ self.outdent()
+ for elif_ in node.elif_:
self.writeline("elif ", elif_)
- self.visit(elif_.test, if_frame)
+ self.visit(elif_.test, if_frame)
self.write(":")
- self.indent()
- self.blockvisit(elif_.body, if_frame)
- self.outdent()
- if node.else_:
+ self.indent()
+ self.blockvisit(elif_.body, if_frame)
+ self.outdent()
+ if node.else_:
self.writeline("else:")
- self.indent()
- self.blockvisit(node.else_, if_frame)
- self.outdent()
-
+ self.indent()
+ self.blockvisit(node.else_, if_frame)
+ self.outdent()
+
def visit_Macro(self, node: nodes.Macro, frame: Frame) -> None:
- macro_frame, macro_ref = self.macro_body(node, frame)
- self.newline()
- if frame.toplevel:
+ macro_frame, macro_ref = self.macro_body(node, frame)
+ self.newline()
+ if frame.toplevel:
if not node.name.startswith("_"):
self.write(f"context.exported_vars.add({node.name!r})")
self.writeline(f"context.vars[{node.name!r}] = ")
self.write(f"{frame.symbols.ref(node.name)} = ")
- self.macro_def(macro_ref, macro_frame)
-
+ self.macro_def(macro_ref, macro_frame)
+
def visit_CallBlock(self, node: nodes.CallBlock, frame: Frame) -> None:
- call_frame, macro_ref = self.macro_body(node, frame)
+ call_frame, macro_ref = self.macro_body(node, frame)
self.writeline("caller = ")
- self.macro_def(macro_ref, call_frame)
- self.start_write(frame, node)
- self.visit_Call(node.call, frame, forward_caller=True)
- self.end_write(frame)
-
+ self.macro_def(macro_ref, call_frame)
+ self.start_write(frame, node)
+ self.visit_Call(node.call, frame, forward_caller=True)
+ self.end_write(frame)
+
def visit_FilterBlock(self, node: nodes.FilterBlock, frame: Frame) -> None:
- filter_frame = frame.inner()
- filter_frame.symbols.analyze_node(node)
- self.enter_frame(filter_frame)
- self.buffer(filter_frame)
- self.blockvisit(node.body, filter_frame)
- self.start_write(frame, node)
- self.visit_Filter(node.filter, filter_frame)
- self.end_write(frame)
- self.leave_frame(filter_frame)
-
+ filter_frame = frame.inner()
+ filter_frame.symbols.analyze_node(node)
+ self.enter_frame(filter_frame)
+ self.buffer(filter_frame)
+ self.blockvisit(node.body, filter_frame)
+ self.start_write(frame, node)
+ self.visit_Filter(node.filter, filter_frame)
+ self.end_write(frame)
+ self.leave_frame(filter_frame)
+
def visit_With(self, node: nodes.With, frame: Frame) -> None:
- with_frame = frame.inner()
- with_frame.symbols.analyze_node(node)
- self.enter_frame(with_frame)
+ with_frame = frame.inner()
+ with_frame.symbols.analyze_node(node)
+ self.enter_frame(with_frame)
for target, expr in zip(node.targets, node.values):
- self.newline()
- self.visit(target, with_frame)
+ self.newline()
+ self.visit(target, with_frame)
self.write(" = ")
- self.visit(expr, frame)
- self.blockvisit(node.body, with_frame)
- self.leave_frame(with_frame)
-
+ self.visit(expr, frame)
+ self.blockvisit(node.body, with_frame)
+ self.leave_frame(with_frame)
+
def visit_ExprStmt(self, node: nodes.ExprStmt, frame: Frame) -> None:
- self.newline(node)
- self.visit(node.node, frame)
-
+ self.newline(node)
+ self.visit(node.node, frame)
+
class _FinalizeInfo(t.NamedTuple):
const: t.Optional[t.Callable[..., str]]
src: t.Optional[str]
-
+
@staticmethod
def _default_finalize(value: t.Any) -> t.Any:
"""The default finalize function if the environment isn't
@@ -1393,7 +1393,7 @@ class CodeGenerator(NodeVisitor):
finalize = default = self._default_finalize
src = None
- if self.environment.finalize:
+ if self.environment.finalize:
src = "environment.finalize("
env_finalize = self.environment.finalize
pass_arg = {
@@ -1459,9 +1459,9 @@ class CodeGenerator(NodeVisitor):
self.write("(escape if context.eval_ctx.autoescape else str)(")
elif frame.eval_ctx.autoescape:
self.write("escape(")
- else:
+ else:
self.write("str(")
-
+
if finalize.src is not None:
self.write(finalize.src)
@@ -1478,22 +1478,22 @@ class CodeGenerator(NodeVisitor):
def visit_Output(self, node: nodes.Output, frame: Frame) -> None:
# If an extends is active, don't render outside a block.
- if frame.require_output_check:
+ if frame.require_output_check:
# A top-level extends is known to exist at compile time.
if self.has_known_extends:
return
self.writeline("if parent_template is None:")
- self.indent()
-
+ self.indent()
+
finalize = self._make_finalize()
body: t.List[t.Union[t.List[t.Any], nodes.Expr]] = []
# Evaluate constants at compile time if possible. Each item in
# body will be either a list of static data or a node to be
# evaluated at runtime.
- for child in node.nodes:
- try:
+ for child in node.nodes:
+ try:
if not (
# If the finalize function requires runtime context,
# constants can't be evaluated at compile time.
@@ -1502,21 +1502,21 @@ class CodeGenerator(NodeVisitor):
# finalized anyway.
or isinstance(child, nodes.TemplateData)
):
- raise nodes.Impossible()
+ raise nodes.Impossible()
const = self._output_child_to_const(child, frame, finalize)
except (nodes.Impossible, Exception):
# The node was not constant and needs to be evaluated at
# runtime. Or another error was raised, which is easier
# to debug at runtime.
- body.append(child)
- continue
-
- if body and isinstance(body[-1], list):
- body[-1].append(const)
- else:
- body.append([const])
-
+ body.append(child)
+ continue
+
+ if body and isinstance(body[-1], list):
+ body[-1].append(const)
+ else:
+ body.append([const])
+
if frame.buffer is not None:
if len(body) == 1:
self.writeline(f"{frame.buffer}.append(")
@@ -1532,14 +1532,14 @@ class CodeGenerator(NodeVisitor):
if frame.buffer is None:
self.writeline("yield " + val)
- else:
+ else:
self.writeline(val + ",")
else:
if frame.buffer is None:
self.writeline("yield ", item)
- else:
+ else:
self.newline(item)
-
+
# A node to be evaluated at runtime.
self._output_child_pre(item, frame, finalize)
self.visit(item, frame)
@@ -1549,57 +1549,57 @@ class CodeGenerator(NodeVisitor):
self.write(",")
if frame.buffer is not None:
- self.outdent()
+ self.outdent()
self.writeline(")" if len(body) == 1 else "))")
-
+
if frame.require_output_check:
- self.outdent()
-
+ self.outdent()
+
def visit_Assign(self, node: nodes.Assign, frame: Frame) -> None:
- self.push_assign_tracking()
- self.newline(node)
- self.visit(node.target, frame)
+ self.push_assign_tracking()
+ self.newline(node)
+ self.visit(node.target, frame)
self.write(" = ")
- self.visit(node.node, frame)
- self.pop_assign_tracking(frame)
-
+ self.visit(node.node, frame)
+ self.pop_assign_tracking(frame)
+
def visit_AssignBlock(self, node: nodes.AssignBlock, frame: Frame) -> None:
- self.push_assign_tracking()
- block_frame = frame.inner()
- # This is a special case. Since a set block always captures we
- # will disable output checks. This way one can use set blocks
- # toplevel even in extended templates.
- block_frame.require_output_check = False
- block_frame.symbols.analyze_node(node)
- self.enter_frame(block_frame)
- self.buffer(block_frame)
- self.blockvisit(node.body, block_frame)
- self.newline(node)
- self.visit(node.target, frame)
+ self.push_assign_tracking()
+ block_frame = frame.inner()
+ # This is a special case. Since a set block always captures we
+ # will disable output checks. This way one can use set blocks
+ # toplevel even in extended templates.
+ block_frame.require_output_check = False
+ block_frame.symbols.analyze_node(node)
+ self.enter_frame(block_frame)
+ self.buffer(block_frame)
+ self.blockvisit(node.body, block_frame)
+ self.newline(node)
+ self.visit(node.target, frame)
self.write(" = (Markup if context.eval_ctx.autoescape else identity)(")
- if node.filter is not None:
- self.visit_Filter(node.filter, block_frame)
- else:
+ if node.filter is not None:
+ self.visit_Filter(node.filter, block_frame)
+ else:
self.write(f"concat({block_frame.buffer})")
self.write(")")
- self.pop_assign_tracking(frame)
- self.leave_frame(block_frame)
-
- # -- Expression Visitors
-
+ self.pop_assign_tracking(frame)
+ self.leave_frame(block_frame)
+
+ # -- Expression Visitors
+
def visit_Name(self, node: nodes.Name, frame: Frame) -> None:
if node.ctx == "store" and (
frame.toplevel or frame.loop_frame or frame.block_frame
):
- if self._assign_stack:
- self._assign_stack[-1].add(node.name)
- ref = frame.symbols.ref(node.name)
-
- # If we are looking up a variable we might have to deal with the
- # case where it's undefined. We can skip that case if the load
- # instruction indicates a parameter which are always defined.
+ if self._assign_stack:
+ self._assign_stack[-1].add(node.name)
+ ref = frame.symbols.ref(node.name)
+
+ # If we are looking up a variable we might have to deal with the
+ # case where it's undefined. We can skip that case if the load
+ # instruction indicates a parameter which are always defined.
if node.ctx == "load":
- load = frame.symbols.find_load(ref)
+ load = frame.symbols.find_load(ref)
if not (
load is not None
and load[0] == VAR_LOAD_PARAMETER
@@ -1608,66 +1608,66 @@ class CodeGenerator(NodeVisitor):
self.write(
f"(undefined(name={node.name!r}) if {ref} is missing else {ref})"
)
- return
-
- self.write(ref)
-
+ return
+
+ self.write(ref)
+
def visit_NSRef(self, node: nodes.NSRef, frame: Frame) -> None:
- # NSRefs can only be used to store values; since they use the normal
- # `foo.bar` notation they will be parsed as a normal attribute access
- # when used anywhere but in a `set` context
- ref = frame.symbols.ref(node.name)
+ # NSRefs can only be used to store values; since they use the normal
+ # `foo.bar` notation they will be parsed as a normal attribute access
+ # when used anywhere but in a `set` context
+ ref = frame.symbols.ref(node.name)
self.writeline(f"if not isinstance({ref}, Namespace):")
- self.indent()
+ self.indent()
self.writeline(
"raise TemplateRuntimeError"
'("cannot assign attribute on non-namespace object")'
)
- self.outdent()
+ self.outdent()
self.writeline(f"{ref}[{node.attr!r}]")
-
+
def visit_Const(self, node: nodes.Const, frame: Frame) -> None:
- val = node.as_const(frame.eval_ctx)
- if isinstance(val, float):
- self.write(str(val))
- else:
- self.write(repr(val))
-
+ val = node.as_const(frame.eval_ctx)
+ if isinstance(val, float):
+ self.write(str(val))
+ else:
+ self.write(repr(val))
+
def visit_TemplateData(self, node: nodes.TemplateData, frame: Frame) -> None:
- try:
- self.write(repr(node.as_const(frame.eval_ctx)))
- except nodes.Impossible:
+ try:
+ self.write(repr(node.as_const(frame.eval_ctx)))
+ except nodes.Impossible:
self.write(
f"(Markup if context.eval_ctx.autoescape else identity)({node.data!r})"
)
-
+
def visit_Tuple(self, node: nodes.Tuple, frame: Frame) -> None:
self.write("(")
- idx = -1
- for idx, item in enumerate(node.items):
- if idx:
+ idx = -1
+ for idx, item in enumerate(node.items):
+ if idx:
self.write(", ")
- self.visit(item, frame)
+ self.visit(item, frame)
self.write(",)" if idx == 0 else ")")
-
+
def visit_List(self, node: nodes.List, frame: Frame) -> None:
self.write("[")
- for idx, item in enumerate(node.items):
- if idx:
+ for idx, item in enumerate(node.items):
+ if idx:
self.write(", ")
- self.visit(item, frame)
+ self.visit(item, frame)
self.write("]")
-
+
def visit_Dict(self, node: nodes.Dict, frame: Frame) -> None:
self.write("{")
- for idx, item in enumerate(node.items):
- if idx:
+ for idx, item in enumerate(node.items):
+ if idx:
self.write(", ")
- self.visit(item.key, frame)
+ self.visit(item.key, frame)
self.write(": ")
- self.visit(item.value, frame)
+ self.visit(item.value, frame)
self.write("}")
-
+
visit_Add = _make_binop("+")
visit_Sub = _make_binop("-")
visit_Mul = _make_binop("*")
@@ -1681,86 +1681,86 @@ class CodeGenerator(NodeVisitor):
visit_Neg = _make_unop("-")
visit_Not = _make_unop("not ")
- @optimizeconst
+ @optimizeconst
def visit_Concat(self, node: nodes.Concat, frame: Frame) -> None:
- if frame.eval_ctx.volatile:
+ if frame.eval_ctx.volatile:
func_name = "(markup_join if context.eval_ctx.volatile else str_join)"
- elif frame.eval_ctx.autoescape:
+ elif frame.eval_ctx.autoescape:
func_name = "markup_join"
- else:
+ else:
func_name = "str_join"
self.write(f"{func_name}((")
- for arg in node.nodes:
- self.visit(arg, frame)
+ for arg in node.nodes:
+ self.visit(arg, frame)
self.write(", ")
self.write("))")
-
- @optimizeconst
+
+ @optimizeconst
def visit_Compare(self, node: nodes.Compare, frame: Frame) -> None:
self.write("(")
- self.visit(node.expr, frame)
- for op in node.ops:
- self.visit(op, frame)
+ self.visit(node.expr, frame)
+ for op in node.ops:
+ self.visit(op, frame)
self.write(")")
-
+
def visit_Operand(self, node: nodes.Operand, frame: Frame) -> None:
self.write(f" {operators[node.op]} ")
- self.visit(node.expr, frame)
-
- @optimizeconst
+ self.visit(node.expr, frame)
+
+ @optimizeconst
def visit_Getattr(self, node: nodes.Getattr, frame: Frame) -> None:
if self.environment.is_async:
self.write("(await auto_await(")
self.write("environment.getattr(")
- self.visit(node.node, frame)
+ self.visit(node.node, frame)
self.write(f", {node.attr!r})")
-
+
if self.environment.is_async:
self.write("))")
- @optimizeconst
+ @optimizeconst
def visit_Getitem(self, node: nodes.Getitem, frame: Frame) -> None:
- # slices bypass the environment getitem method.
- if isinstance(node.arg, nodes.Slice):
- self.visit(node.node, frame)
+ # slices bypass the environment getitem method.
+ if isinstance(node.arg, nodes.Slice):
+ self.visit(node.node, frame)
self.write("[")
- self.visit(node.arg, frame)
+ self.visit(node.arg, frame)
self.write("]")
- else:
+ else:
if self.environment.is_async:
self.write("(await auto_await(")
self.write("environment.getitem(")
- self.visit(node.node, frame)
+ self.visit(node.node, frame)
self.write(", ")
- self.visit(node.arg, frame)
+ self.visit(node.arg, frame)
self.write(")")
-
+
if self.environment.is_async:
self.write("))")
def visit_Slice(self, node: nodes.Slice, frame: Frame) -> None:
- if node.start is not None:
- self.visit(node.start, frame)
+ if node.start is not None:
+ self.visit(node.start, frame)
self.write(":")
- if node.stop is not None:
- self.visit(node.stop, frame)
- if node.step is not None:
+ if node.stop is not None:
+ self.visit(node.stop, frame)
+ if node.step is not None:
self.write(":")
- self.visit(node.step, frame)
-
+ self.visit(node.step, frame)
+
@contextmanager
def _filter_test_common(
self, node: t.Union[nodes.Filter, nodes.Test], frame: Frame, is_filter: bool
) -> t.Iterator[None]:
- if self.environment.is_async:
+ if self.environment.is_async:
self.write("await auto_await(")
-
+
if is_filter:
self.write(f"{self.filters[node.name]}(")
func = self.environment.filters.get(node.name)
- else:
+ else:
self.write(f"{self.tests[node.name]}(")
func = self.environment.tests.get(node.name)
@@ -1786,13 +1786,13 @@ class CodeGenerator(NodeVisitor):
# the filter or test.
yield
- self.signature(node, frame)
+ self.signature(node, frame)
self.write(")")
- if self.environment.is_async:
+ if self.environment.is_async:
self.write(")")
-
- @optimizeconst
+
+ @optimizeconst
def visit_Filter(self, node: nodes.Filter, frame: Frame) -> None:
with self._filter_test_common(node, frame, True):
# if the filter node is None we are inside a filter block
@@ -1808,8 +1808,8 @@ class CodeGenerator(NodeVisitor):
self.write(f"Markup(concat({frame.buffer}))")
else:
self.write(f"concat({frame.buffer})")
-
- @optimizeconst
+
+ @optimizeconst
def visit_Test(self, node: nodes.Test, frame: Frame) -> None:
with self._filter_test_common(node, frame, False):
self.visit(node.node, frame)
@@ -1819,7 +1819,7 @@ class CodeGenerator(NodeVisitor):
frame = frame.soft()
def write_expr2() -> None:
- if node.expr2 is not None:
+ if node.expr2 is not None:
self.visit(node.expr2, frame)
return
@@ -1828,26 +1828,26 @@ class CodeGenerator(NodeVisitor):
f" {self.position(node)} evaluated to false and no else"
f' section was defined.")'
)
-
+
self.write("(")
- self.visit(node.expr1, frame)
+ self.visit(node.expr1, frame)
self.write(" if ")
- self.visit(node.test, frame)
+ self.visit(node.test, frame)
self.write(" else ")
- write_expr2()
+ write_expr2()
self.write(")")
-
- @optimizeconst
+
+ @optimizeconst
def visit_Call(
self, node: nodes.Call, frame: Frame, forward_caller: bool = False
) -> None:
- if self.environment.is_async:
+ if self.environment.is_async:
self.write("await auto_await(")
- if self.environment.sandboxed:
+ if self.environment.sandboxed:
self.write("environment.call(context, ")
- else:
+ else:
self.write("context.call(")
- self.visit(node.node, frame)
+ self.visit(node.node, frame)
extra_kwargs = {"caller": "caller"} if forward_caller else None
loop_kwargs = {"_loop_vars": "_loop_vars"} if frame.loop_frame else {}
block_kwargs = {"_block_vars": "_block_vars"} if frame.block_frame else {}
@@ -1855,50 +1855,50 @@ class CodeGenerator(NodeVisitor):
extra_kwargs.update(loop_kwargs, **block_kwargs)
elif loop_kwargs or block_kwargs:
extra_kwargs = dict(loop_kwargs, **block_kwargs)
- self.signature(node, frame, extra_kwargs)
+ self.signature(node, frame, extra_kwargs)
self.write(")")
- if self.environment.is_async:
+ if self.environment.is_async:
self.write(")")
-
+
def visit_Keyword(self, node: nodes.Keyword, frame: Frame) -> None:
self.write(node.key + "=")
- self.visit(node.value, frame)
-
- # -- Unused nodes for extensions
-
+ self.visit(node.value, frame)
+
+ # -- Unused nodes for extensions
+
def visit_MarkSafe(self, node: nodes.MarkSafe, frame: Frame) -> None:
self.write("Markup(")
- self.visit(node.expr, frame)
+ self.visit(node.expr, frame)
self.write(")")
-
+
def visit_MarkSafeIfAutoescape(
self, node: nodes.MarkSafeIfAutoescape, frame: Frame
) -> None:
self.write("(Markup if context.eval_ctx.autoescape else identity)(")
- self.visit(node.expr, frame)
+ self.visit(node.expr, frame)
self.write(")")
-
+
def visit_EnvironmentAttribute(
self, node: nodes.EnvironmentAttribute, frame: Frame
) -> None:
self.write("environment." + node.name)
-
+
def visit_ExtensionAttribute(
self, node: nodes.ExtensionAttribute, frame: Frame
) -> None:
self.write(f"environment.extensions[{node.identifier!r}].{node.name}")
-
+
def visit_ImportedName(self, node: nodes.ImportedName, frame: Frame) -> None:
- self.write(self.import_aliases[node.importname])
-
+ self.write(self.import_aliases[node.importname])
+
def visit_InternalName(self, node: nodes.InternalName, frame: Frame) -> None:
- self.write(node.name)
-
+ self.write(node.name)
+
def visit_ContextReference(
self, node: nodes.ContextReference, frame: Frame
) -> None:
self.write("context")
-
+
def visit_DerivedContextReference(
self, node: nodes.DerivedContextReference, frame: Frame
) -> None:
@@ -1906,52 +1906,52 @@ class CodeGenerator(NodeVisitor):
def visit_Continue(self, node: nodes.Continue, frame: Frame) -> None:
self.writeline("continue", node)
-
+
def visit_Break(self, node: nodes.Break, frame: Frame) -> None:
self.writeline("break", node)
-
+
def visit_Scope(self, node: nodes.Scope, frame: Frame) -> None:
- scope_frame = frame.inner()
- scope_frame.symbols.analyze_node(node)
- self.enter_frame(scope_frame)
- self.blockvisit(node.body, scope_frame)
- self.leave_frame(scope_frame)
-
+ scope_frame = frame.inner()
+ scope_frame.symbols.analyze_node(node)
+ self.enter_frame(scope_frame)
+ self.blockvisit(node.body, scope_frame)
+ self.leave_frame(scope_frame)
+
def visit_OverlayScope(self, node: nodes.OverlayScope, frame: Frame) -> None:
- ctx = self.temporary_identifier()
+ ctx = self.temporary_identifier()
self.writeline(f"{ctx} = {self.derive_context(frame)}")
self.writeline(f"{ctx}.vars = ")
- self.visit(node.context, frame)
- self.push_context_reference(ctx)
-
- scope_frame = frame.inner(isolated=True)
- scope_frame.symbols.analyze_node(node)
- self.enter_frame(scope_frame)
- self.blockvisit(node.body, scope_frame)
- self.leave_frame(scope_frame)
- self.pop_context_reference()
-
+ self.visit(node.context, frame)
+ self.push_context_reference(ctx)
+
+ scope_frame = frame.inner(isolated=True)
+ scope_frame.symbols.analyze_node(node)
+ self.enter_frame(scope_frame)
+ self.blockvisit(node.body, scope_frame)
+ self.leave_frame(scope_frame)
+ self.pop_context_reference()
+
def visit_EvalContextModifier(
self, node: nodes.EvalContextModifier, frame: Frame
) -> None:
- for keyword in node.options:
+ for keyword in node.options:
self.writeline(f"context.eval_ctx.{keyword.key} = ")
- self.visit(keyword.value, frame)
- try:
- val = keyword.value.as_const(frame.eval_ctx)
- except nodes.Impossible:
- frame.eval_ctx.volatile = True
- else:
- setattr(frame.eval_ctx, keyword.key, val)
-
+ self.visit(keyword.value, frame)
+ try:
+ val = keyword.value.as_const(frame.eval_ctx)
+ except nodes.Impossible:
+ frame.eval_ctx.volatile = True
+ else:
+ setattr(frame.eval_ctx, keyword.key, val)
+
def visit_ScopedEvalContextModifier(
self, node: nodes.ScopedEvalContextModifier, frame: Frame
) -> None:
- old_ctx_name = self.temporary_identifier()
- saved_ctx = frame.eval_ctx.save()
+ old_ctx_name = self.temporary_identifier()
+ saved_ctx = frame.eval_ctx.save()
self.writeline(f"{old_ctx_name} = context.eval_ctx.save()")
- self.visit_EvalContextModifier(node, frame)
- for child in node.body:
- self.visit(child, frame)
- frame.eval_ctx.revert(saved_ctx)
+ self.visit_EvalContextModifier(node, frame)
+ for child in node.body:
+ self.visit(child, frame)
+ frame.eval_ctx.revert(saved_ctx)
self.writeline(f"context.eval_ctx.revert({old_ctx_name})")
diff --git a/contrib/python/Jinja2/py3/jinja2/constants.py b/contrib/python/Jinja2/py3/jinja2/constants.py
index 41a1c23b0a..1ab21dd812 100644
--- a/contrib/python/Jinja2/py3/jinja2/constants.py
+++ b/contrib/python/Jinja2/py3/jinja2/constants.py
@@ -1,20 +1,20 @@
-#: list of lorem ipsum words used by the lipsum() helper function
+#: list of lorem ipsum words used by the lipsum() helper function
LOREM_IPSUM_WORDS = """\
-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
-diam dictum dictumst dignissim dis dolor donec dui duis egestas eget eleifend
-elementum elit enim erat eros est et etiam eu euismod facilisi facilisis fames
-faucibus felis fermentum feugiat fringilla fusce gravida habitant habitasse hac
-hendrerit hymenaeos iaculis id imperdiet in inceptos integer interdum ipsum
-justo lacinia lacus laoreet lectus leo libero ligula litora lobortis lorem
-luctus maecenas magna magnis malesuada massa mattis mauris metus mi molestie
-mollis montes morbi mus nam nascetur natoque nec neque netus nibh nisi nisl non
-nonummy nostra nulla nullam nunc odio orci ornare parturient pede pellentesque
-penatibus per pharetra phasellus placerat platea porta porttitor posuere
-potenti praesent pretium primis proin pulvinar purus quam quis quisque rhoncus
-ridiculus risus rutrum sagittis sapien scelerisque sed sem semper senectus sit
-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
+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
+diam dictum dictumst dignissim dis dolor donec dui duis egestas eget eleifend
+elementum elit enim erat eros est et etiam eu euismod facilisi facilisis fames
+faucibus felis fermentum feugiat fringilla fusce gravida habitant habitasse hac
+hendrerit hymenaeos iaculis id imperdiet in inceptos integer interdum ipsum
+justo lacinia lacus laoreet lectus leo libero ligula litora lobortis lorem
+luctus maecenas magna magnis malesuada massa mattis mauris metus mi molestie
+mollis montes morbi mus nam nascetur natoque nec neque netus nibh nisi nisl non
+nonummy nostra nulla nullam nunc odio orci ornare parturient pede pellentesque
+penatibus per pharetra phasellus placerat platea porta porttitor posuere
+potenti praesent pretium primis proin pulvinar purus quam quis quisque rhoncus
+ridiculus risus rutrum sagittis sapien scelerisque sed sem semper senectus sit
+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"""
diff --git a/contrib/python/Jinja2/py3/jinja2/debug.py b/contrib/python/Jinja2/py3/jinja2/debug.py
index 805866bd6f..ecd9257fa8 100644
--- a/contrib/python/Jinja2/py3/jinja2/debug.py
+++ b/contrib/python/Jinja2/py3/jinja2/debug.py
@@ -1,24 +1,24 @@
import platform
-import sys
+import sys
import typing as t
from types import CodeType
from types import TracebackType
-
+
from .exceptions import TemplateSyntaxError
from .utils import internal_code
from .utils import missing
-
+
if t.TYPE_CHECKING:
from .runtime import Context
-
+
def rewrite_traceback_stack(source: t.Optional[str] = None) -> BaseException:
"""Rewrite the current exception to replace any tracebacks from
within compiled template code with tracebacks that look like they
came from the template source.
-
+
This must be called within an ``except`` block.
-
+
:param source: For ``TemplateSyntaxError``, the original source if
known.
:return: The original exception with the rewritten traceback.
@@ -26,7 +26,7 @@ def rewrite_traceback_stack(source: t.Optional[str] = None) -> BaseException:
_, exc_value, tb = sys.exc_info()
exc_value = t.cast(BaseException, exc_value)
tb = t.cast(TracebackType, tb)
-
+
if isinstance(exc_value, TemplateSyntaxError) and not exc_value.translated:
exc_value.translated = True
exc_value.source = source
@@ -41,9 +41,9 @@ def rewrite_traceback_stack(source: t.Optional[str] = None) -> BaseException:
else:
# Skip the frame for the render function.
tb = tb.tb_next
-
+
stack = []
-
+
# Build the stack of traceback object, replacing any in template
# code with the source file and line information.
while tb is not None:
@@ -52,27 +52,27 @@ def rewrite_traceback_stack(source: t.Optional[str] = None) -> BaseException:
if tb.tb_frame.f_code in internal_code:
tb = tb.tb_next
continue
-
+
template = tb.tb_frame.f_globals.get("__jinja_template__")
-
+
if template is not None:
lineno = template.get_corresponding_lineno(tb.tb_lineno)
fake_tb = fake_traceback(exc_value, tb, template.filename, lineno)
stack.append(fake_tb)
- else:
+ else:
stack.append(tb)
-
+
tb = tb.tb_next
-
+
tb_next = None
-
+
# Assign tb_next in reverse to avoid circular references.
for tb in reversed(stack):
tb_next = tb_set_next(tb, tb_next)
-
+
return exc_value.with_traceback(tb_next)
-
-
+
+
def fake_traceback( # type: ignore
exc_value: BaseException, tb: t.Optional[TracebackType], filename: str, lineno: int
) -> TracebackType:
@@ -80,7 +80,7 @@ def fake_traceback( # type: ignore
template source instead of the compiled code. The filename, line
number, and location name will point to the template, and the local
variables will be the current template context.
-
+
:param exc_value: The original exception to be re-raised to create
the new traceback.
:param tb: The original traceback to get the local variables and
@@ -93,9 +93,9 @@ def fake_traceback( # type: ignore
# available at that point in the template.
locals = get_template_locals(tb.tb_frame.f_locals)
locals.pop("__jinja_exception__", None)
- else:
+ else:
locals = {}
-
+
globals = {
"__name__": filename,
"__file__": filename,
@@ -105,19 +105,19 @@ def fake_traceback( # type: ignore
code: CodeType = compile(
"\n" * (lineno - 1) + "raise __jinja_exception__", filename, "exec"
)
-
+
# Build a new code object that points to the template file and
# replaces the location with a block name.
location = "template"
-
+
if tb is not None:
function = tb.tb_frame.f_code.co_name
-
+
if function == "root":
location = "top-level template code"
elif function.startswith("block_"):
location = f"block {function[6:]!r}"
-
+
if sys.version_info >= (3, 8):
code = code.replace(co_name=location)
else:
@@ -138,59 +138,59 @@ def fake_traceback( # type: ignore
code.co_freevars,
code.co_cellvars,
)
-
+
# Execute the new code, which is guaranteed to raise, and return
# the new traceback without this frame.
try:
exec(code, globals, locals)
except BaseException:
return sys.exc_info()[2].tb_next # type: ignore
-
-
+
+
def get_template_locals(real_locals: t.Mapping[str, t.Any]) -> t.Dict[str, t.Any]:
"""Based on the runtime locals, get the context that would be
available at that point in the template.
"""
# Start with the current template context.
ctx: "t.Optional[Context]" = real_locals.get("context")
-
+
if ctx is not None:
data: t.Dict[str, t.Any] = ctx.get_all().copy()
- else:
+ else:
data = {}
-
+
# Might be in a derived context that only sets local variables
# rather than pushing a context. Local variables follow the scheme
# l_depth_name. Find the highest-depth local that has a value for
# each name.
local_overrides: t.Dict[str, t.Tuple[int, t.Any]] = {}
-
+
for name, value in real_locals.items():
if not name.startswith("l_") or value is missing:
# Not a template variable, or no longer relevant.
- continue
+ continue
- try:
+ try:
_, depth_str, name = name.split("_", 2)
depth = int(depth_str)
- except ValueError:
- continue
-
- cur_depth = local_overrides.get(name, (-1,))[0]
+ except ValueError:
+ continue
- if cur_depth < depth:
- local_overrides[name] = (depth, value)
+ cur_depth = local_overrides.get(name, (-1,))[0]
+ if cur_depth < depth:
+ local_overrides[name] = (depth, value)
+
# Modify the context with any derived context.
for name, (_, value) in local_overrides.items():
- if value is missing:
+ if value is missing:
data.pop(name, None)
- else:
+ else:
data[name] = value
-
+
return data
-
-
+
+
if sys.version_info >= (3, 7):
# tb_next is directly assignable as of Python 3.7
def tb_set_next(
@@ -198,11 +198,11 @@ if sys.version_info >= (3, 7):
) -> TracebackType:
tb.tb_next = tb_next
return tb
-
-
+
+
elif platform.python_implementation() == "PyPy":
# PyPy might have special support, and won't work with ctypes.
- try:
+ try:
import tputil # type: ignore
except ImportError:
# Without tproxy support, use the original traceback.
@@ -210,7 +210,7 @@ elif platform.python_implementation() == "PyPy":
tb: TracebackType, tb_next: t.Optional[TracebackType]
) -> TracebackType:
return tb
-
+
else:
# With tproxy support, create a proxy around the traceback that
# returns the new tb_next.
@@ -220,40 +220,40 @@ elif platform.python_implementation() == "PyPy":
def controller(op): # type: ignore
if op.opname == "__getattribute__" and op.args[0] == "tb_next":
return tb_next
-
+
return op.delegate()
-
+
return tputil.make_proxy(controller, obj=tb) # type: ignore
-
-
+
+
else:
# Use ctypes to assign tb_next at the C level since it's read-only
# from Python.
- import ctypes
-
+ import ctypes
+
class _CTraceback(ctypes.Structure):
_fields_ = [
# Extra PyObject slots when compiled with Py_TRACE_REFS.
("PyObject_HEAD", ctypes.c_byte * object().__sizeof__()),
# Only care about tb_next as an object, not a traceback.
("tb_next", ctypes.py_object),
- ]
-
+ ]
+
def tb_set_next(
tb: TracebackType, tb_next: t.Optional[TracebackType]
) -> TracebackType:
c_tb = _CTraceback.from_address(id(tb))
-
+
# Clear out the old tb_next.
- if tb.tb_next is not None:
+ if tb.tb_next is not None:
c_tb_next = ctypes.py_object(tb.tb_next)
c_tb.tb_next = ctypes.py_object()
ctypes.pythonapi.Py_DecRef(c_tb_next)
-
+
# Assign the new tb_next.
if tb_next is not None:
c_tb_next = ctypes.py_object(tb_next)
ctypes.pythonapi.Py_IncRef(c_tb_next)
c_tb.tb_next = c_tb_next
-
+
return tb
diff --git a/contrib/python/Jinja2/py3/jinja2/defaults.py b/contrib/python/Jinja2/py3/jinja2/defaults.py
index 638cad3d2d..acfe872c2a 100644
--- a/contrib/python/Jinja2/py3/jinja2/defaults.py
+++ b/contrib/python/Jinja2/py3/jinja2/defaults.py
@@ -6,11 +6,11 @@ from .utils import Cycler
from .utils import generate_lorem_ipsum
from .utils import Joiner
from .utils import Namespace
-
+
if t.TYPE_CHECKING:
import typing_extensions as te
-# defaults for the parser / lexer
+# defaults for the parser / lexer
BLOCK_START_STRING = "{%"
BLOCK_END_STRING = "%}"
VARIABLE_START_STRING = "{{"
@@ -19,23 +19,23 @@ COMMENT_START_STRING = "{#"
COMMENT_END_STRING = "#}"
LINE_STATEMENT_PREFIX: t.Optional[str] = None
LINE_COMMENT_PREFIX: t.Optional[str] = None
-TRIM_BLOCKS = False
-LSTRIP_BLOCKS = False
+TRIM_BLOCKS = False
+LSTRIP_BLOCKS = False
NEWLINE_SEQUENCE: "te.Literal['\\n', '\\r\\n', '\\r']" = "\n"
-KEEP_TRAILING_NEWLINE = False
-
+KEEP_TRAILING_NEWLINE = False
+
# default filters, tests and namespace
-
-DEFAULT_NAMESPACE = {
+
+DEFAULT_NAMESPACE = {
"range": range,
"dict": dict,
"lipsum": generate_lorem_ipsum,
"cycler": Cycler,
"joiner": Joiner,
"namespace": Namespace,
-}
-
-# default policies
+}
+
+# default policies
DEFAULT_POLICIES: t.Dict[str, t.Any] = {
"compiler.ascii_str": True,
"urlize.rel": "noopener",
@@ -45,4 +45,4 @@ DEFAULT_POLICIES: t.Dict[str, t.Any] = {
"json.dumps_function": None,
"json.dumps_kwargs": {"sort_keys": True},
"ext.i18n.trimmed": False,
-}
+}
diff --git a/contrib/python/Jinja2/py3/jinja2/environment.py b/contrib/python/Jinja2/py3/jinja2/environment.py
index a231d9cd57..af6b6d9705 100644
--- a/contrib/python/Jinja2/py3/jinja2/environment.py
+++ b/contrib/python/Jinja2/py3/jinja2/environment.py
@@ -1,19 +1,19 @@
"""Classes for managing templates and their runtime and compile time
options.
-"""
-import os
-import sys
+"""
+import os
+import sys
import typing
import typing as t
-import weakref
+import weakref
from collections import ChainMap
from functools import lru_cache
from functools import partial
from functools import reduce
from types import CodeType
-
+
from markupsafe import Markup
-
+
from . import nodes
from .compiler import CodeGenerator
from .compiler import generate
@@ -59,9 +59,9 @@ if t.TYPE_CHECKING:
from .bccache import BytecodeCache
from .ext import Extension
from .loaders import BaseLoader
-
+
_env_bound = t.TypeVar("_env_bound", bound="Environment")
-
+
# for direct template usage we have up to ten living environments
@lru_cache(maxsize=10)
@@ -69,61 +69,61 @@ def get_spontaneous_environment(cls: t.Type[_env_bound], *args: t.Any) -> _env_b
"""Return a new spontaneous environment. A spontaneous environment
is used for templates created directly rather than through an
existing environment.
-
+
:param cls: Environment class to create.
:param args: Positional arguments passed to environment.
- """
+ """
env = cls(*args)
env.shared = True
return env
-
+
def create_cache(
size: int,
) -> t.Optional[t.MutableMapping[t.Tuple[weakref.ref, str], "Template"]]:
- """Return the cache class for the given size."""
- if size == 0:
- return None
-
- if size < 0:
- return {}
+ """Return the cache class for the given size."""
+ if size == 0:
+ return None
+ if size < 0:
+ return {}
+
return LRUCache(size) # type: ignore
-
+
def copy_cache(
cache: t.Optional[t.MutableMapping],
) -> t.Optional[t.MutableMapping[t.Tuple[weakref.ref, str], "Template"]]:
- """Create an empty copy of the given cache."""
- if cache is None:
- return None
+ """Create an empty copy of the given cache."""
+ if cache is None:
+ return None
if type(cache) is dict:
- return {}
-
+ return {}
+
return LRUCache(cache.capacity) # type: ignore
-
+
def load_extensions(
environment: "Environment",
extensions: t.Sequence[t.Union[str, t.Type["Extension"]]],
) -> t.Dict[str, "Extension"]:
- """Load the extensions from the list and bind it to the environment.
+ """Load the extensions from the list and bind it to the environment.
Returns a dict of instantiated extensions.
- """
- result = {}
+ """
+ result = {}
- for extension in extensions:
+ for extension in extensions:
if isinstance(extension, str):
extension = t.cast(t.Type["Extension"], import_string(extension))
- result[extension.identifier] = extension(environment)
-
- return result
-
+ result[extension.identifier] = extension(environment)
+ return result
+
+
def _environment_config_check(environment: "Environment") -> "Environment":
- """Perform a sanity check on the environment."""
+ """Perform a sanity check on the environment."""
assert issubclass(
environment.undefined, Undefined
), "'undefined' must be a subclass of 'jinja2.Undefined'."
@@ -137,155 +137,155 @@ def _environment_config_check(environment: "Environment") -> "Environment":
"\r\n",
"\n",
}, "'newline_sequence' must be one of '\\n', '\\r\\n', or '\\r'."
- return environment
-
-
+ return environment
+
+
class Environment:
- r"""The core component of Jinja is the `Environment`. It contains
- important shared variables like configuration, filters, tests,
- globals and others. Instances of this class may be modified if
- they are not shared and if no template was loaded so far.
- Modifications on environments after the first template was loaded
- will lead to surprising effects and undefined behavior.
-
- Here are the possible initialization parameters:
-
- `block_start_string`
- The string marking the beginning of a block. Defaults to ``'{%'``.
-
- `block_end_string`
- The string marking the end of a block. Defaults to ``'%}'``.
-
- `variable_start_string`
- The string marking the beginning of a print statement.
- Defaults to ``'{{'``.
-
- `variable_end_string`
- The string marking the end of a print statement. Defaults to
- ``'}}'``.
-
- `comment_start_string`
- The string marking the beginning of a comment. Defaults to ``'{#'``.
-
- `comment_end_string`
- The string marking the end of a comment. Defaults to ``'#}'``.
-
- `line_statement_prefix`
- If given and a string, this will be used as prefix for line based
- statements. See also :ref:`line-statements`.
-
- `line_comment_prefix`
- If given and a string, this will be used as prefix for line based
- comments. See also :ref:`line-statements`.
-
- .. versionadded:: 2.2
-
- `trim_blocks`
- If this is set to ``True`` the first newline after a block is
- removed (block, not variable tag!). Defaults to `False`.
-
- `lstrip_blocks`
- If this is set to ``True`` leading spaces and tabs are stripped
- from the start of a line to a block. Defaults to `False`.
-
- `newline_sequence`
- The sequence that starts a newline. Must be one of ``'\r'``,
- ``'\n'`` or ``'\r\n'``. The default is ``'\n'`` which is a
- useful default for Linux and OS X systems as well as web
- applications.
-
- `keep_trailing_newline`
- Preserve the trailing newline when rendering templates.
- The default is ``False``, which causes a single newline,
- if present, to be stripped from the end of the template.
-
- .. versionadded:: 2.7
-
- `extensions`
- List of Jinja extensions to use. This can either be import paths
- as strings or extension classes. For more information have a
- look at :ref:`the extensions documentation <jinja-extensions>`.
-
- `optimized`
- should the optimizer be enabled? Default is ``True``.
-
- `undefined`
- :class:`Undefined` or a subclass of it that is used to represent
- undefined values in the template.
-
- `finalize`
- A callable that can be used to process the result of a variable
- expression before it is output. For example one can convert
- ``None`` implicitly into an empty string here.
-
- `autoescape`
- If set to ``True`` the XML/HTML autoescaping feature is enabled by
- default. For more details about autoescaping see
+ r"""The core component of Jinja is the `Environment`. It contains
+ important shared variables like configuration, filters, tests,
+ globals and others. Instances of this class may be modified if
+ they are not shared and if no template was loaded so far.
+ Modifications on environments after the first template was loaded
+ will lead to surprising effects and undefined behavior.
+
+ Here are the possible initialization parameters:
+
+ `block_start_string`
+ The string marking the beginning of a block. Defaults to ``'{%'``.
+
+ `block_end_string`
+ The string marking the end of a block. Defaults to ``'%}'``.
+
+ `variable_start_string`
+ The string marking the beginning of a print statement.
+ Defaults to ``'{{'``.
+
+ `variable_end_string`
+ The string marking the end of a print statement. Defaults to
+ ``'}}'``.
+
+ `comment_start_string`
+ The string marking the beginning of a comment. Defaults to ``'{#'``.
+
+ `comment_end_string`
+ The string marking the end of a comment. Defaults to ``'#}'``.
+
+ `line_statement_prefix`
+ If given and a string, this will be used as prefix for line based
+ statements. See also :ref:`line-statements`.
+
+ `line_comment_prefix`
+ If given and a string, this will be used as prefix for line based
+ comments. See also :ref:`line-statements`.
+
+ .. versionadded:: 2.2
+
+ `trim_blocks`
+ If this is set to ``True`` the first newline after a block is
+ removed (block, not variable tag!). Defaults to `False`.
+
+ `lstrip_blocks`
+ If this is set to ``True`` leading spaces and tabs are stripped
+ from the start of a line to a block. Defaults to `False`.
+
+ `newline_sequence`
+ The sequence that starts a newline. Must be one of ``'\r'``,
+ ``'\n'`` or ``'\r\n'``. The default is ``'\n'`` which is a
+ useful default for Linux and OS X systems as well as web
+ applications.
+
+ `keep_trailing_newline`
+ Preserve the trailing newline when rendering templates.
+ The default is ``False``, which causes a single newline,
+ if present, to be stripped from the end of the template.
+
+ .. versionadded:: 2.7
+
+ `extensions`
+ List of Jinja extensions to use. This can either be import paths
+ as strings or extension classes. For more information have a
+ look at :ref:`the extensions documentation <jinja-extensions>`.
+
+ `optimized`
+ should the optimizer be enabled? Default is ``True``.
+
+ `undefined`
+ :class:`Undefined` or a subclass of it that is used to represent
+ undefined values in the template.
+
+ `finalize`
+ A callable that can be used to process the result of a variable
+ expression before it is output. For example one can convert
+ ``None`` implicitly into an empty string here.
+
+ `autoescape`
+ If set to ``True`` the XML/HTML autoescaping feature is enabled by
+ default. For more details about autoescaping see
:class:`~markupsafe.Markup`. As of Jinja 2.4 this can also
- be a callable that is passed the template name and has to
- return ``True`` or ``False`` depending on autoescape should be
- enabled by default.
-
- .. versionchanged:: 2.4
- `autoescape` can now be a function
-
- `loader`
- The template loader for this environment.
-
- `cache_size`
- The size of the cache. Per default this is ``400`` which means
- that if more than 400 templates are loaded the loader will clean
- out the least recently used template. If the cache size is set to
- ``0`` templates are recompiled all the time, if the cache size is
- ``-1`` the cache will not be cleaned.
-
- .. versionchanged:: 2.8
- The cache size was increased to 400 from a low 50.
-
- `auto_reload`
- Some loaders load templates from locations where the template
- sources may change (ie: file system or database). If
- ``auto_reload`` is set to ``True`` (default) every time a template is
- requested the loader checks if the source changed and if yes, it
- will reload the template. For higher performance it's possible to
- disable that.
-
- `bytecode_cache`
- If set to a bytecode cache object, this object will provide a
- cache for the internal Jinja bytecode so that templates don't
- have to be parsed if they were not changed.
-
- See :ref:`bytecode-cache` for more information.
-
- `enable_async`
+ be a callable that is passed the template name and has to
+ return ``True`` or ``False`` depending on autoescape should be
+ enabled by default.
+
+ .. versionchanged:: 2.4
+ `autoescape` can now be a function
+
+ `loader`
+ The template loader for this environment.
+
+ `cache_size`
+ The size of the cache. Per default this is ``400`` which means
+ that if more than 400 templates are loaded the loader will clean
+ out the least recently used template. If the cache size is set to
+ ``0`` templates are recompiled all the time, if the cache size is
+ ``-1`` the cache will not be cleaned.
+
+ .. versionchanged:: 2.8
+ The cache size was increased to 400 from a low 50.
+
+ `auto_reload`
+ Some loaders load templates from locations where the template
+ sources may change (ie: file system or database). If
+ ``auto_reload`` is set to ``True`` (default) every time a template is
+ requested the loader checks if the source changed and if yes, it
+ will reload the template. For higher performance it's possible to
+ disable that.
+
+ `bytecode_cache`
+ If set to a bytecode cache object, this object will provide a
+ cache for the internal Jinja bytecode so that templates don't
+ have to be parsed if they were not changed.
+
+ See :ref:`bytecode-cache` for more information.
+
+ `enable_async`
If set to true this enables async template execution which
allows using async functions and generators.
- """
-
- #: if this environment is sandboxed. Modifying this variable won't make
- #: the environment sandboxed though. For a real sandboxed environment
- #: have a look at jinja2.sandbox. This flag alone controls the code
- #: generation by the compiler.
- sandboxed = False
-
- #: True if the environment is just an overlay
- overlayed = False
-
- #: the environment this environment is linked to if it is an overlay
+ """
+
+ #: if this environment is sandboxed. Modifying this variable won't make
+ #: the environment sandboxed though. For a real sandboxed environment
+ #: have a look at jinja2.sandbox. This flag alone controls the code
+ #: generation by the compiler.
+ sandboxed = False
+
+ #: True if the environment is just an overlay
+ overlayed = False
+
+ #: the environment this environment is linked to if it is an overlay
linked_to: t.Optional["Environment"] = None
-
- #: shared environments have this set to `True`. A shared environment
- #: must not be modified
- shared = False
-
- #: the class that is used for code generation. See
- #: :class:`~jinja2.compiler.CodeGenerator` for more information.
+
+ #: shared environments have this set to `True`. A shared environment
+ #: must not be modified
+ shared = False
+
+ #: the class that is used for code generation. See
+ #: :class:`~jinja2.compiler.CodeGenerator` for more information.
code_generator_class: t.Type["CodeGenerator"] = CodeGenerator
-
+
#: the context class that is used for templates. See
- #: :class:`~jinja2.runtime.Context` for more information.
+ #: :class:`~jinja2.runtime.Context` for more information.
context_class: t.Type[Context] = Context
-
+
template_class: t.Type["Template"]
def __init__(
@@ -313,73 +313,73 @@ class Environment:
bytecode_cache: t.Optional["BytecodeCache"] = None,
enable_async: bool = False,
):
- # !!Important notice!!
- # The constructor accepts quite a few arguments that should be
- # passed by keyword rather than position. However it's important to
- # not change the order of arguments because it's used at least
- # internally in those cases:
- # - spontaneous environments (i18n extension and Template)
- # - unittests
- # If parameter changes are required only add parameters at the end
- # and don't change the arguments (or the defaults!) of the arguments
- # existing already.
-
- # lexer / parser information
- self.block_start_string = block_start_string
- self.block_end_string = block_end_string
- self.variable_start_string = variable_start_string
- self.variable_end_string = variable_end_string
- self.comment_start_string = comment_start_string
- self.comment_end_string = comment_end_string
- self.line_statement_prefix = line_statement_prefix
- self.line_comment_prefix = line_comment_prefix
- self.trim_blocks = trim_blocks
- self.lstrip_blocks = lstrip_blocks
- self.newline_sequence = newline_sequence
- self.keep_trailing_newline = keep_trailing_newline
-
- # runtime information
+ # !!Important notice!!
+ # The constructor accepts quite a few arguments that should be
+ # passed by keyword rather than position. However it's important to
+ # not change the order of arguments because it's used at least
+ # internally in those cases:
+ # - spontaneous environments (i18n extension and Template)
+ # - unittests
+ # If parameter changes are required only add parameters at the end
+ # and don't change the arguments (or the defaults!) of the arguments
+ # existing already.
+
+ # lexer / parser information
+ self.block_start_string = block_start_string
+ self.block_end_string = block_end_string
+ self.variable_start_string = variable_start_string
+ self.variable_end_string = variable_end_string
+ self.comment_start_string = comment_start_string
+ self.comment_end_string = comment_end_string
+ self.line_statement_prefix = line_statement_prefix
+ self.line_comment_prefix = line_comment_prefix
+ self.trim_blocks = trim_blocks
+ self.lstrip_blocks = lstrip_blocks
+ self.newline_sequence = newline_sequence
+ self.keep_trailing_newline = keep_trailing_newline
+
+ # runtime information
self.undefined: t.Type[Undefined] = undefined
- self.optimized = optimized
- self.finalize = finalize
- self.autoescape = autoescape
-
- # defaults
- self.filters = DEFAULT_FILTERS.copy()
- self.tests = DEFAULT_TESTS.copy()
- self.globals = DEFAULT_NAMESPACE.copy()
-
- # set the loader provided
- self.loader = loader
- self.cache = create_cache(cache_size)
- self.bytecode_cache = bytecode_cache
- self.auto_reload = auto_reload
-
- # configurable policies
- self.policies = DEFAULT_POLICIES.copy()
-
- # load extensions
- self.extensions = load_extensions(self, extensions)
-
+ self.optimized = optimized
+ self.finalize = finalize
+ self.autoescape = autoescape
+
+ # defaults
+ self.filters = DEFAULT_FILTERS.copy()
+ self.tests = DEFAULT_TESTS.copy()
+ self.globals = DEFAULT_NAMESPACE.copy()
+
+ # set the loader provided
+ self.loader = loader
+ self.cache = create_cache(cache_size)
+ self.bytecode_cache = bytecode_cache
+ self.auto_reload = auto_reload
+
+ # configurable policies
+ self.policies = DEFAULT_POLICIES.copy()
+
+ # load extensions
+ self.extensions = load_extensions(self, extensions)
+
self.is_async = enable_async
_environment_config_check(self)
-
+
def add_extension(self, extension: t.Union[str, t.Type["Extension"]]) -> None:
- """Adds an extension after the environment was created.
-
- .. versionadded:: 2.5
- """
- self.extensions.update(load_extensions(self, [extension]))
-
+ """Adds an extension after the environment was created.
+
+ .. versionadded:: 2.5
+ """
+ self.extensions.update(load_extensions(self, [extension]))
+
def extend(self, **attributes: t.Any) -> None:
- """Add the items to the instance of the environment if they do not exist
- yet. This is used by :ref:`extensions <writing-extensions>` to register
- callbacks and configuration values without breaking inheritance.
- """
+ """Add the items to the instance of the environment if they do not exist
+ yet. This is used by :ref:`extensions <writing-extensions>` to register
+ callbacks and configuration values without breaking inheritance.
+ """
for key, value in attributes.items():
- if not hasattr(self, key):
- setattr(self, key, value)
-
+ if not hasattr(self, key):
+ setattr(self, key, value)
+
def overlay(
self,
block_start_string: str = missing,
@@ -402,83 +402,83 @@ class Environment:
auto_reload: bool = missing,
bytecode_cache: t.Optional["BytecodeCache"] = missing,
) -> "Environment":
- """Create a new overlay environment that shares all the data with the
- current environment except for cache and the overridden attributes.
- Extensions cannot be removed for an overlayed environment. An overlayed
- environment automatically gets all the extensions of the environment it
- is linked to plus optional extra extensions.
-
- Creating overlays should happen after the initial environment was set
- up completely. Not all attributes are truly linked, some are just
- copied over so modifications on the original environment may not shine
- through.
- """
- args = dict(locals())
+ """Create a new overlay environment that shares all the data with the
+ current environment except for cache and the overridden attributes.
+ Extensions cannot be removed for an overlayed environment. An overlayed
+ environment automatically gets all the extensions of the environment it
+ is linked to plus optional extra extensions.
+
+ Creating overlays should happen after the initial environment was set
+ up completely. Not all attributes are truly linked, some are just
+ copied over so modifications on the original environment may not shine
+ through.
+ """
+ args = dict(locals())
del args["self"], args["cache_size"], args["extensions"]
-
- rv = object.__new__(self.__class__)
- rv.__dict__.update(self.__dict__)
- rv.overlayed = True
- rv.linked_to = self
-
+
+ rv = object.__new__(self.__class__)
+ rv.__dict__.update(self.__dict__)
+ rv.overlayed = True
+ rv.linked_to = self
+
for key, value in args.items():
- if value is not missing:
- setattr(rv, key, value)
-
- if cache_size is not missing:
- rv.cache = create_cache(cache_size)
- else:
- rv.cache = copy_cache(self.cache)
-
- rv.extensions = {}
+ if value is not missing:
+ setattr(rv, key, value)
+
+ if cache_size is not missing:
+ rv.cache = create_cache(cache_size)
+ else:
+ rv.cache = copy_cache(self.cache)
+
+ rv.extensions = {}
for key, value in self.extensions.items():
- rv.extensions[key] = value.bind(rv)
- if extensions is not missing:
- rv.extensions.update(load_extensions(rv, extensions))
-
+ rv.extensions[key] = value.bind(rv)
+ if extensions is not missing:
+ rv.extensions.update(load_extensions(rv, extensions))
+
return _environment_config_check(rv)
-
+
@property
def lexer(self) -> Lexer:
"""The lexer for this environment."""
return get_lexer(self)
-
+
def iter_extensions(self) -> t.Iterator["Extension"]:
- """Iterates over the extensions by priority."""
+ """Iterates over the extensions by priority."""
return iter(sorted(self.extensions.values(), key=lambda x: x.priority))
-
+
def getitem(
self, obj: t.Any, argument: t.Union[str, t.Any]
) -> t.Union[t.Any, Undefined]:
- """Get an item or attribute of an object but prefer the item."""
- try:
- return obj[argument]
- except (AttributeError, TypeError, LookupError):
+ """Get an item or attribute of an object but prefer the item."""
+ try:
+ return obj[argument]
+ except (AttributeError, TypeError, LookupError):
if isinstance(argument, str):
- try:
- attr = str(argument)
- except Exception:
- pass
- else:
- try:
- return getattr(obj, attr)
- except AttributeError:
- pass
- return self.undefined(obj=obj, name=argument)
-
+ try:
+ attr = str(argument)
+ except Exception:
+ pass
+ else:
+ try:
+ return getattr(obj, attr)
+ except AttributeError:
+ pass
+ return self.undefined(obj=obj, name=argument)
+
def getattr(self, obj: t.Any, attribute: str) -> t.Any:
- """Get an item or attribute of an object but prefer the attribute.
+ """Get an item or attribute of an object but prefer the attribute.
Unlike :meth:`getitem` the attribute *must* be a string.
- """
- try:
- return getattr(obj, attribute)
- except AttributeError:
- pass
- try:
- return obj[attribute]
- except (TypeError, LookupError, AttributeError):
- return self.undefined(obj=obj, name=attribute)
-
+ """
+ try:
+ return getattr(obj, attribute)
+ except AttributeError:
+ pass
+ try:
+ return obj[attribute]
+ except (TypeError, LookupError, AttributeError):
+ return self.undefined(obj=obj, name=attribute)
+
def _filter_test_common(
self,
name: t.Union[str, Undefined],
@@ -495,10 +495,10 @@ class Environment:
else:
env_map = self.tests
type_name = "test"
-
+
func = env_map.get(name) # type: ignore
-
- if func is None:
+
+ if func is None:
msg = f"No {type_name} named {name!r}."
if isinstance(name, Undefined):
@@ -514,25 +514,25 @@ class Environment:
pass_arg = _PassArg.from_obj(func)
if pass_arg is _PassArg.context:
- if context is None:
+ if context is None:
raise TemplateRuntimeError(
f"Attempted to invoke a context {type_name} without context."
)
- args.insert(0, context)
+ args.insert(0, context)
elif pass_arg is _PassArg.eval_context:
- if eval_ctx is None:
- if context is not None:
- eval_ctx = context.eval_ctx
- else:
- eval_ctx = EvalContext(self)
+ 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)
+ args.insert(0, eval_ctx)
elif pass_arg is _PassArg.environment:
- args.insert(0, self)
-
+ args.insert(0, self)
+
return func(*args, **kwargs)
-
+
def call_filter(
self,
name: str,
@@ -548,12 +548,12 @@ class Environment:
environment in async mode and the filter supports async
execution. It's your responsibility to await this if needed.
- .. versionadded:: 2.7
- """
+ .. versionadded:: 2.7
+ """
return self._filter_test_common(
name, value, args, kwargs, context, eval_ctx, True
)
-
+
def call_test(
self,
name: str,
@@ -579,69 +579,69 @@ class Environment:
name, value, args, kwargs, context, eval_ctx, False
)
- @internalcode
+ @internalcode
def parse(
self,
source: str,
name: t.Optional[str] = None,
filename: t.Optional[str] = None,
) -> nodes.Template:
- """Parse the sourcecode and return the abstract syntax tree. This
- tree of nodes is used by the compiler to convert the template into
- executable source- or bytecode. This is useful for debugging or to
- extract information from templates.
-
+ """Parse the sourcecode and return the abstract syntax tree. This
+ tree of nodes is used by the compiler to convert the template into
+ executable source- or bytecode. This is useful for debugging or to
+ extract information from templates.
+
If you are :ref:`developing Jinja extensions <writing-extensions>`
- this gives you a good overview of the node tree generated.
- """
- try:
- return self._parse(source, name, filename)
- except TemplateSyntaxError:
+ this gives you a good overview of the node tree generated.
+ """
+ try:
+ return self._parse(source, name, filename)
+ except TemplateSyntaxError:
self.handle_exception(source=source)
-
+
def _parse(
self, source: str, name: t.Optional[str], filename: t.Optional[str]
) -> nodes.Template:
- """Internal parsing function used by `parse` and `compile`."""
+ """Internal parsing function used by `parse` and `compile`."""
return Parser(self, source, name, filename).parse()
-
+
def lex(
self,
source: str,
name: t.Optional[str] = None,
filename: t.Optional[str] = None,
) -> t.Iterator[t.Tuple[int, str, str]]:
- """Lex the given sourcecode and return a generator that yields
- tokens as tuples in the form ``(lineno, token_type, value)``.
- This can be useful for :ref:`extension development <writing-extensions>`
- and debugging templates.
-
- This does not perform preprocessing. If you want the preprocessing
- of the extensions to be applied you have to filter source through
- the :meth:`preprocess` method.
- """
+ """Lex the given sourcecode and return a generator that yields
+ tokens as tuples in the form ``(lineno, token_type, value)``.
+ This can be useful for :ref:`extension development <writing-extensions>`
+ and debugging templates.
+
+ This does not perform preprocessing. If you want the preprocessing
+ of the extensions to be applied you have to filter source through
+ the :meth:`preprocess` method.
+ """
source = str(source)
- try:
- return self.lexer.tokeniter(source, name, filename)
- except TemplateSyntaxError:
+ try:
+ return self.lexer.tokeniter(source, name, filename)
+ except TemplateSyntaxError:
self.handle_exception(source=source)
-
+
def preprocess(
self,
source: str,
name: t.Optional[str] = None,
filename: t.Optional[str] = None,
) -> str:
- """Preprocesses the source with all extensions. This is automatically
- called for all parsing and compiling methods but *not* for :meth:`lex`
- because there you usually only want the actual source tokenized.
- """
+ """Preprocesses the source with all extensions. This is automatically
+ called for all parsing and compiling methods but *not* for :meth:`lex`
+ because there you usually only want the actual source tokenized.
+ """
return reduce(
lambda s, e: e.preprocess(s, name, filename),
self.iter_extensions(),
str(source),
)
-
+
def _tokenize(
self,
source: str,
@@ -649,20 +649,20 @@ class Environment:
filename: t.Optional[str] = None,
state: t.Optional[str] = None,
) -> TokenStream:
- """Called by the parser to do the preprocessing and filtering
- for all the extensions. Returns a :class:`~jinja2.lexer.TokenStream`.
- """
- source = self.preprocess(source, name, filename)
- stream = self.lexer.tokenize(source, name, filename, state)
+ """Called by the parser to do the preprocessing and filtering
+ for all the extensions. Returns a :class:`~jinja2.lexer.TokenStream`.
+ """
+ source = self.preprocess(source, name, filename)
+ stream = self.lexer.tokenize(source, name, filename, state)
- for ext in self.iter_extensions():
+ for ext in self.iter_extensions():
stream = ext.filter_stream(stream) # type: ignore
- if not isinstance(stream, TokenStream):
+ if not isinstance(stream, TokenStream):
stream = TokenStream(stream, name, filename) # type: ignore
- return stream
-
+ return stream
+
def _generate(
self,
source: nodes.Template,
@@ -670,11 +670,11 @@ class Environment:
filename: t.Optional[str],
defer_init: bool = False,
) -> str:
- """Internal hook that can be overridden to hook a different generate
- method in.
-
- .. versionadded:: 2.5
- """
+ """Internal hook that can be overridden to hook a different generate
+ method in.
+
+ .. versionadded:: 2.5
+ """
return generate( # type: ignore
source,
self,
@@ -683,15 +683,15 @@ class Environment:
defer_init=defer_init,
optimized=self.optimized,
)
-
+
def _compile(self, source: str, filename: str) -> CodeType:
- """Internal hook that can be overridden to hook a different compile
- method in.
-
- .. versionadded:: 2.5
- """
+ """Internal hook that can be overridden to hook a different compile
+ method in.
+
+ .. versionadded:: 2.5
+ """
return compile(source, filename, "exec") # type: ignore
-
+
@typing.overload
def compile( # type: ignore
self,
@@ -714,7 +714,7 @@ class Environment:
) -> str:
...
- @internalcode
+ @internalcode
def compile(
self,
source: t.Union[str, nodes.Template],
@@ -723,84 +723,84 @@ class Environment:
raw: bool = False,
defer_init: bool = False,
) -> t.Union[str, CodeType]:
- """Compile a node or template source code. The `name` parameter is
- the load name of the template after it was joined using
- :meth:`join_path` if necessary, not the filename on the file system.
- the `filename` parameter is the estimated filename of the template on
- the file system. If the template came from a database or memory this
- can be omitted.
-
- The return value of this method is a python code object. If the `raw`
- parameter is `True` the return value will be a string with python
- code equivalent to the bytecode returned otherwise. This method is
- mainly used internally.
-
- `defer_init` is use internally to aid the module code generator. This
- causes the generated code to be able to import without the global
- environment variable to be set.
-
- .. versionadded:: 2.4
- `defer_init` parameter added.
- """
- source_hint = None
- try:
+ """Compile a node or template source code. The `name` parameter is
+ the load name of the template after it was joined using
+ :meth:`join_path` if necessary, not the filename on the file system.
+ the `filename` parameter is the estimated filename of the template on
+ the file system. If the template came from a database or memory this
+ can be omitted.
+
+ The return value of this method is a python code object. If the `raw`
+ parameter is `True` the return value will be a string with python
+ code equivalent to the bytecode returned otherwise. This method is
+ mainly used internally.
+
+ `defer_init` is use internally to aid the module code generator. This
+ causes the generated code to be able to import without the global
+ environment variable to be set.
+
+ .. versionadded:: 2.4
+ `defer_init` parameter added.
+ """
+ source_hint = None
+ try:
if isinstance(source, str):
- source_hint = source
- source = self._parse(source, name, filename)
+ source_hint = source
+ source = self._parse(source, name, filename)
source = self._generate(source, name, filename, defer_init=defer_init)
- if raw:
- return source
- if filename is None:
+ if raw:
+ return source
+ if filename is None:
filename = "<template>"
- return self._compile(source, filename)
- except TemplateSyntaxError:
+ return self._compile(source, filename)
+ except TemplateSyntaxError:
self.handle_exception(source=source_hint)
-
+
def compile_expression(
self, source: str, undefined_to_none: bool = True
) -> "TemplateExpression":
- """A handy helper method that returns a callable that accepts keyword
- arguments that appear as variables in the expression. If called it
- returns the result of the expression.
-
- This is useful if applications want to use the same rules as Jinja
- in template "configuration files" or similar situations.
-
- Example usage:
-
- >>> env = Environment()
- >>> expr = env.compile_expression('foo == 42')
- >>> expr(foo=23)
- False
- >>> expr(foo=42)
- True
-
- Per default the return value is converted to `None` if the
- expression returns an undefined value. This can be changed
- by setting `undefined_to_none` to `False`.
-
- >>> env.compile_expression('var')() is None
- True
- >>> env.compile_expression('var', undefined_to_none=False)()
- Undefined
-
- .. versionadded:: 2.1
- """
+ """A handy helper method that returns a callable that accepts keyword
+ arguments that appear as variables in the expression. If called it
+ returns the result of the expression.
+
+ This is useful if applications want to use the same rules as Jinja
+ in template "configuration files" or similar situations.
+
+ Example usage:
+
+ >>> env = Environment()
+ >>> expr = env.compile_expression('foo == 42')
+ >>> expr(foo=23)
+ False
+ >>> expr(foo=42)
+ True
+
+ Per default the return value is converted to `None` if the
+ expression returns an undefined value. This can be changed
+ by setting `undefined_to_none` to `False`.
+
+ >>> env.compile_expression('var')() is None
+ True
+ >>> env.compile_expression('var', undefined_to_none=False)()
+ Undefined
+
+ .. versionadded:: 2.1
+ """
parser = Parser(self, source, state="variable")
- try:
- expr = parser.parse_expression()
- if not parser.stream.eos:
+ try:
+ expr = parser.parse_expression()
+ if not parser.stream.eos:
raise TemplateSyntaxError(
"chunk after expression", parser.stream.current.lineno, None, None
)
- expr.set_environment(self)
- except TemplateSyntaxError:
+ expr.set_environment(self)
+ except TemplateSyntaxError:
self.handle_exception(source=source)
body = [nodes.Assign(nodes.Name("result", "store"), expr, lineno=1)]
- template = self.from_string(nodes.Template(body, lineno=1))
- return TemplateExpression(template, undefined_to_none)
-
+ template = self.from_string(nodes.Template(body, lineno=1))
+ return TemplateExpression(template, undefined_to_none)
+
def compile_templates(
self,
target: t.Union[str, os.PathLike],
@@ -810,27 +810,27 @@ class Environment:
log_function: t.Optional[t.Callable[[str], None]] = None,
ignore_errors: bool = True,
) -> None:
- """Finds all the templates the loader can find, compiles them
- and stores them in `target`. If `zip` is `None`, instead of in a
- zipfile, the templates will be stored in a directory.
- By default a deflate zip algorithm is used. To switch to
- the stored algorithm, `zip` can be set to ``'stored'``.
-
- `extensions` and `filter_func` are passed to :meth:`list_templates`.
- Each template returned will be compiled to the target folder or
- zipfile.
-
- By default template compilation errors are ignored. In case a
- log function is provided, errors are logged. If you want template
- syntax errors to abort the compilation you can set `ignore_errors`
- to `False` and you will get an exception on syntax errors.
-
- .. versionadded:: 2.4
- """
+ """Finds all the templates the loader can find, compiles them
+ and stores them in `target`. If `zip` is `None`, instead of in a
+ zipfile, the templates will be stored in a directory.
+ By default a deflate zip algorithm is used. To switch to
+ the stored algorithm, `zip` can be set to ``'stored'``.
+
+ `extensions` and `filter_func` are passed to :meth:`list_templates`.
+ Each template returned will be compiled to the target folder or
+ zipfile.
+
+ By default template compilation errors are ignored. In case a
+ log function is provided, errors are logged. If you want template
+ syntax errors to abort the compilation you can set `ignore_errors`
+ to `False` and you will get an exception on syntax errors.
+
+ .. versionadded:: 2.4
+ """
from .loaders import ModuleLoader
-
- if log_function is None:
-
+
+ if log_function is None:
+
def log_function(x: str) -> None:
pass
@@ -838,72 +838,72 @@ class Environment:
assert self.loader is not None, "No loader configured."
def write_file(filename: str, data: str) -> None:
- if zip:
- info = ZipInfo(filename)
- info.external_attr = 0o755 << 16
- zip_file.writestr(info, data)
- else:
+ if zip:
+ info = ZipInfo(filename)
+ info.external_attr = 0o755 << 16
+ zip_file.writestr(info, data)
+ else:
with open(os.path.join(target, filename), "wb") as f:
f.write(data.encode("utf8"))
-
- if zip is not None:
- from zipfile import ZipFile, ZipInfo, ZIP_DEFLATED, ZIP_STORED
+
+ if zip is not None:
+ from zipfile import ZipFile, ZipInfo, ZIP_DEFLATED, ZIP_STORED
zip_file = ZipFile(
target, "w", dict(deflated=ZIP_DEFLATED, stored=ZIP_STORED)[zip]
)
log_function(f"Compiling into Zip archive {target!r}")
- else:
- if not os.path.isdir(target):
- os.makedirs(target)
+ else:
+ if not os.path.isdir(target):
+ os.makedirs(target)
log_function(f"Compiling into folder {target!r}")
-
- try:
- for name in self.list_templates(extensions, filter_func):
- source, filename, _ = self.loader.get_source(self, name)
- try:
- code = self.compile(source, name, filename, True, True)
- except TemplateSyntaxError as e:
- if not ignore_errors:
- raise
+
+ try:
+ for name in self.list_templates(extensions, filter_func):
+ source, filename, _ = self.loader.get_source(self, name)
+ try:
+ code = self.compile(source, name, filename, True, True)
+ except TemplateSyntaxError as e:
+ if not ignore_errors:
+ raise
log_function(f'Could not compile "{name}": {e}')
- continue
-
- filename = ModuleLoader.get_module_filename(name)
-
+ continue
+
+ filename = ModuleLoader.get_module_filename(name)
+
write_file(filename, code)
log_function(f'Compiled "{name}" as {filename}')
- finally:
- if zip:
- zip_file.close()
-
+ finally:
+ if zip:
+ zip_file.close()
+
log_function("Finished compiling templates")
-
+
def list_templates(
self,
extensions: t.Optional[t.Collection[str]] = None,
filter_func: t.Optional[t.Callable[[str], bool]] = None,
) -> t.List[str]:
- """Returns a list of templates for this environment. This requires
- that the loader supports the loader's
- :meth:`~BaseLoader.list_templates` method.
-
- If there are other files in the template folder besides the
- actual templates, the returned list can be filtered. There are two
- ways: either `extensions` is set to a list of file extensions for
- templates, or a `filter_func` can be provided which is a callable that
- is passed a template name and should return `True` if it should end up
- in the result list.
-
- If the loader does not support that, a :exc:`TypeError` is raised.
-
- .. versionadded:: 2.4
- """
+ """Returns a list of templates for this environment. This requires
+ that the loader supports the loader's
+ :meth:`~BaseLoader.list_templates` method.
+
+ If there are other files in the template folder besides the
+ actual templates, the returned list can be filtered. There are two
+ ways: either `extensions` is set to a list of file extensions for
+ templates, or a `filter_func` can be provided which is a callable that
+ is passed a template name and should return `True` if it should end up
+ in the result list.
+
+ If the loader does not support that, a :exc:`TypeError` is raised.
+
+ .. versionadded:: 2.4
+ """
assert self.loader is not None, "No loader configured."
names = self.loader.list_templates()
- if extensions is not None:
- if filter_func is not None:
+ if extensions is not None:
+ if filter_func is not None:
raise TypeError(
"either extensions or filter_func can be passed, but not both"
)
@@ -911,40 +911,40 @@ class Environment:
def filter_func(x: str) -> bool:
return "." in x and x.rsplit(".", 1)[1] in extensions # type: ignore
- if filter_func is not None:
+ if filter_func is not None:
names = [name for name in names if filter_func(name)]
-
+
return names
def handle_exception(self, source: t.Optional[str] = None) -> "te.NoReturn":
- """Exception handling helper. This is used internally to either raise
- rewritten exceptions or return a rendered traceback for the template.
- """
+ """Exception handling helper. This is used internally to either raise
+ rewritten exceptions or return a rendered traceback for the template.
+ """
from .debug import rewrite_traceback_stack
-
+
raise rewrite_traceback_stack(source=source)
-
+
def join_path(self, template: str, parent: str) -> str:
- """Join a template with the parent. By default all the lookups are
- relative to the loader root so this method returns the `template`
- parameter unchanged, but if the paths should be relative to the
- parent template, this function can be used to calculate the real
- template name.
-
- Subclasses may override this method and implement template path
- joining here.
- """
- return template
-
- @internalcode
+ """Join a template with the parent. By default all the lookups are
+ relative to the loader root so this method returns the `template`
+ parameter unchanged, but if the paths should be relative to the
+ parent template, this function can be used to calculate the real
+ template name.
+
+ Subclasses may override this method and implement template path
+ joining here.
+ """
+ return template
+
+ @internalcode
def _load_template(
self, name: str, globals: t.Optional[t.Mapping[str, t.Any]]
) -> "Template":
- if self.loader is None:
+ if self.loader is None:
raise TypeError("no loader for this environment specified")
- cache_key = (weakref.ref(self.loader), name)
- if self.cache is not None:
- template = self.cache.get(cache_key)
+ cache_key = (weakref.ref(self.loader), name)
+ if self.cache is not None:
+ template = self.cache.get(cache_key)
if template is not None and (
not self.auto_reload or template.is_up_to_date
):
@@ -953,15 +953,15 @@ class Environment:
if globals:
template.globals.update(globals)
- return template
+ return template
template = self.loader.load(self, name, self.make_globals(globals))
- if self.cache is not None:
- self.cache[cache_key] = template
- return template
-
- @internalcode
+ if self.cache is not None:
+ self.cache[cache_key] = template
+ return template
+
+ @internalcode
def get_template(
self,
name: t.Union[str, "Template"],
@@ -971,7 +971,7 @@ class Environment:
"""Load a template by name with :attr:`loader` and return a
:class:`Template`. If the template does not exist a
:exc:`TemplateNotFound` exception is raised.
-
+
:param name: Name of the template to load.
:param parent: The name of the parent template importing this
template. :meth:`join_path` can be used to implement name
@@ -980,23 +980,23 @@ class Environment:
these extra variables available for all renders of this
template. If the template has already been loaded and
cached, its globals are updated with any new items.
-
+
.. versionchanged:: 3.0
If a template is loaded from cache, ``globals`` will update
the template's globals instead of ignoring the new values.
-
- .. versionchanged:: 2.4
+
+ .. versionchanged:: 2.4
If ``name`` is a :class:`Template` object it is returned
unchanged.
- """
- if isinstance(name, Template):
- return name
- if parent is not None:
- name = self.join_path(name, parent)
-
+ """
+ if isinstance(name, Template):
+ return name
+ if parent is not None:
+ name = self.join_path(name, parent)
+
return self._load_template(name, globals)
- @internalcode
+ @internalcode
def select_template(
self,
names: t.Iterable[t.Union[str, "Template"]],
@@ -1006,7 +1006,7 @@ class Environment:
"""Like :meth:`get_template`, but tries loading multiple names.
If none of the names can be loaded a :exc:`TemplatesNotFound`
exception is raised.
-
+
:param names: List of template names to try loading in order.
:param parent: The name of the parent template importing this
template. :meth:`join_path` can be used to implement name
@@ -1024,33 +1024,33 @@ class Environment:
If ``names`` is :class:`Undefined`, an :exc:`UndefinedError`
is raised instead. If no templates were found and ``names``
contains :class:`Undefined`, the message is more helpful.
-
- .. versionchanged:: 2.4
+
+ .. versionchanged:: 2.4
If ``names`` contains a :class:`Template` object it is
returned unchanged.
.. versionadded:: 2.3
- """
+ """
if isinstance(names, Undefined):
names._fail_with_undefined_error()
- if not names:
+ if not names:
raise TemplatesNotFound(
message="Tried to select from an empty list of templates."
)
- for name in names:
- if isinstance(name, Template):
- return name
- if parent is not None:
- name = self.join_path(name, parent)
- try:
- return self._load_template(name, globals)
+ for name in names:
+ if isinstance(name, Template):
+ return name
+ if parent is not None:
+ name = self.join_path(name, parent)
+ try:
+ return self._load_template(name, globals)
except (TemplateNotFound, UndefinedError):
- pass
+ pass
raise TemplatesNotFound(names) # type: ignore
-
- @internalcode
+
+ @internalcode
def get_or_select_template(
self,
template_name_or_list: t.Union[
@@ -1061,15 +1061,15 @@ class Environment:
) -> "Template":
"""Use :meth:`select_template` if an iterable of template names
is given, or :meth:`get_template` if one name is given.
-
- .. versionadded:: 2.3
- """
+
+ .. versionadded:: 2.3
+ """
if isinstance(template_name_or_list, (str, Undefined)):
- return self.get_template(template_name_or_list, parent, globals)
- elif isinstance(template_name_or_list, Template):
- return template_name_or_list
- return self.select_template(template_name_or_list, parent, globals)
-
+ return self.get_template(template_name_or_list, parent, globals)
+ elif isinstance(template_name_or_list, Template):
+ return template_name_or_list
+ return self.select_template(template_name_or_list, parent, globals)
+
def from_string(
self,
source: t.Union[str, nodes.Template],
@@ -1086,22 +1086,22 @@ class Environment:
cached, its globals are updated with any new items.
:param template_class: Return an instance of this
:class:`Template` class.
- """
+ """
gs = self.make_globals(globals)
- cls = template_class or self.template_class
+ cls = template_class or self.template_class
return cls.from_code(self, self.compile(source), gs, None)
-
+
def make_globals(
self, d: t.Optional[t.Mapping[str, t.Any]]
) -> t.MutableMapping[str, t.Any]:
"""Make the globals map for a template. Any given template
globals overlay the environment :attr:`globals`.
-
+
Returns a :class:`collections.ChainMap`. This allows any changes
to a template's globals to only affect that template, while
changes to the environment's globals are still reflected.
However, avoid modifying any globals after a template is loaded.
-
+
:param d: Dict of template-specific globals.
.. versionchanged:: 3.0
@@ -1116,21 +1116,21 @@ class Environment:
class Template:
"""A compiled template that can be rendered.
-
+
Use the methods on :class:`Environment` to create or load templates.
The environment is used to configure how templates are compiled and
behave.
-
+
It is also possible to create a template object directly. This is
not usually recommended. The constructor takes most of the same
arguments as :class:`Environment`. All templates created with the
same environment arguments share the same ephemeral ``Environment``
instance behind the scenes.
-
+
A template object should be considered immutable. Modifications on
the object are not supported.
- """
-
+ """
+
#: Type of environment to create when creating a template directly
#: rather than through an existing environment.
environment_class: t.Type[Environment] = Environment
@@ -1167,7 +1167,7 @@ class Template:
autoescape: t.Union[bool, t.Callable[[t.Optional[str]], bool]] = False,
enable_async: bool = False,
) -> t.Any: # it returns a `Template`, but this breaks the sphinx build...
- env = get_spontaneous_environment(
+ env = get_spontaneous_environment(
cls.environment_class, # type: ignore
block_start_string,
block_end_string,
@@ -1192,9 +1192,9 @@ class Template:
None,
enable_async,
)
- return env.from_string(source, template_class=cls)
-
- @classmethod
+ return env.from_string(source, template_class=cls)
+
+ @classmethod
def from_code(
cls,
environment: Environment,
@@ -1202,30 +1202,30 @@ class Template:
globals: t.MutableMapping[str, t.Any],
uptodate: t.Optional[t.Callable[[], bool]] = None,
) -> "Template":
- """Creates a template object from compiled code and the globals. This
- is used by the loaders and environment to create a template object.
- """
+ """Creates a template object from compiled code and the globals. This
+ is used by the loaders and environment to create a template object.
+ """
namespace = {"environment": environment, "__file__": code.co_filename}
- exec(code, namespace)
- rv = cls._from_namespace(environment, namespace, globals)
- rv._uptodate = uptodate
- return rv
-
- @classmethod
+ exec(code, namespace)
+ rv = cls._from_namespace(environment, namespace, globals)
+ rv._uptodate = uptodate
+ return rv
+
+ @classmethod
def from_module_dict(
cls,
environment: Environment,
module_dict: t.MutableMapping[str, t.Any],
globals: t.MutableMapping[str, t.Any],
) -> "Template":
- """Creates a template object from a module. This is used by the
- module loader to create a template object.
-
- .. versionadded:: 2.4
- """
- return cls._from_namespace(environment, module_dict, globals)
-
- @classmethod
+ """Creates a template object from a module. This is used by the
+ module loader to create a template object.
+
+ .. versionadded:: 2.4
+ """
+ return cls._from_namespace(environment, module_dict, globals)
+
+ @classmethod
def _from_namespace(
cls,
environment: Environment,
@@ -1233,36 +1233,36 @@ class Template:
globals: t.MutableMapping[str, t.Any],
) -> "Template":
t: "Template" = object.__new__(cls)
- t.environment = environment
- t.globals = globals
+ t.environment = environment
+ t.globals = globals
t.name = namespace["name"]
t.filename = namespace["__file__"]
t.blocks = namespace["blocks"]
-
- # render function and module
+
+ # render function and module
t.root_render_func = namespace["root"] # type: ignore
- t._module = None
-
- # debug and loader helpers
+ t._module = None
+
+ # debug and loader helpers
t._debug_info = namespace["debug_info"]
- t._uptodate = None
-
- # store the reference
+ t._uptodate = None
+
+ # store the reference
namespace["environment"] = environment
namespace["__jinja_template__"] = t
-
- return t
-
+
+ return t
+
def render(self, *args: t.Any, **kwargs: t.Any) -> str:
- """This method accepts the same arguments as the `dict` constructor:
- A dict, a dict subclass or some keyword arguments. If no arguments
- are given the context will be empty. These two calls do the same::
-
- template.render(knights='that say nih')
- template.render({'knights': 'that say nih'})
-
+ """This method accepts the same arguments as the `dict` constructor:
+ A dict, a dict subclass or some keyword arguments. If no arguments
+ are given the context will be empty. These two calls do the same::
+
+ template.render(knights='that say nih')
+ template.render({'knights': 'that say nih'})
+
This will return the rendered template as a string.
- """
+ """
if self.environment.is_async:
import asyncio
@@ -1285,25 +1285,25 @@ class Template:
ctx = self.new_context(dict(*args, **kwargs))
- try:
+ try:
return concat(self.root_render_func(ctx)) # type: ignore
- except Exception:
+ except Exception:
self.environment.handle_exception()
-
+
async def render_async(self, *args: t.Any, **kwargs: t.Any) -> str:
- """This works similar to :meth:`render` but returns a coroutine
- that when awaited returns the entire rendered template string. This
- requires the async feature to be enabled.
-
- Example usage::
-
- await template.render_async(knights='that say nih; asynchronously')
- """
+ """This works similar to :meth:`render` but returns a coroutine
+ that when awaited returns the entire rendered template string. This
+ requires the async feature to be enabled.
+
+ Example usage::
+
+ await template.render_async(knights='that say nih; asynchronously')
+ """
if not self.environment.is_async:
raise RuntimeError(
"The environment was not created with async mode enabled."
)
-
+
ctx = self.new_context(dict(*args, **kwargs))
try:
@@ -1312,19 +1312,19 @@ class Template:
return self.environment.handle_exception()
def stream(self, *args: t.Any, **kwargs: t.Any) -> "TemplateStream":
- """Works exactly like :meth:`generate` but returns a
- :class:`TemplateStream`.
- """
- return TemplateStream(self.generate(*args, **kwargs))
-
+ """Works exactly like :meth:`generate` but returns a
+ :class:`TemplateStream`.
+ """
+ return TemplateStream(self.generate(*args, **kwargs))
+
def generate(self, *args: t.Any, **kwargs: t.Any) -> t.Iterator[str]:
- """For very large templates it can be useful to not render the whole
- template at once but evaluate each statement after another and yield
- piece for piece. This method basically does exactly that and returns
+ """For very large templates it can be useful to not render the whole
+ template at once but evaluate each statement after another and yield
+ piece for piece. This method basically does exactly that and returns
a generator that yields one item after another as strings.
-
- It accepts the same arguments as :meth:`render`.
- """
+
+ It accepts the same arguments as :meth:`render`.
+ """
if self.environment.is_async:
import asyncio
@@ -1342,22 +1342,22 @@ class Template:
ctx = self.new_context(dict(*args, **kwargs))
- try:
+ try:
yield from self.root_render_func(ctx) # type: ignore
- except Exception:
+ except Exception:
yield self.environment.handle_exception()
-
+
async def generate_async(
self, *args: t.Any, **kwargs: t.Any
) -> t.AsyncIterator[str]:
- """An async version of :meth:`generate`. Works very similarly but
- returns an async iterator instead.
- """
+ """An async version of :meth:`generate`. Works very similarly but
+ returns an async iterator instead.
+ """
if not self.environment.is_async:
raise RuntimeError(
"The environment was not created with async mode enabled."
)
-
+
ctx = self.new_context(dict(*args, **kwargs))
try:
@@ -1372,55 +1372,55 @@ class Template:
shared: bool = False,
locals: t.Optional[t.Mapping[str, t.Any]] = None,
) -> Context:
- """Create a new :class:`Context` for this template. The vars
- provided will be passed to the template. Per default the globals
- are added to the context. If shared is set to `True` the data
+ """Create a new :class:`Context` for this template. The vars
+ provided will be passed to the template. Per default the globals
+ are added to the context. If shared is set to `True` the data
is passed as is to the context without adding the globals.
-
- `locals` can be a dict of local variables for internal usage.
- """
+
+ `locals` can be a dict of local variables for internal usage.
+ """
return new_context(
self.environment, self.name, self.blocks, vars, shared, self.globals, locals
)
-
+
def make_module(
self,
vars: t.Optional[t.Dict[str, t.Any]] = None,
shared: bool = False,
locals: t.Optional[t.Mapping[str, t.Any]] = None,
) -> "TemplateModule":
- """This method works like the :attr:`module` attribute when called
- without arguments but it will evaluate the template on every call
- rather than caching it. It's also possible to provide
- a dict which is then used as context. The arguments are the same
- as for the :meth:`new_context` method.
- """
+ """This method works like the :attr:`module` attribute when called
+ without arguments but it will evaluate the template on every call
+ rather than caching it. It's also possible to provide
+ a dict which is then used as context. The arguments are the same
+ as for the :meth:`new_context` method.
+ """
ctx = self.new_context(vars, shared, locals)
return TemplateModule(self, ctx)
-
+
async def make_module_async(
self,
vars: t.Optional[t.Dict[str, t.Any]] = None,
shared: bool = False,
locals: t.Optional[t.Mapping[str, t.Any]] = None,
) -> "TemplateModule":
- """As template module creation can invoke template code for
+ """As template module creation can invoke template code for
asynchronous executions this method must be used instead of the
- normal :meth:`make_module` one. Likewise the module attribute
- becomes unavailable in async mode.
- """
+ normal :meth:`make_module` one. Likewise the module attribute
+ becomes unavailable in async mode.
+ """
ctx = self.new_context(vars, shared, locals)
return TemplateModule(
self, ctx, [x async for x in self.root_render_func(ctx)] # type: ignore
)
-
- @internalcode
+
+ @internalcode
def _get_default_module(self, ctx: t.Optional[Context] = None) -> "TemplateModule":
"""If a context is passed in, this means that the template was
imported. Imported templates have access to the current
template's globals by default, but they can only be accessed via
the context during runtime.
-
+
If there are new globals, we need to create a new module because
the cached module is already rendered and will not have access
to globals from the current context. This new module is not
@@ -1455,41 +1455,41 @@ class Template:
return self._module
- @property
+ @property
def module(self) -> "TemplateModule":
- """The template as module. This is used for imports in the
- template runtime but is also useful if one wants to access
- exported template variables from the Python layer:
-
- >>> t = Template('{% macro foo() %}42{% endmacro %}23')
- >>> str(t.module)
- '23'
- >>> t.module.foo() == u'42'
- True
-
- This attribute is not available if async mode is enabled.
- """
- return self._get_default_module()
-
+ """The template as module. This is used for imports in the
+ template runtime but is also useful if one wants to access
+ exported template variables from the Python layer:
+
+ >>> t = Template('{% macro foo() %}42{% endmacro %}23')
+ >>> str(t.module)
+ '23'
+ >>> t.module.foo() == u'42'
+ True
+
+ This attribute is not available if async mode is enabled.
+ """
+ return self._get_default_module()
+
def get_corresponding_lineno(self, lineno: int) -> int:
- """Return the source line number of a line number in the
- generated bytecode as they are not in sync.
- """
- for template_line, code_line in reversed(self.debug_info):
- if code_line <= lineno:
- return template_line
- return 1
-
- @property
+ """Return the source line number of a line number in the
+ generated bytecode as they are not in sync.
+ """
+ for template_line, code_line in reversed(self.debug_info):
+ if code_line <= lineno:
+ return template_line
+ return 1
+
+ @property
def is_up_to_date(self) -> bool:
- """If this variable is `False` there is a newer version available."""
- if self._uptodate is None:
- return True
- return self._uptodate()
-
- @property
+ """If this variable is `False` there is a newer version available."""
+ if self._uptodate is None:
+ return True
+ return self._uptodate()
+
+ @property
def debug_info(self) -> t.List[t.Tuple[int, int]]:
- """The debug info mapping."""
+ """The debug info mapping."""
if self._debug_info:
return [
tuple(map(int, x.split("="))) # type: ignore
@@ -1497,29 +1497,29 @@ class Template:
]
return []
-
+
def __repr__(self) -> str:
- if self.name is None:
+ if self.name is None:
name = f"memory:{id(self):x}"
- else:
- name = repr(self.name)
+ else:
+ name = repr(self.name)
return f"<{type(self).__name__} {name}>"
-
-
+
+
class TemplateModule:
- """Represents an imported template. All the exported names of the
- template are available as attributes on this object. Additionally
+ """Represents an imported template. All the exported names of the
+ template are available as attributes on this object. Additionally
converting it into a string renders the contents.
- """
-
+ """
+
def __init__(
self,
template: Template,
context: Context,
body_stream: t.Optional[t.Iterable[str]] = None,
) -> None:
- if body_stream is None:
- if context.environment.is_async:
+ if body_stream is None:
+ if context.environment.is_async:
raise RuntimeError(
"Async mode requires a body stream to be passed to"
" a template module. Use the async methods of the"
@@ -1528,134 +1528,134 @@ class TemplateModule:
body_stream = list(template.root_render_func(context)) # type: ignore
- self._body_stream = body_stream
- self.__dict__.update(context.get_exported())
- self.__name__ = template.name
-
+ self._body_stream = body_stream
+ self.__dict__.update(context.get_exported())
+ self.__name__ = template.name
+
def __html__(self) -> Markup:
- return Markup(concat(self._body_stream))
-
+ return Markup(concat(self._body_stream))
+
def __str__(self) -> str:
- return concat(self._body_stream)
-
+ return concat(self._body_stream)
+
def __repr__(self) -> str:
- if self.__name__ is None:
+ if self.__name__ is None:
name = f"memory:{id(self):x}"
- else:
- name = repr(self.__name__)
+ else:
+ name = repr(self.__name__)
return f"<{type(self).__name__} {name}>"
-
-
+
+
class TemplateExpression:
- """The :meth:`jinja2.Environment.compile_expression` method returns an
- instance of this object. It encapsulates the expression-like access
- to the template with an expression it wraps.
- """
-
+ """The :meth:`jinja2.Environment.compile_expression` method returns an
+ instance of this object. It encapsulates the expression-like access
+ to the template with an expression it wraps.
+ """
+
def __init__(self, template: Template, undefined_to_none: bool) -> None:
- self._template = template
- self._undefined_to_none = undefined_to_none
-
+ self._template = template
+ self._undefined_to_none = undefined_to_none
+
def __call__(self, *args: t.Any, **kwargs: t.Any) -> t.Optional[t.Any]:
- context = self._template.new_context(dict(*args, **kwargs))
+ context = self._template.new_context(dict(*args, **kwargs))
consume(self._template.root_render_func(context)) # type: ignore
rv = context.vars["result"]
- if self._undefined_to_none and isinstance(rv, Undefined):
- rv = None
- return rv
-
-
+ if self._undefined_to_none and isinstance(rv, Undefined):
+ rv = None
+ return rv
+
+
class TemplateStream:
- """A template stream works pretty much like an ordinary python generator
- but it can buffer multiple items to reduce the number of total iterations.
- Per default the output is unbuffered which means that for every unbuffered
+ """A template stream works pretty much like an ordinary python generator
+ but it can buffer multiple items to reduce the number of total iterations.
+ Per default the output is unbuffered which means that for every unbuffered
instruction in the template one string is yielded.
-
- If buffering is enabled with a buffer size of 5, five items are combined
+
+ If buffering is enabled with a buffer size of 5, five items are combined
into a new string. This is mainly useful if you are streaming
- big templates to a client via WSGI which flushes after each iteration.
- """
-
+ big templates to a client via WSGI which flushes after each iteration.
+ """
+
def __init__(self, gen: t.Iterator[str]) -> None:
- self._gen = gen
- self.disable_buffering()
-
+ self._gen = gen
+ self.disable_buffering()
+
def dump(
self,
fp: t.Union[str, t.IO],
encoding: t.Optional[str] = None,
errors: t.Optional[str] = "strict",
) -> None:
- """Dump the complete stream into a file or file-like object.
+ """Dump the complete stream into a file or file-like object.
Per default strings are written, if you want to encode
- before writing specify an `encoding`.
-
- Example usage::
-
- Template('Hello {{ name }}!').stream(name='foo').dump('hello.html')
- """
- close = False
+ before writing specify an `encoding`.
+
+ Example usage::
+
+ Template('Hello {{ name }}!').stream(name='foo').dump('hello.html')
+ """
+ close = False
if isinstance(fp, str):
- if encoding is None:
+ if encoding is None:
encoding = "utf-8"
fp = open(fp, "wb")
- close = True
- try:
- if encoding is not None:
+ close = True
+ try:
+ if encoding is not None:
iterable = (x.encode(encoding, errors) for x in self) # type: ignore
- else:
+ else:
iterable = self # type: ignore
if hasattr(fp, "writelines"):
- fp.writelines(iterable)
- else:
- for item in iterable:
- fp.write(item)
- finally:
- if close:
- fp.close()
-
+ fp.writelines(iterable)
+ else:
+ for item in iterable:
+ fp.write(item)
+ finally:
+ if close:
+ fp.close()
+
def disable_buffering(self) -> None:
- """Disable the output buffering."""
- self._next = partial(next, self._gen)
- self.buffered = False
-
+ """Disable the output buffering."""
+ self._next = partial(next, self._gen)
+ self.buffered = False
+
def _buffered_generator(self, size: int) -> t.Iterator[str]:
buf: t.List[str] = []
- c_size = 0
- push = buf.append
-
+ c_size = 0
+ push = buf.append
+
while True:
- try:
- while c_size < size:
- c = next(self._gen)
- push(c)
- if c:
- c_size += 1
- except StopIteration:
- if not c_size:
- return
- yield concat(buf)
- del buf[:]
- c_size = 0
-
+ try:
+ while c_size < size:
+ c = next(self._gen)
+ push(c)
+ if c:
+ c_size += 1
+ except StopIteration:
+ if not c_size:
+ return
+ yield concat(buf)
+ del buf[:]
+ c_size = 0
+
def enable_buffering(self, size: int = 5) -> None:
- """Enable buffering. Buffer `size` items before yielding them."""
- if size <= 1:
+ """Enable buffering. Buffer `size` items before yielding them."""
+ if size <= 1:
raise ValueError("buffer size too small")
-
- self.buffered = True
- self._next = partial(next, self._buffered_generator(size))
-
+
+ self.buffered = True
+ self._next = partial(next, self._buffered_generator(size))
+
def __iter__(self) -> "TemplateStream":
- return self
-
+ return self
+
def __next__(self) -> str:
return self._next() # type: ignore
-
-
-# hook in default template class. if anyone reads this comment: ignore that
-# it's possible to use custom templates ;-)
-Environment.template_class = Template
+
+
+# hook in default template class. if anyone reads this comment: ignore that
+# it's possible to use custom templates ;-)
+Environment.template_class = Template
diff --git a/contrib/python/Jinja2/py3/jinja2/exceptions.py b/contrib/python/Jinja2/py3/jinja2/exceptions.py
index 082ebe8f22..6f5e257ae1 100644
--- a/contrib/python/Jinja2/py3/jinja2/exceptions.py
+++ b/contrib/python/Jinja2/py3/jinja2/exceptions.py
@@ -1,23 +1,23 @@
import typing as t
-
+
if t.TYPE_CHECKING:
from .runtime import Undefined
+
-
-class TemplateError(Exception):
- """Baseclass for all template errors."""
-
+class TemplateError(Exception):
+ """Baseclass for all template errors."""
+
def __init__(self, message: t.Optional[str] = None) -> None:
super().__init__(message)
@property
def message(self) -> t.Optional[str]:
return self.args[0] if self.args else None
-
-
-class TemplateNotFound(IOError, LookupError, TemplateError):
+
+
+class TemplateNotFound(IOError, LookupError, TemplateError):
"""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.
@@ -26,7 +26,7 @@ class TemplateNotFound(IOError, LookupError, TemplateError):
# Silence the Python warning about message being deprecated since
# it's not valid here.
message: t.Optional[str] = None
-
+
def __init__(
self,
name: t.Optional[t.Union[str, "Undefined"]],
@@ -34,40 +34,40 @@ class TemplateNotFound(IOError, LookupError, TemplateError):
) -> None:
IOError.__init__(self, name)
- if message is None:
+ 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]
+ message = name
+ self.message = message
+ self.name = name
+ self.templates = [name]
+
def __str__(self) -> str:
return str(self.message)
-
-
-class TemplatesNotFound(TemplateNotFound):
- """Like :class:`TemplateNotFound` but raised if multiple templates
- are selected. This is a subclass of :class:`TemplateNotFound`
- exception, so just catching the base exception will catch both.
-
+
+
+class TemplatesNotFound(TemplateNotFound):
+ """Like :class:`TemplateNotFound` but raised if multiple templates
+ 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
- """
-
+ .. versionadded:: 2.2
+ """
+
def __init__(
self,
names: t.Sequence[t.Union[str, "Undefined"]] = (),
message: t.Optional[str] = None,
) -> None:
- if message is None:
+ if message is None:
from .runtime import Undefined
parts = []
@@ -82,12 +82,12 @@ class TemplatesNotFound(TemplateNotFound):
message = f"none of the templates given were found: {parts_str}"
super().__init__(names[-1] if names else None, message)
- self.templates = list(names)
-
-
-class TemplateSyntaxError(TemplateError):
- """Raised to tell the user that there is a problem with the template."""
-
+ self.templates = list(names)
+
+
+class TemplateSyntaxError(TemplateError):
+ """Raised to tell the user that there is a problem with the template."""
+
def __init__(
self,
message: str,
@@ -96,71 +96,71 @@ class TemplateSyntaxError(TemplateError):
filename: t.Optional[str] = None,
) -> None:
super().__init__(message)
- self.lineno = lineno
- self.name = name
- self.filename = filename
+ self.lineno = lineno
+ self.name = name
+ self.filename = filename
self.source: t.Optional[str] = None
-
- # this is set to True if the debug.translate_syntax_error
- # function translated the syntax error into a new traceback
- self.translated = False
-
+
+ # this is set to True if the debug.translate_syntax_error
+ # function translated the syntax error into a new traceback
+ self.translated = False
+
def __str__(self) -> str:
- # for translated errors we only return the message
- if self.translated:
+ # for translated errors we only return the message
+ if self.translated:
return t.cast(str, self.message)
-
- # otherwise attach some stuff
+
+ # otherwise attach some stuff
location = f"line {self.lineno}"
- name = self.filename or self.name
- if name:
+ name = self.filename or self.name
+ if name:
location = f'File "{name}", {location}'
lines = [t.cast(str, self.message), " " + location]
-
- # if the source is set, add the line to the output
- if self.source is not None:
- try:
- line = self.source.splitlines()[self.lineno - 1]
- except IndexError:
+
+ # if the source is set, add the line to the output
+ if self.source is not None:
+ try:
+ line = self.source.splitlines()[self.lineno - 1]
+ except IndexError:
pass
else:
lines.append(" " + line.strip())
-
+
return "\n".join(lines)
-
+
def __reduce__(self): # type: ignore
# 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):
- """Like a template syntax error, but covers cases where something in the
- template caused an error at compile time that wasn't necessarily caused
- by a syntax error. However it's a direct subclass of
- :exc:`TemplateSyntaxError` and has the same attributes.
- """
-
-
-class TemplateRuntimeError(TemplateError):
- """A generic runtime error in the template engine. Under some situations
- Jinja may raise this exception.
- """
-
-
-class UndefinedError(TemplateRuntimeError):
- """Raised if a template tries to operate on :class:`Undefined`."""
-
-
-class SecurityError(TemplateRuntimeError):
- """Raised if a template tries to do something insecure if the
- sandbox is enabled.
- """
-
-
-class FilterArgumentError(TemplateRuntimeError):
- """This error is raised if a filter was called with inappropriate
- arguments
- """
+
+
+class TemplateAssertionError(TemplateSyntaxError):
+ """Like a template syntax error, but covers cases where something in the
+ template caused an error at compile time that wasn't necessarily caused
+ by a syntax error. However it's a direct subclass of
+ :exc:`TemplateSyntaxError` and has the same attributes.
+ """
+
+
+class TemplateRuntimeError(TemplateError):
+ """A generic runtime error in the template engine. Under some situations
+ Jinja may raise this exception.
+ """
+
+
+class UndefinedError(TemplateRuntimeError):
+ """Raised if a template tries to operate on :class:`Undefined`."""
+
+
+class SecurityError(TemplateRuntimeError):
+ """Raised if a template tries to do something insecure if the
+ sandbox is enabled.
+ """
+
+
+class FilterArgumentError(TemplateRuntimeError):
+ """This error is raised if a filter was called with inappropriate
+ arguments
+ """
diff --git a/contrib/python/Jinja2/py3/jinja2/ext.py b/contrib/python/Jinja2/py3/jinja2/ext.py
index 3e982930c4..7b837db429 100644
--- a/contrib/python/Jinja2/py3/jinja2/ext.py
+++ b/contrib/python/Jinja2/py3/jinja2/ext.py
@@ -1,11 +1,11 @@
"""Extension API for adding custom tags and behavior."""
import pprint
-import re
+import re
import typing as t
import warnings
-
+
from markupsafe import Markup
-
+
from . import defaults
from . import nodes
from .environment import Environment
@@ -16,29 +16,29 @@ from .runtime import Context
from .runtime import Undefined
from .utils import import_string
from .utils import pass_context
-
+
if t.TYPE_CHECKING:
import typing_extensions as te
from .lexer import Token
from .lexer import TokenStream
from .parser import Parser
-
+
class _TranslationsBasic(te.Protocol):
def gettext(self, message: str) -> str:
...
-
+
def ngettext(self, singular: str, plural: str, n: int) -> str:
pass
class _TranslationsContext(_TranslationsBasic):
def pgettext(self, context: str, message: str) -> str:
...
-
+
def npgettext(self, context: str, singular: str, plural: str, n: int) -> str:
...
-
+
_SupportedTranslations = t.Union[_TranslationsBasic, _TranslationsContext]
-
+
# I18N functions available in Jinja templates. If the I18N library
# provides ugettext, it will be assigned to gettext.
@@ -53,88 +53,88 @@ _ws_re = re.compile(r"\s*\n\s*")
class Extension:
- """Extensions can be used to add extra functionality to the Jinja template
- system at the parser level. Custom extensions are bound to an environment
- but may not store environment specific data on `self`. The reason for
- this is that an extension can be bound to another environment (for
- overlays) by creating a copy and reassigning the `environment` attribute.
-
- As extensions are created by the environment they cannot accept any
- arguments for configuration. One may want to work around that by using
- a factory function, but that is not possible as extensions are identified
- by their import name. The correct way to configure the extension is
- storing the configuration values on the environment. Because this way the
- environment ends up acting as central configuration storage the
- attributes may clash which is why extensions have to ensure that the names
- they choose for configuration are not too generic. ``prefix`` for example
- is a terrible name, ``fragment_cache_prefix`` on the other hand is a good
- name as includes the name of the extension (fragment cache).
- """
-
+ """Extensions can be used to add extra functionality to the Jinja template
+ system at the parser level. Custom extensions are bound to an environment
+ but may not store environment specific data on `self`. The reason for
+ this is that an extension can be bound to another environment (for
+ overlays) by creating a copy and reassigning the `environment` attribute.
+
+ As extensions are created by the environment they cannot accept any
+ arguments for configuration. One may want to work around that by using
+ a factory function, but that is not possible as extensions are identified
+ by their import name. The correct way to configure the extension is
+ storing the configuration values on the environment. Because this way the
+ environment ends up acting as central configuration storage the
+ attributes may clash which is why extensions have to ensure that the names
+ they choose for configuration are not too generic. ``prefix`` for example
+ is a terrible name, ``fragment_cache_prefix`` on the other hand is a good
+ name as includes the name of the extension (fragment cache).
+ """
+
identifier: t.ClassVar[str]
def __init_subclass__(cls) -> None:
cls.identifier = f"{cls.__module__}.{cls.__name__}"
- #: if this extension parses this is the list of tags it's listening to.
+ #: if this extension parses this is the list of tags it's listening to.
tags: t.Set[str] = set()
-
- #: the priority of that extension. This is especially useful for
- #: extensions that preprocess values. A lower value means higher
- #: priority.
- #:
- #: .. versionadded:: 2.4
- priority = 100
-
+
+ #: the priority of that extension. This is especially useful for
+ #: extensions that preprocess values. A lower value means higher
+ #: priority.
+ #:
+ #: .. versionadded:: 2.4
+ priority = 100
+
def __init__(self, environment: Environment) -> None:
- self.environment = environment
-
+ self.environment = environment
+
def bind(self, environment: Environment) -> "Extension":
- """Create a copy of this extension bound to another environment."""
+ """Create a copy of this extension bound to another environment."""
rv = t.cast(Extension, object.__new__(self.__class__))
- rv.__dict__.update(self.__dict__)
- rv.environment = environment
- return rv
-
+ rv.__dict__.update(self.__dict__)
+ rv.environment = environment
+ return rv
+
def preprocess(
self, source: str, name: t.Optional[str], filename: t.Optional[str] = None
) -> str:
- """This method is called before the actual lexing and can be used to
- preprocess the source. The `filename` is optional. The return value
- must be the preprocessed source.
- """
- return source
-
+ """This method is called before the actual lexing and can be used to
+ preprocess the source. The `filename` is optional. The return value
+ must be the preprocessed source.
+ """
+ return source
+
def filter_stream(
self, stream: "TokenStream"
) -> t.Union["TokenStream", t.Iterable["Token"]]:
- """It's passed a :class:`~jinja2.lexer.TokenStream` that can be used
- to filter tokens returned. This method has to return an iterable of
- :class:`~jinja2.lexer.Token`\\s, but it doesn't have to return a
- :class:`~jinja2.lexer.TokenStream`.
- """
- return stream
-
+ """It's passed a :class:`~jinja2.lexer.TokenStream` that can be used
+ to filter tokens returned. This method has to return an iterable of
+ :class:`~jinja2.lexer.Token`\\s, but it doesn't have to return a
+ :class:`~jinja2.lexer.TokenStream`.
+ """
+ return stream
+
def parse(self, parser: "Parser") -> t.Union[nodes.Node, t.List[nodes.Node]]:
- """If any of the :attr:`tags` matched this method is called with the
- parser as first argument. The token the parser stream is pointing at
- is the name token that matched. This method has to return one or a
- list of multiple nodes.
- """
- raise NotImplementedError()
-
+ """If any of the :attr:`tags` matched this method is called with the
+ parser as first argument. The token the parser stream is pointing at
+ is the name token that matched. This method has to return one or a
+ list of multiple nodes.
+ """
+ raise NotImplementedError()
+
def attr(
self, name: str, lineno: t.Optional[int] = None
) -> nodes.ExtensionAttribute:
- """Return an attribute node for the current extension. This is useful
- to pass constants on extensions to generated template code.
-
- ::
-
- self.attr('_my_attribute', lineno=lineno)
- """
- return nodes.ExtensionAttribute(self.identifier, name, lineno=lineno)
-
+ """Return an attribute node for the current extension. This is useful
+ to pass constants on extensions to generated template code.
+
+ ::
+
+ self.attr('_my_attribute', lineno=lineno)
+ """
+ return nodes.ExtensionAttribute(self.identifier, name, lineno=lineno)
+
def call_method(
self,
name: str,
@@ -144,13 +144,13 @@ class Extension:
dyn_kwargs: t.Optional[nodes.Expr] = None,
lineno: t.Optional[int] = None,
) -> nodes.Call:
- """Call a method of the extension. This is a shortcut for
- :meth:`attr` + :class:`jinja2.nodes.Call`.
- """
- if args is None:
- args = []
- if kwargs is None:
- kwargs = []
+ """Call a method of the extension. This is a shortcut for
+ :meth:`attr` + :class:`jinja2.nodes.Call`.
+ """
+ if args is None:
+ args = []
+ if kwargs is None:
+ kwargs = []
return nodes.Call(
self.attr(name, lineno=lineno),
args,
@@ -159,29 +159,29 @@ class Extension:
dyn_kwargs,
lineno=lineno,
)
-
-
+
+
@pass_context
def _gettext_alias(
__context: Context, *args: t.Any, **kwargs: t.Any
) -> t.Union[t.Any, Undefined]:
return __context.call(__context.resolve("gettext"), *args, **kwargs)
-
-
+
+
def _make_new_gettext(func: t.Callable[[str], str]) -> t.Callable[..., str]:
@pass_context
def gettext(__context: Context, __string: str, **variables: t.Any) -> str:
- rv = __context.call(func, __string)
- if __context.eval_ctx.autoescape:
- rv = Markup(rv)
+ rv = __context.call(func, __string)
+ if __context.eval_ctx.autoescape:
+ rv = Markup(rv)
# Always treat as a format string, even if there are no
# variables. This makes translation strings more consistent
# and predictable. This requires escaping
return rv % variables # type: ignore
- return gettext
-
-
+ return gettext
+
+
def _make_new_ngettext(func: t.Callable[[str, str, int], str]) -> t.Callable[..., str]:
@pass_context
def ngettext(
@@ -192,15 +192,15 @@ def _make_new_ngettext(func: t.Callable[[str, str, int], str]) -> t.Callable[...
**variables: t.Any,
) -> str:
variables.setdefault("num", __num)
- rv = __context.call(func, __singular, __plural, __num)
- if __context.eval_ctx.autoescape:
- rv = Markup(rv)
+ rv = __context.call(func, __singular, __plural, __num)
+ if __context.eval_ctx.autoescape:
+ rv = Markup(rv)
# Always treat as a format string, see gettext comment above.
return rv % variables # type: ignore
- return ngettext
-
-
+ return ngettext
+
+
def _make_new_pgettext(func: t.Callable[[str, str], str]) -> t.Callable[..., str]:
@pass_context
def pgettext(
@@ -243,48 +243,48 @@ def _make_new_npgettext(
return npgettext
-class InternationalizationExtension(Extension):
+class InternationalizationExtension(Extension):
"""This extension adds gettext support to Jinja."""
-
+
tags = {"trans"}
- # TODO: the i18n extension is currently reevaluating values in a few
- # situations. Take this example:
- # {% trans count=something() %}{{ count }} foo{% pluralize
- # %}{{ count }} fooss{% endtrans %}
- # something is called twice here. One time for the gettext value and
- # the other time for the n-parameter of the ngettext function.
-
+ # TODO: the i18n extension is currently reevaluating values in a few
+ # situations. Take this example:
+ # {% trans count=something() %}{{ count }} foo{% pluralize
+ # %}{{ count }} fooss{% endtrans %}
+ # something is called twice here. One time for the gettext value and
+ # the other time for the n-parameter of the ngettext function.
+
def __init__(self, environment: Environment) -> None:
super().__init__(environment)
environment.globals["_"] = _gettext_alias
- environment.extend(
- install_gettext_translations=self._install,
- install_null_translations=self._install_null,
- install_gettext_callables=self._install_callables,
- uninstall_gettext_translations=self._uninstall,
- extract_translations=self._extract,
+ environment.extend(
+ install_gettext_translations=self._install,
+ install_null_translations=self._install_null,
+ install_gettext_callables=self._install_callables,
+ uninstall_gettext_translations=self._uninstall,
+ extract_translations=self._extract,
newstyle_gettext=False,
- )
-
+ )
+
def _install(
self, translations: "_SupportedTranslations", newstyle: t.Optional[bool] = None
) -> None:
# ugettext and ungettext are preferred in case the I18N library
# is providing compatibility with older Python versions.
gettext = getattr(translations, "ugettext", None)
- if gettext is None:
- gettext = translations.gettext
+ if gettext is None:
+ gettext = translations.gettext
ngettext = getattr(translations, "ungettext", None)
- if ngettext is None:
- ngettext = translations.ngettext
-
+ if ngettext is None:
+ ngettext = translations.ngettext
+
pgettext = getattr(translations, "pgettext", None)
npgettext = getattr(translations, "npgettext", None)
- self._install_callables(
+ self._install_callables(
gettext, ngettext, newstyle=newstyle, pgettext=pgettext, npgettext=npgettext
- )
-
+ )
+
def _install_null(self, newstyle: t.Optional[bool] = None) -> None:
import gettext
@@ -321,12 +321,12 @@ class InternationalizationExtension(Extension):
pgettext: t.Optional[t.Callable[[str, str], str]] = None,
npgettext: t.Optional[t.Callable[[str, str, str, int], str]] = None,
) -> None:
- if newstyle is not None:
+ if newstyle is not None:
self.environment.newstyle_gettext = newstyle # type: ignore
if self.environment.newstyle_gettext: # type: ignore
- gettext = _make_new_gettext(gettext)
- ngettext = _make_new_ngettext(ngettext)
-
+ gettext = _make_new_gettext(gettext)
+ ngettext = _make_new_ngettext(ngettext)
+
if pgettext is not None:
pgettext = _make_new_pgettext(pgettext)
@@ -339,8 +339,8 @@ class InternationalizationExtension(Extension):
def _uninstall(self, translations: "_SupportedTranslations") -> None:
for key in ("gettext", "ngettext", "pgettext", "npgettext"):
- self.environment.globals.pop(key, None)
-
+ self.environment.globals.pop(key, None)
+
def _extract(
self,
source: t.Union[str, nodes.Template],
@@ -349,29 +349,29 @@ class InternationalizationExtension(Extension):
t.Tuple[int, str, t.Union[t.Optional[str], t.Tuple[t.Optional[str], ...]]]
]:
if isinstance(source, str):
- source = self.environment.parse(source)
- return extract_from_ast(source, gettext_functions)
-
+ source = self.environment.parse(source)
+ return extract_from_ast(source, gettext_functions)
+
def parse(self, parser: "Parser") -> t.Union[nodes.Node, t.List[nodes.Node]]:
- """Parse a translatable tag."""
- lineno = next(parser.stream).lineno
- num_called_num = False
-
- # find all the variables referenced. Additionally a variable can be
- # defined in the body of the trans block too, but this is checked at
- # a later state.
+ """Parse a translatable tag."""
+ lineno = next(parser.stream).lineno
+ num_called_num = False
+
+ # find all the variables referenced. Additionally a variable can be
+ # defined in the body of the trans block too, but this is checked at
+ # a later state.
plural_expr: t.Optional[nodes.Expr] = None
plural_expr_assignment: t.Optional[nodes.Assign] = None
variables: t.Dict[str, nodes.Expr] = {}
- trimmed = None
+ trimmed = None
while parser.stream.current.type != "block_end":
- if variables:
+ if variables:
parser.stream.expect("comma")
-
- # skip colon for python compatibility
+
+ # skip colon for python compatibility
if parser.stream.skip_if("colon"):
- break
-
+ break
+
token = parser.stream.expect("name")
if token.value in variables:
parser.fail(
@@ -379,46 +379,46 @@ class InternationalizationExtension(Extension):
token.lineno,
exc=TemplateAssertionError,
)
-
- # expressions
+
+ # expressions
if parser.stream.current.type == "assign":
- next(parser.stream)
+ next(parser.stream)
variables[token.value] = var = parser.parse_expression()
elif trimmed is None and token.value in ("trimmed", "notrimmed"):
trimmed = token.value == "trimmed"
- continue
- else:
+ continue
+ else:
variables[token.value] = var = nodes.Name(token.value, "load")
-
- if plural_expr is None:
- if isinstance(var, nodes.Call):
+
+ if plural_expr is None:
+ if isinstance(var, nodes.Call):
plural_expr = nodes.Name("_trans", "load")
variables[token.value] = plural_expr
- plural_expr_assignment = nodes.Assign(
+ plural_expr_assignment = nodes.Assign(
nodes.Name("_trans", "store"), var
)
- else:
- plural_expr = var
+ else:
+ plural_expr = var
num_called_num = token.value == "num"
-
+
parser.stream.expect("block_end")
-
- plural = None
- have_plural = False
- referenced = set()
-
- # now parse until endtrans or pluralize
- singular_names, singular = self._parse_block(parser, True)
- if singular_names:
- referenced.update(singular_names)
- if plural_expr is None:
+
+ plural = None
+ have_plural = False
+ referenced = set()
+
+ # now parse until endtrans or pluralize
+ singular_names, singular = self._parse_block(parser, True)
+ if singular_names:
+ referenced.update(singular_names)
+ if plural_expr is None:
plural_expr = nodes.Name(singular_names[0], "load")
num_called_num = singular_names[0] == "num"
-
- # if we have a pluralize block, we parse that too
+
+ # if we have a pluralize block, we parse that too
if parser.stream.current.test("name:pluralize"):
- have_plural = True
- next(parser.stream)
+ have_plural = True
+ next(parser.stream)
if parser.stream.current.type != "block_end":
token = parser.stream.expect("name")
if token.value not in variables:
@@ -430,29 +430,29 @@ class InternationalizationExtension(Extension):
plural_expr = variables[token.value]
num_called_num = token.value == "num"
parser.stream.expect("block_end")
- plural_names, plural = self._parse_block(parser, False)
- next(parser.stream)
- referenced.update(plural_names)
- else:
- next(parser.stream)
-
- # register free names as simple name expressions
+ plural_names, plural = self._parse_block(parser, False)
+ next(parser.stream)
+ referenced.update(plural_names)
+ else:
+ next(parser.stream)
+
+ # register free names as simple name expressions
for name in referenced:
if name not in variables:
variables[name] = nodes.Name(name, "load")
-
- if not have_plural:
- plural_expr = None
- elif plural_expr is None:
+
+ if not have_plural:
+ plural_expr = None
+ elif plural_expr is None:
parser.fail("pluralize without variables", lineno)
-
- if trimmed is None:
+
+ if trimmed is None:
trimmed = self.environment.policies["ext.i18n.trimmed"]
- if trimmed:
- singular = self._trim_whitespace(singular)
- if plural:
- plural = self._trim_whitespace(plural)
-
+ if trimmed:
+ singular = self._trim_whitespace(singular)
+ if plural:
+ plural = self._trim_whitespace(plural)
+
node = self._make_node(
singular,
plural,
@@ -461,52 +461,52 @@ class InternationalizationExtension(Extension):
bool(referenced),
num_called_num and have_plural,
)
- node.set_lineno(lineno)
- if plural_expr_assignment is not None:
- return [plural_expr_assignment, node]
- else:
- return node
-
+ node.set_lineno(lineno)
+ if plural_expr_assignment is not None:
+ return [plural_expr_assignment, node]
+ else:
+ return node
+
def _trim_whitespace(self, string: str, _ws_re: t.Pattern[str] = _ws_re) -> str:
return _ws_re.sub(" ", string.strip())
-
+
def _parse_block(
self, parser: "Parser", allow_pluralize: bool
) -> t.Tuple[t.List[str], str]:
- """Parse until the next block tag with a given name."""
- referenced = []
- buf = []
+ """Parse until the next block tag with a given name."""
+ referenced = []
+ buf = []
while True:
if parser.stream.current.type == "data":
buf.append(parser.stream.current.value.replace("%", "%%"))
- next(parser.stream)
+ next(parser.stream)
elif parser.stream.current.type == "variable_begin":
- next(parser.stream)
+ next(parser.stream)
name = parser.stream.expect("name").value
- referenced.append(name)
+ referenced.append(name)
buf.append(f"%({name})s")
parser.stream.expect("variable_end")
elif parser.stream.current.type == "block_begin":
- next(parser.stream)
+ next(parser.stream)
if parser.stream.current.test("name:endtrans"):
- break
+ break
elif parser.stream.current.test("name:pluralize"):
- if allow_pluralize:
- break
+ if allow_pluralize:
+ break
parser.fail(
"a translatable section can have only one pluralize section"
)
parser.fail(
"control structures in translatable sections are not allowed"
)
- elif parser.stream.eos:
+ elif parser.stream.eos:
parser.fail("unclosed translation block")
- else:
+ else:
raise RuntimeError("internal parser error")
-
- return referenced, concat(buf)
-
+
+ return referenced, concat(buf)
+
def _make_node(
self,
singular: str,
@@ -516,24 +516,24 @@ class InternationalizationExtension(Extension):
vars_referenced: bool,
num_called_num: bool,
) -> nodes.Output:
- """Generates a useful node from the data provided."""
+ """Generates a useful node from the data provided."""
newstyle = self.environment.newstyle_gettext # type: ignore
node: nodes.Expr
- # no variables referenced? no need to escape for old style
- # gettext invocations only if there are vars.
+ # no variables referenced? no need to escape for old style
+ # gettext invocations only if there are vars.
if not vars_referenced and not newstyle:
singular = singular.replace("%%", "%")
- if plural:
+ if plural:
plural = plural.replace("%%", "%")
-
- # singular only:
- if plural_expr is None:
+
+ # singular only:
+ if plural_expr is None:
gettext = nodes.Name("gettext", "load")
node = nodes.Call(gettext, [nodes.Const(singular)], [], None, None)
-
- # singular and plural
- else:
+
+ # singular and plural
+ else:
ngettext = nodes.Name("ngettext", "load")
node = nodes.Call(
ngettext,
@@ -542,24 +542,24 @@ class InternationalizationExtension(Extension):
None,
None,
)
-
- # in case newstyle gettext is used, the method is powerful
- # enough to handle the variable expansion and autoescape
- # handling itself
+
+ # in case newstyle gettext is used, the method is powerful
+ # enough to handle the variable expansion and autoescape
+ # handling itself
if newstyle:
for key, value in variables.items():
- # the function adds that later anyways in case num was
- # called num, so just skip it.
+ # the function adds that later anyways in case num was
+ # called num, so just skip it.
if num_called_num and key == "num":
- continue
- node.kwargs.append(nodes.Keyword(key, value))
-
- # otherwise do that here
- else:
- # mark the return value as safe if we are in an
- # environment with autoescaping turned on
- node = nodes.MarkSafeIfAutoescape(node)
- if variables:
+ continue
+ node.kwargs.append(nodes.Keyword(key, value))
+
+ # otherwise do that here
+ else:
+ # mark the return value as safe if we are in an
+ # environment with autoescaping turned on
+ node = nodes.MarkSafeIfAutoescape(node)
+ if variables:
node = nodes.Mod(
node,
nodes.Dict(
@@ -569,35 +569,35 @@ class InternationalizationExtension(Extension):
]
),
)
- return nodes.Output([node])
-
-
-class ExprStmtExtension(Extension):
+ return nodes.Output([node])
+
+
+class ExprStmtExtension(Extension):
"""Adds a `do` tag to Jinja that works like the print statement just
- that it doesn't print the return value.
- """
-
+ that it doesn't print the return value.
+ """
+
tags = {"do"}
def parse(self, parser: "Parser") -> nodes.ExprStmt:
- node = nodes.ExprStmt(lineno=next(parser.stream).lineno)
- node.node = parser.parse_tuple()
- return node
-
-
-class LoopControlExtension(Extension):
- """Adds break and continue to the template engine."""
-
+ node = nodes.ExprStmt(lineno=next(parser.stream).lineno)
+ node.node = parser.parse_tuple()
+ return node
+
+
+class LoopControlExtension(Extension):
+ """Adds break and continue to the template engine."""
+
tags = {"break", "continue"}
def parse(self, parser: "Parser") -> t.Union[nodes.Break, nodes.Continue]:
- token = next(parser.stream)
+ token = next(parser.stream)
if token.value == "break":
- return nodes.Break(lineno=token.lineno)
- return nodes.Continue(lineno=token.lineno)
-
-
-class WithExtension(Extension):
+ return nodes.Break(lineno=token.lineno)
+ return nodes.Continue(lineno=token.lineno)
+
+
+class WithExtension(Extension):
def __init__(self, environment: Environment) -> None:
super().__init__(environment)
warnings.warn(
@@ -606,9 +606,9 @@ class WithExtension(Extension):
DeprecationWarning,
stacklevel=3,
)
-
-
-class AutoEscapeExtension(Extension):
+
+
+class AutoEscapeExtension(Extension):
def __init__(self, environment: Environment) -> None:
super().__init__(environment)
warnings.warn(
@@ -617,8 +617,8 @@ class AutoEscapeExtension(Extension):
DeprecationWarning,
stacklevel=3,
)
-
-
+
+
class DebugExtension(Extension):
"""A ``{% debug %}`` tag that dumps the available variables,
filters, and tests.
@@ -666,40 +666,40 @@ def extract_from_ast(
) -> t.Iterator[
t.Tuple[int, str, t.Union[t.Optional[str], t.Tuple[t.Optional[str], ...]]]
]:
- """Extract localizable strings from the given template node. Per
- default this function returns matches in babel style that means non string
- parameters as well as keyword arguments are returned as `None`. This
- allows Babel to figure out what you really meant if you are using
- gettext functions that allow keyword arguments for placeholder expansion.
- If you don't want that behavior set the `babel_style` parameter to `False`
- which causes only strings to be returned and parameters are always stored
- in tuples. As a consequence invalid gettext calls (calls without a single
- string parameter or string parameters after non-string parameters) are
- skipped.
-
- This example explains the behavior:
-
- >>> from jinja2 import Environment
- >>> env = Environment()
- >>> node = env.parse('{{ (_("foo"), _(), ngettext("foo", "bar", 42)) }}')
- >>> list(extract_from_ast(node))
- [(1, '_', 'foo'), (1, '_', ()), (1, 'ngettext', ('foo', 'bar', None))]
- >>> list(extract_from_ast(node, babel_style=False))
- [(1, '_', ('foo',)), (1, 'ngettext', ('foo', 'bar'))]
-
- For every string found this function yields a ``(lineno, function,
- message)`` tuple, where:
-
- * ``lineno`` is the number of the line on which the string was found,
- * ``function`` is the name of the ``gettext`` function used (if the
- string was extracted from embedded Python code), and
+ """Extract localizable strings from the given template node. Per
+ default this function returns matches in babel style that means non string
+ parameters as well as keyword arguments are returned as `None`. This
+ allows Babel to figure out what you really meant if you are using
+ gettext functions that allow keyword arguments for placeholder expansion.
+ If you don't want that behavior set the `babel_style` parameter to `False`
+ which causes only strings to be returned and parameters are always stored
+ in tuples. As a consequence invalid gettext calls (calls without a single
+ string parameter or string parameters after non-string parameters) are
+ skipped.
+
+ This example explains the behavior:
+
+ >>> from jinja2 import Environment
+ >>> env = Environment()
+ >>> node = env.parse('{{ (_("foo"), _(), ngettext("foo", "bar", 42)) }}')
+ >>> list(extract_from_ast(node))
+ [(1, '_', 'foo'), (1, '_', ()), (1, 'ngettext', ('foo', 'bar', None))]
+ >>> list(extract_from_ast(node, babel_style=False))
+ [(1, '_', ('foo',)), (1, 'ngettext', ('foo', 'bar'))]
+
+ For every string found this function yields a ``(lineno, function,
+ message)`` tuple, where:
+
+ * ``lineno`` is the number of the line on which the string was found,
+ * ``function`` is the name of the ``gettext`` function used (if the
+ string was extracted from embedded Python code), and
* ``message`` is the string, or a tuple of strings for functions
with multiple string arguments.
-
- This extraction function operates on the AST and is because of that unable
- to extract any comments. For comment support you have to use the babel
- extraction interface or extract comments yourself.
- """
+
+ This extraction function operates on the AST and is because of that unable
+ to extract any comments. For comment support you have to use the babel
+ extraction interface or extract comments yourself.
+ """
out: t.Union[t.Optional[str], t.Tuple[t.Optional[str], ...]]
for node in ast.find_all(nodes.Call):
@@ -707,77 +707,77 @@ def extract_from_ast(
not isinstance(node.node, nodes.Name)
or node.node.name not in gettext_functions
):
- continue
-
+ continue
+
strings: t.List[t.Optional[str]] = []
- for arg in node.args:
+ for arg in node.args:
if isinstance(arg, nodes.Const) and isinstance(arg.value, str):
- strings.append(arg.value)
- else:
- strings.append(None)
-
+ strings.append(arg.value)
+ else:
+ strings.append(None)
+
for _ in node.kwargs:
- strings.append(None)
- if node.dyn_args is not None:
- strings.append(None)
- if node.dyn_kwargs is not None:
- strings.append(None)
-
- if not babel_style:
+ strings.append(None)
+ if node.dyn_args is not None:
+ strings.append(None)
+ if node.dyn_kwargs is not None:
+ strings.append(None)
+
+ if not babel_style:
out = tuple(x for x in strings if x is not None)
if not out:
- continue
- else:
- if len(strings) == 1:
+ continue
+ else:
+ if len(strings) == 1:
out = strings[0]
- else:
+ else:
out = tuple(strings)
-
+
yield node.lineno, node.node.name, out
-
+
class _CommentFinder:
- """Helper class to find comments in a token stream. Can only
- find comments for gettext calls forwards. Once the comment
- from line 4 is found, a comment for line 1 will not return a
- usable value.
- """
-
+ """Helper class to find comments in a token stream. Can only
+ find comments for gettext calls forwards. Once the comment
+ from line 4 is found, a comment for line 1 will not return a
+ usable value.
+ """
+
def __init__(
self, tokens: t.Sequence[t.Tuple[int, str, str]], comment_tags: t.Sequence[str]
) -> None:
- self.tokens = tokens
- self.comment_tags = comment_tags
- self.offset = 0
- self.last_lineno = 0
-
+ self.tokens = tokens
+ self.comment_tags = comment_tags
+ self.offset = 0
+ self.last_lineno = 0
+
def find_backwards(self, offset: int) -> t.List[str]:
- try:
+ try:
for _, token_type, token_value in reversed(
self.tokens[self.offset : offset]
):
if token_type in ("comment", "linecomment"):
- try:
- prefix, comment = token_value.split(None, 1)
- except ValueError:
- continue
- if prefix in self.comment_tags:
- return [comment.rstrip()]
- return []
- finally:
- self.offset = offset
-
+ try:
+ prefix, comment = token_value.split(None, 1)
+ except ValueError:
+ continue
+ if prefix in self.comment_tags:
+ return [comment.rstrip()]
+ return []
+ finally:
+ self.offset = offset
+
def find_comments(self, lineno: int) -> t.List[str]:
- if not self.comment_tags or self.last_lineno > lineno:
- return []
+ if not self.comment_tags or self.last_lineno > lineno:
+ return []
for idx, (token_lineno, _, _) in enumerate(self.tokens[self.offset :]):
- if token_lineno > lineno:
- return self.find_backwards(self.offset + idx)
- return self.find_backwards(len(self.tokens))
-
-
+ if token_lineno > lineno:
+ return self.find_backwards(self.offset + idx)
+ return self.find_backwards(len(self.tokens))
+
+
def babel_extract(
fileobj: t.BinaryIO,
keywords: t.Sequence[str],
@@ -788,51 +788,51 @@ def babel_extract(
int, str, t.Union[t.Optional[str], t.Tuple[t.Optional[str], ...]], t.List[str]
]
]:
- """Babel extraction method for Jinja templates.
-
- .. versionchanged:: 2.3
- Basic support for translation comments was added. If `comment_tags`
- is now set to a list of keywords for extraction, the extractor will
+ """Babel extraction method for Jinja templates.
+
+ .. versionchanged:: 2.3
+ Basic support for translation comments was added. If `comment_tags`
+ is now set to a list of keywords for extraction, the extractor will
try to find the best preceding comment that begins with one of the
- keywords. For best results, make sure to not have more than one
- gettext call in one line of code and the matching comment in the
- same line or the line before.
-
- .. versionchanged:: 2.5.1
- The `newstyle_gettext` flag can be set to `True` to enable newstyle
- gettext calls.
-
- .. versionchanged:: 2.7
- A `silent` option can now be provided. If set to `False` template
- syntax errors are propagated instead of being ignored.
-
- :param fileobj: the file-like object the messages should be extracted from
- :param keywords: a list of keywords (i.e. function names) that should be
- recognized as translation functions
- :param comment_tags: a list of translator tags to search for and include
- in the results.
- :param options: a dictionary of additional options (optional)
- :return: an iterator over ``(lineno, funcname, message, comments)`` tuples.
- (comments will be empty currently)
- """
+ keywords. For best results, make sure to not have more than one
+ gettext call in one line of code and the matching comment in the
+ same line or the line before.
+
+ .. versionchanged:: 2.5.1
+ The `newstyle_gettext` flag can be set to `True` to enable newstyle
+ gettext calls.
+
+ .. versionchanged:: 2.7
+ A `silent` option can now be provided. If set to `False` template
+ syntax errors are propagated instead of being ignored.
+
+ :param fileobj: the file-like object the messages should be extracted from
+ :param keywords: a list of keywords (i.e. function names) that should be
+ recognized as translation functions
+ :param comment_tags: a list of translator tags to search for and include
+ in the results.
+ :param options: a dictionary of additional options (optional)
+ :return: an iterator over ``(lineno, funcname, message, comments)`` tuples.
+ (comments will be empty currently)
+ """
extensions: t.Dict[t.Type[Extension], None] = {}
for extension_name in options.get("extensions", "").split(","):
extension_name = extension_name.strip()
if not extension_name:
- continue
+ continue
extensions[import_string(extension_name)] = None
- if InternationalizationExtension not in extensions:
+ if InternationalizationExtension not in extensions:
extensions[InternationalizationExtension] = None
-
+
def getbool(options: t.Mapping[str, str], key: str, default: bool = False) -> bool:
return options.get(key, str(default)).lower() in {"1", "on", "yes", "true"}
-
+
silent = getbool(options, "silent", True)
- environment = Environment(
+ environment = Environment(
options.get("block_start_string", defaults.BLOCK_START_STRING),
options.get("block_end_string", defaults.BLOCK_END_STRING),
options.get("variable_start_string", defaults.VARIABLE_START_STRING),
@@ -846,34 +846,34 @@ def babel_extract(
defaults.NEWLINE_SEQUENCE,
getbool(options, "keep_trailing_newline", defaults.KEEP_TRAILING_NEWLINE),
tuple(extensions),
- cache_size=0,
+ cache_size=0,
auto_reload=False,
- )
-
+ )
+
if getbool(options, "trimmed"):
environment.policies["ext.i18n.trimmed"] = True
if getbool(options, "newstyle_gettext"):
environment.newstyle_gettext = True # type: ignore
-
+
source = fileobj.read().decode(options.get("encoding", "utf-8"))
- try:
- node = environment.parse(source)
- tokens = list(environment.lex(environment.preprocess(source)))
+ try:
+ node = environment.parse(source)
+ tokens = list(environment.lex(environment.preprocess(source)))
except TemplateSyntaxError:
- if not silent:
- raise
- # skip templates with syntax errors
- return
-
- finder = _CommentFinder(tokens, comment_tags)
- for lineno, func, message in extract_from_ast(node, keywords):
- yield lineno, func, message, finder.find_comments(lineno)
-
-
-#: nicer import names
-i18n = InternationalizationExtension
-do = ExprStmtExtension
-loopcontrols = LoopControlExtension
-with_ = WithExtension
-autoescape = AutoEscapeExtension
+ if not silent:
+ raise
+ # skip templates with syntax errors
+ return
+
+ finder = _CommentFinder(tokens, comment_tags)
+ for lineno, func, message in extract_from_ast(node, keywords):
+ yield lineno, func, message, finder.find_comments(lineno)
+
+
+#: nicer import names
+i18n = InternationalizationExtension
+do = ExprStmtExtension
+loopcontrols = LoopControlExtension
+with_ = WithExtension
+autoescape = AutoEscapeExtension
debug = DebugExtension
diff --git a/contrib/python/Jinja2/py3/jinja2/filters.py b/contrib/python/Jinja2/py3/jinja2/filters.py
index ffb98bf4e3..7c91895f49 100644
--- a/contrib/python/Jinja2/py3/jinja2/filters.py
+++ b/contrib/python/Jinja2/py3/jinja2/filters.py
@@ -1,18 +1,18 @@
"""Built-in template filters used with the ``|`` operator."""
-import math
-import random
+import math
+import random
import re
import typing
import typing as t
-import warnings
+import warnings
from collections import abc
from itertools import chain
from itertools import groupby
-
+
from markupsafe import escape
from markupsafe import Markup
from markupsafe import soft_str
-
+
from .async_utils import async_variant
from .async_utils import auto_aiter
from .async_utils import auto_await
@@ -26,14 +26,14 @@ from .utils import pass_eval_context
from .utils import pformat
from .utils import url_quote
from .utils import urlize
-
+
if t.TYPE_CHECKING:
import typing_extensions as te
from .environment import Environment
from .nodes import EvalContext
from .runtime import Context
from .sandbox import SandboxedEnvironment # noqa: F401
-
+
class HasHTML(te.Protocol):
def __html__(self) -> str:
pass
@@ -50,7 +50,7 @@ def contextfilter(f: F) -> F:
.. deprecated:: 3.0
Will be removed in Jinja 3.1. Use :func:`~jinja2.pass_context`
instead.
- """
+ """
warnings.warn(
"'contextfilter' is renamed to 'pass_context', the old name"
" will be removed in Jinja 3.1.",
@@ -58,18 +58,18 @@ def contextfilter(f: F) -> F:
stacklevel=2,
)
return pass_context(f)
-
-
+
+
def evalcontextfilter(f: F) -> F:
"""Pass the eval context as the first argument to the decorated
function.
-
+
.. deprecated:: 3.0
Will be removed in Jinja 3.1. Use
:func:`~jinja2.pass_eval_context` instead.
- .. versionadded:: 2.4
- """
+ .. versionadded:: 2.4
+ """
warnings.warn(
"'evalcontextfilter' is renamed to 'pass_eval_context', the old"
" name will be removed in Jinja 3.1.",
@@ -77,8 +77,8 @@ def evalcontextfilter(f: F) -> F:
stacklevel=2,
)
return pass_eval_context(f)
-
-
+
+
def environmentfilter(f: F) -> F:
"""Pass the environment as the first argument to the decorated
function.
@@ -86,7 +86,7 @@ def environmentfilter(f: F) -> F:
.. deprecated:: 3.0
Will be removed in Jinja 3.1. Use
:func:`~jinja2.pass_environment` instead.
- """
+ """
warnings.warn(
"'environmentfilter' is renamed to 'pass_environment', the old"
" name will be removed in Jinja 3.1.",
@@ -94,16 +94,16 @@ def environmentfilter(f: F) -> F:
stacklevel=2,
)
return pass_environment(f)
-
-
+
+
def ignore_case(value: V) -> V:
- """For use as a postprocessor for :func:`make_attrgetter`. Converts strings
- to lowercase and returns other types as-is."""
+ """For use as a postprocessor for :func:`make_attrgetter`. Converts strings
+ to lowercase and returns other types as-is."""
if isinstance(value, str):
return t.cast(V, value.lower())
-
+
return value
-
+
def make_attrgetter(
environment: "Environment",
@@ -111,28 +111,28 @@ def make_attrgetter(
postprocess: t.Optional[t.Callable[[t.Any], t.Any]] = None,
default: t.Optional[t.Any] = None,
) -> t.Callable[[t.Any], t.Any]:
- """Returns a callable that looks up the given attribute from a
- passed object with the rules of the environment. Dots are allowed
- to access attributes of attributes. Integer parts in paths are
- looked up as integers.
- """
+ """Returns a callable that looks up the given attribute from a
+ passed object with the rules of the environment. Dots are allowed
+ to access attributes of attributes. Integer parts in paths are
+ looked up as integers.
+ """
parts = _prepare_attribute_parts(attribute)
-
+
def attrgetter(item: t.Any) -> t.Any:
for part in parts:
- item = environment.getitem(item, part)
-
+ item = environment.getitem(item, part)
+
if default is not None and isinstance(item, Undefined):
item = default
- if postprocess is not None:
- item = postprocess(item)
-
- return item
-
- return attrgetter
-
-
+ if postprocess is not None:
+ item = postprocess(item)
+
+ return item
+
+ return attrgetter
+
+
def make_multi_attrgetter(
environment: "Environment",
attribute: t.Optional[t.Union[str, int]],
@@ -187,18 +187,18 @@ def _prepare_attribute_parts(
def do_forceescape(value: "t.Union[str, HasHTML]") -> Markup:
- """Enforce HTML escaping. This will probably double escape variables."""
+ """Enforce HTML escaping. This will probably double escape variables."""
if hasattr(value, "__html__"):
value = t.cast("HasHTML", value).__html__()
-
+
return escape(str(value))
-
+
def do_urlencode(
value: t.Union[str, t.Mapping[str, t.Any], t.Iterable[t.Tuple[str, t.Any]]]
) -> str:
"""Quote data for use in a URL path or query using UTF-8.
-
+
Basic wrapper around :func:`urllib.parse.quote` when given a
string, or :func:`urllib.parse.urlencode` for a dict or iterable.
@@ -210,16 +210,16 @@ def do_urlencode(
"%2F" equivalently in paths. If you need quoted slashes, use the
``|replace("/", "%2F")`` filter.
- .. versionadded:: 2.7
- """
+ .. versionadded:: 2.7
+ """
if isinstance(value, str) or not isinstance(value, abc.Iterable):
return url_quote(value)
-
+
if isinstance(value, dict):
items: t.Iterable[t.Tuple[str, t.Any]] = value.items()
else:
items = value # type: ignore
-
+
return "&".join(
f"{url_quote(k, for_qs=True)}={url_quote(v, for_qs=True)}" for k, v in items
)
@@ -229,24 +229,24 @@ def do_urlencode(
def do_replace(
eval_ctx: "EvalContext", s: str, old: str, new: str, count: t.Optional[int] = None
) -> str:
- """Return a copy of the value with all occurrences of a substring
- replaced with a new one. The first argument is the substring
- that should be replaced, the second is the replacement string.
- If the optional third argument ``count`` is given, only the first
- ``count`` occurrences are replaced:
-
- .. sourcecode:: jinja
-
- {{ "Hello World"|replace("Hello", "Goodbye") }}
- -> Goodbye World
-
- {{ "aaaaargh"|replace("a", "d'oh, ", 2) }}
- -> d'oh, d'oh, aaargh
- """
- if count is None:
- count = -1
-
- if not eval_ctx.autoescape:
+ """Return a copy of the value with all occurrences of a substring
+ replaced with a new one. The first argument is the substring
+ that should be replaced, the second is the replacement string.
+ If the optional third argument ``count`` is given, only the first
+ ``count`` occurrences are replaced:
+
+ .. sourcecode:: jinja
+
+ {{ "Hello World"|replace("Hello", "Goodbye") }}
+ -> Goodbye World
+
+ {{ "aaaaargh"|replace("a", "d'oh, ", 2) }}
+ -> d'oh, d'oh, aaargh
+ """
+ if count is None:
+ count = -1
+
+ if not eval_ctx.autoescape:
return str(s).replace(str(old), str(new), count)
if (
@@ -254,78 +254,78 @@ def do_replace(
or hasattr(new, "__html__")
and not hasattr(s, "__html__")
):
- s = escape(s)
- else:
+ s = escape(s)
+ else:
s = soft_str(s)
-
+
return s.replace(soft_str(old), soft_str(new), count)
-
+
def do_upper(s: str) -> str:
- """Convert a value to uppercase."""
+ """Convert a value to uppercase."""
return soft_str(s).upper()
-
-
+
+
def do_lower(s: str) -> str:
- """Convert a value to lowercase."""
+ """Convert a value to lowercase."""
return soft_str(s).lower()
-
-
+
+
@pass_eval_context
def do_xmlattr(
eval_ctx: "EvalContext", d: t.Mapping[str, t.Any], autospace: bool = True
) -> str:
- """Create an SGML/XML attribute string based on the items in a dict.
- All values that are neither `none` nor `undefined` are automatically
- escaped:
-
- .. sourcecode:: html+jinja
-
- <ul{{ {'class': 'my_list', 'missing': none,
- 'id': 'list-%d'|format(variable)}|xmlattr }}>
- ...
- </ul>
-
- Results in something like this:
-
- .. sourcecode:: html
-
- <ul class="my_list" id="list-42">
- ...
- </ul>
-
- As you can see it automatically prepends a space in front of the item
- if the filter returned something unless the second parameter is false.
- """
+ """Create an SGML/XML attribute string based on the items in a dict.
+ All values that are neither `none` nor `undefined` are automatically
+ escaped:
+
+ .. sourcecode:: html+jinja
+
+ <ul{{ {'class': 'my_list', 'missing': none,
+ 'id': 'list-%d'|format(variable)}|xmlattr }}>
+ ...
+ </ul>
+
+ Results in something like this:
+
+ .. sourcecode:: html
+
+ <ul class="my_list" id="list-42">
+ ...
+ </ul>
+
+ As you can see it automatically prepends a space in front of the item
+ if the filter returned something unless the second parameter is false.
+ """
rv = " ".join(
f'{escape(key)}="{escape(value)}"'
for key, value in d.items()
- if value is not None and not isinstance(value, Undefined)
- )
+ if value is not None and not isinstance(value, Undefined)
+ )
- if autospace and rv:
+ if autospace and rv:
rv = " " + rv
if eval_ctx.autoescape:
- rv = Markup(rv)
-
- return rv
-
+ rv = Markup(rv)
+ return rv
+
+
def do_capitalize(s: str) -> str:
- """Capitalize a value. The first character will be uppercase, all others
- lowercase.
- """
+ """Capitalize a value. The first character will be uppercase, all others
+ lowercase.
+ """
return soft_str(s).capitalize()
-
-
+
+
_word_beginning_split_re = re.compile(r"([-\s({\[<]+)")
def do_title(s: str) -> str:
- """Return a titlecased version of the value. I.e. words will start with
- uppercase letters, all remaining characters are lowercase.
- """
+ """Return a titlecased version of the value. I.e. words will start with
+ uppercase letters, all remaining characters are lowercase.
+ """
return "".join(
[
item[0].upper() + item[1:].lower()
@@ -333,8 +333,8 @@ def do_title(s: str) -> str:
if item
]
)
-
-
+
+
def do_dictsort(
value: t.Mapping[K, V],
case_sensitive: bool = False,
@@ -343,39 +343,39 @@ def do_dictsort(
) -> t.List[t.Tuple[K, V]]:
"""Sort a dict and yield (key, value) pairs. Python dicts may not
be in the order you want to display them in, so sort them first.
-
- .. sourcecode:: jinja
-
+
+ .. sourcecode:: jinja
+
{% for key, value in mydict|dictsort %}
- sort the dict by key, case insensitive
-
+ sort the dict by key, case insensitive
+
{% for key, value in mydict|dictsort(reverse=true) %}
- sort the dict by key, case insensitive, reverse order
-
+ sort the dict by key, case insensitive, reverse order
+
{% for key, value in mydict|dictsort(true) %}
- sort the dict by key, case sensitive
-
+ sort the dict by key, case sensitive
+
{% for key, value in mydict|dictsort(false, 'value') %}
- sort the dict by value, case insensitive
- """
+ sort the dict by value, case insensitive
+ """
if by == "key":
- pos = 0
+ pos = 0
elif by == "value":
- pos = 1
- else:
+ pos = 1
+ else:
raise FilterArgumentError('You can only sort by either "key" or "value"')
-
+
def sort_func(item: t.Tuple[t.Any, t.Any]) -> t.Any:
- value = item[pos]
-
- if not case_sensitive:
- value = ignore_case(value)
-
- return value
-
- return sorted(value.items(), key=sort_func, reverse=reverse)
-
-
+ value = item[pos]
+
+ if not case_sensitive:
+ value = ignore_case(value)
+
+ return value
+
+ return sorted(value.items(), key=sort_func, reverse=reverse)
+
+
@pass_environment
def do_sort(
environment: "Environment",
@@ -385,9 +385,9 @@ def do_sort(
attribute: t.Optional[t.Union[str, int]] = None,
) -> "t.List[V]":
"""Sort an iterable using Python's :func:`sorted`.
-
+
.. sourcecode:: jinja
-
+
{% for city in cities|sort %}
...
{% endfor %}
@@ -403,35 +403,35 @@ def do_sort(
elements that compare equal. This makes it is possible to chain
sorts on different attributes and ordering.
- .. sourcecode:: jinja
-
+ .. sourcecode:: jinja
+
{% for user in users|sort(attribute="name")
|sort(reverse=true, attribute="age") %}
- ...
- {% endfor %}
-
+ ...
+ {% endfor %}
+
As a shortcut to chaining when the direction is the same for all
attributes, pass a comma separate list of attributes.
-
- .. sourcecode:: jinja
-
+
+ .. sourcecode:: jinja
+
{% for user users|sort(attribute="age,name") %}
- ...
- {% endfor %}
-
+ ...
+ {% endfor %}
+
.. versionchanged:: 2.11.0
The ``attribute`` parameter can be a comma separated list of
attributes, e.g. ``"age,name"``.
- .. versionchanged:: 2.6
+ .. versionchanged:: 2.6
The ``attribute`` parameter was added.
- """
+ """
key_func = make_multi_attrgetter(
environment, attribute, postprocess=ignore_case if not case_sensitive else None
- )
- return sorted(value, key=key_func, reverse=reverse)
-
-
+ )
+ return sorted(value, key=key_func, reverse=reverse)
+
+
@pass_environment
def do_unique(
environment: "Environment",
@@ -440,31 +440,31 @@ def do_unique(
attribute: t.Optional[t.Union[str, int]] = None,
) -> "t.Iterator[V]":
"""Returns a list of unique items from the given iterable.
-
- .. sourcecode:: jinja
-
+
+ .. sourcecode:: jinja
+
{{ ['foo', 'bar', 'foobar', 'FooBar']|unique|list }}
- -> ['foo', 'bar', 'foobar']
-
- The unique items are yielded in the same order as their first occurrence in
- the iterable passed to the filter.
-
- :param case_sensitive: Treat upper and lower case strings as distinct.
- :param attribute: Filter objects with unique values for this attribute.
- """
- getter = make_attrgetter(
+ -> ['foo', 'bar', 'foobar']
+
+ The unique items are yielded in the same order as their first occurrence in
+ the iterable passed to the filter.
+
+ :param case_sensitive: Treat upper and lower case strings as distinct.
+ :param attribute: Filter objects with unique values for this attribute.
+ """
+ getter = make_attrgetter(
environment, attribute, postprocess=ignore_case if not case_sensitive else None
- )
- seen = set()
-
- for item in value:
- key = getter(item)
-
- if key not in seen:
- seen.add(key)
- yield item
-
-
+ )
+ seen = set()
+
+ for item in value:
+ key = getter(item)
+
+ if key not in seen:
+ seen.add(key)
+ yield item
+
+
def _min_or_max(
environment: "Environment",
value: "t.Iterable[V]",
@@ -472,19 +472,19 @@ def _min_or_max(
case_sensitive: bool,
attribute: t.Optional[t.Union[str, int]],
) -> "t.Union[V, Undefined]":
- it = iter(value)
-
- try:
- first = next(it)
- except StopIteration:
+ it = iter(value)
+
+ try:
+ first = next(it)
+ except StopIteration:
return environment.undefined("No aggregated item, sequence was empty.")
-
- key_func = make_attrgetter(
+
+ key_func = make_attrgetter(
environment, attribute, postprocess=ignore_case if not case_sensitive else None
- )
- return func(chain([first], it), key=key_func)
-
-
+ )
+ return func(chain([first], it), key=key_func)
+
+
@pass_environment
def do_min(
environment: "Environment",
@@ -492,19 +492,19 @@ def do_min(
case_sensitive: bool = False,
attribute: t.Optional[t.Union[str, int]] = None,
) -> "t.Union[V, Undefined]":
- """Return the smallest item from the sequence.
-
- .. sourcecode:: jinja
-
- {{ [1, 2, 3]|min }}
- -> 1
-
- :param case_sensitive: Treat upper and lower case strings as distinct.
+ """Return the smallest item from the sequence.
+
+ .. sourcecode:: jinja
+
+ {{ [1, 2, 3]|min }}
+ -> 1
+
+ :param case_sensitive: Treat upper and lower case strings as distinct.
:param attribute: Get the object with the min value of this attribute.
- """
- return _min_or_max(environment, value, min, case_sensitive, attribute)
-
-
+ """
+ return _min_or_max(environment, value, min, case_sensitive, attribute)
+
+
@pass_environment
def do_max(
environment: "Environment",
@@ -512,52 +512,52 @@ def do_max(
case_sensitive: bool = False,
attribute: t.Optional[t.Union[str, int]] = None,
) -> "t.Union[V, Undefined]":
- """Return the largest item from the sequence.
-
- .. sourcecode:: jinja
-
- {{ [1, 2, 3]|max }}
- -> 3
-
- :param case_sensitive: Treat upper and lower case strings as distinct.
- :param attribute: Get the object with the max value of this attribute.
- """
- return _min_or_max(environment, value, max, case_sensitive, attribute)
-
-
+ """Return the largest item from the sequence.
+
+ .. sourcecode:: jinja
+
+ {{ [1, 2, 3]|max }}
+ -> 3
+
+ :param case_sensitive: Treat upper and lower case strings as distinct.
+ :param attribute: Get the object with the max value of this attribute.
+ """
+ return _min_or_max(environment, value, max, case_sensitive, attribute)
+
+
def do_default(
value: V,
default_value: V = "", # type: ignore
boolean: bool = False,
) -> V:
- """If the value is undefined it will return the passed default value,
- otherwise the value of the variable:
-
- .. sourcecode:: jinja
-
- {{ my_variable|default('my_variable is not defined') }}
-
- This will output the value of ``my_variable`` if the variable was
- defined, otherwise ``'my_variable is not defined'``. If you want
- to use default with variables that evaluate to false you have to
- set the second parameter to `true`:
-
- .. sourcecode:: jinja
-
- {{ ''|default('the string was empty', true) }}
+ """If the value is undefined it will return the passed default value,
+ otherwise the value of the variable:
+
+ .. sourcecode:: jinja
+
+ {{ my_variable|default('my_variable is not defined') }}
+
+ This will output the value of ``my_variable`` if the variable was
+ defined, otherwise ``'my_variable is not defined'``. If you want
+ to use default with variables that evaluate to false you have to
+ set the second parameter to `true`:
+
+ .. sourcecode:: jinja
+
+ {{ ''|default('the string was empty', true) }}
.. versionchanged:: 2.11
It's now possible to configure the :class:`~jinja2.Environment` with
:class:`~jinja2.ChainableUndefined` to make the `default` filter work
on nested elements and attributes that may contain undefined values
in the chain without getting an :exc:`~jinja2.UndefinedError`.
- """
- if isinstance(value, Undefined) or (boolean and not value):
- return default_value
-
- return value
-
+ """
+ if isinstance(value, Undefined) or (boolean and not value):
+ return default_value
+ return value
+
+
@pass_eval_context
def sync_do_join(
eval_ctx: "EvalContext",
@@ -565,57 +565,57 @@ def sync_do_join(
d: str = "",
attribute: t.Optional[t.Union[str, int]] = None,
) -> str:
- """Return a string which is the concatenation of the strings in the
- sequence. The separator between elements is an empty string per
- default, you can define it with the optional parameter:
-
- .. sourcecode:: jinja
-
- {{ [1, 2, 3]|join('|') }}
- -> 1|2|3
-
- {{ [1, 2, 3]|join }}
- -> 123
-
- It is also possible to join certain attributes of an object:
-
- .. sourcecode:: jinja
-
- {{ users|join(', ', attribute='username') }}
-
- .. versionadded:: 2.6
- The `attribute` parameter was added.
- """
- if attribute is not None:
+ """Return a string which is the concatenation of the strings in the
+ sequence. The separator between elements is an empty string per
+ default, you can define it with the optional parameter:
+
+ .. sourcecode:: jinja
+
+ {{ [1, 2, 3]|join('|') }}
+ -> 1|2|3
+
+ {{ [1, 2, 3]|join }}
+ -> 123
+
+ It is also possible to join certain attributes of an object:
+
+ .. sourcecode:: jinja
+
+ {{ users|join(', ', attribute='username') }}
+
+ .. versionadded:: 2.6
+ The `attribute` parameter was added.
+ """
+ if attribute is not None:
value = map(make_attrgetter(eval_ctx.environment, attribute), value)
-
+
# no automatic escaping? joining is a lot easier then
- if not eval_ctx.autoescape:
+ if not eval_ctx.autoescape:
return str(d).join(map(str, value))
-
- # if the delimiter doesn't have an html representation we check
- # if any of the items has. If yes we do a coercion to Markup
+
+ # if the delimiter doesn't have an html representation we check
+ # if any of the items has. If yes we do a coercion to Markup
if not hasattr(d, "__html__"):
- value = list(value)
- do_escape = False
+ value = list(value)
+ do_escape = False
- for idx, item in enumerate(value):
+ for idx, item in enumerate(value):
if hasattr(item, "__html__"):
- do_escape = True
- else:
+ do_escape = True
+ else:
value[idx] = str(item)
- if do_escape:
- d = escape(d)
- else:
+ if do_escape:
+ d = escape(d)
+ else:
d = str(d)
- return d.join(value)
-
- # no html involved, to normal joining
+ return d.join(value)
+
+ # no html involved, to normal joining
return soft_str(d).join(map(soft_str, value))
-
-
+
+
@async_variant(sync_do_join) # type: ignore
async def do_join(
eval_ctx: "EvalContext",
@@ -627,21 +627,21 @@ async def do_join(
def do_center(value: str, width: int = 80) -> str:
- """Centers the value in a field of a given width."""
+ """Centers the value in a field of a given width."""
return soft_str(value).center(width)
-
-
+
+
@pass_environment
def sync_do_first(
environment: "Environment", seq: "t.Iterable[V]"
) -> "t.Union[V, Undefined]":
- """Return the first item of a sequence."""
- try:
- return next(iter(seq))
- except StopIteration:
+ """Return the first item of a sequence."""
+ try:
+ return next(iter(seq))
+ except StopIteration:
return environment.undefined("No first item, sequence was empty.")
-
-
+
+
@async_variant(sync_do_first) # type: ignore
async def do_first(
environment: "Environment", seq: "t.Union[t.AsyncIterable[V], t.Iterable[V]]"
@@ -665,33 +665,33 @@ def do_last(
{{ data | selectattr('name', '==', 'Jinja') | list | last }}
"""
- try:
- return next(iter(reversed(seq)))
- except StopIteration:
+ try:
+ return next(iter(reversed(seq)))
+ except StopIteration:
return environment.undefined("No last item, sequence was empty.")
-
-
+
+
# No async do_last, it may not be safe in async mode.
@pass_context
def do_random(context: "Context", seq: "t.Sequence[V]") -> "t.Union[V, Undefined]":
- """Return a random item from the sequence."""
- try:
- return random.choice(seq)
- except IndexError:
+ """Return a random item from the sequence."""
+ try:
+ return random.choice(seq)
+ except IndexError:
return context.environment.undefined("No random item, sequence was empty.")
-
-
+
+
def do_filesizeformat(value: t.Union[str, float, int], binary: bool = False) -> str:
- """Format the value like a 'human-readable' file size (i.e. 13 kB,
- 4.1 MB, 102 Bytes, etc). Per default decimal prefixes are used (Mega,
- Giga, etc.), if the second parameter is set to `True` the binary
- prefixes are used (Mebi, Gibi).
- """
- bytes = float(value)
+ """Format the value like a 'human-readable' file size (i.e. 13 kB,
+ 4.1 MB, 102 Bytes, etc). Per default decimal prefixes are used (Mega,
+ Giga, etc.), if the second parameter is set to `True` the binary
+ prefixes are used (Mebi, Gibi).
+ """
+ bytes = float(value)
base = 1024 if binary else 1000
- prefixes = [
+ prefixes = [
("KiB" if binary else "kB"),
("MiB" if binary else "MB"),
("GiB" if binary else "GB"),
@@ -700,27 +700,27 @@ def do_filesizeformat(value: t.Union[str, float, int], binary: bool = False) ->
("EiB" if binary else "EB"),
("ZiB" if binary else "ZB"),
("YiB" if binary else "YB"),
- ]
+ ]
- if bytes == 1:
+ if bytes == 1:
return "1 Byte"
- elif bytes < base:
+ elif bytes < base:
return f"{int(bytes)} Bytes"
- else:
- for i, prefix in enumerate(prefixes):
- unit = base ** (i + 2)
+ else:
+ for i, prefix in enumerate(prefixes):
+ unit = base ** (i + 2)
- if bytes < unit:
+ if bytes < unit:
return f"{base * bytes / unit:.1f} {prefix}"
-
+
return f"{base * bytes / unit:.1f} {prefix}"
-
-
+
+
def do_pprint(value: t.Any) -> str:
"""Pretty print a variable. Useful for debugging."""
return pformat(value)
-
-
+
+
_uri_scheme_re = re.compile(r"^([\w.+-]{2,}:(/){0,2})$")
@@ -735,18 +735,18 @@ def do_urlize(
extra_schemes: t.Optional[t.Iterable[str]] = None,
) -> str:
"""Convert URLs in text into clickable links.
-
+
This may not recognize links in some situations. Usually, a more
comprehensive formatter, such as a Markdown library, is a better
choice.
-
+
Works on ``http://``, ``https://``, ``www.``, ``mailto:``, and email
addresses. Links with trailing punctuation (periods, commas, closing
parentheses) and leading punctuation (opening parentheses) are
recognized excluding the punctuation. Email addresses that include
header fields are not recognized (for example,
``mailto:address@example.com?cc=copy@example.com``).
-
+
:param value: Original text containing URLs to link.
:param trim_url_limit: Shorten displayed URL values to this length.
:param nofollow: Add the ``rel=nofollow`` attribute to links.
@@ -756,31 +756,31 @@ def do_urlize(
in addition to the default behavior. Defaults to
``env.policies["urlize.extra_schemes"]``, which defaults to no
extra schemes.
-
+
.. versionchanged:: 3.0
The ``extra_schemes`` parameter was added.
-
+
.. versionchanged:: 3.0
Generate ``https://`` links for URLs without a scheme.
-
+
.. versionchanged:: 3.0
The parsing rules were updated. Recognize email addresses with
or without the ``mailto:`` scheme. Validate IP addresses. Ignore
parentheses and brackets in more cases.
-
+
.. versionchanged:: 2.8
The ``target`` parameter was added.
- """
- policies = eval_ctx.environment.policies
+ """
+ policies = eval_ctx.environment.policies
rel_parts = set((rel or "").split())
- if nofollow:
+ if nofollow:
rel_parts.add("nofollow")
rel_parts.update((policies["urlize.rel"] or "").split())
rel = " ".join(sorted(rel_parts)) or None
- if target is None:
+ if target is None:
target = policies["urlize.target"]
if extra_schemes is None:
@@ -798,60 +798,60 @@ def do_urlize(
extra_schemes=extra_schemes,
)
- if eval_ctx.autoescape:
- rv = Markup(rv)
-
- return rv
-
+ if eval_ctx.autoescape:
+ rv = Markup(rv)
+ return rv
+
+
def do_indent(
s: str, width: t.Union[int, str] = 4, first: bool = False, blank: bool = False
) -> str:
- """Return a copy of the string with each line indented by 4 spaces. The
- first line and blank lines are not indented by default.
-
+ """Return a copy of the string with each line indented by 4 spaces. The
+ first line and blank lines are not indented by default.
+
:param width: Number of spaces, or a string, to indent by.
- :param first: Don't skip indenting the first line.
- :param blank: Don't skip indenting empty lines.
-
+ :param first: Don't skip indenting the first line.
+ :param blank: Don't skip indenting empty lines.
+
.. versionchanged:: 3.0
``width`` can be a string.
- .. versionchanged:: 2.10
- Blank lines are not indented by default.
-
- Rename the ``indentfirst`` argument to ``first``.
- """
+ .. versionchanged:: 2.10
+ Blank lines are not indented by default.
+
+ Rename the ``indentfirst`` argument to ``first``.
+ """
if isinstance(width, str):
indention = width
else:
indention = " " * width
-
+
newline = "\n"
-
+
if isinstance(s, Markup):
indention = Markup(indention)
newline = Markup(newline)
s += newline # this quirk is necessary for splitlines method
- if blank:
+ if blank:
rv = (newline + indention).join(s.splitlines())
- else:
- lines = s.splitlines()
- rv = lines.pop(0)
-
- if lines:
+ else:
+ lines = s.splitlines()
+ rv = lines.pop(0)
+
+ if lines:
rv += newline + newline.join(
- indention + line if line else line for line in lines
- )
-
- if first:
- rv = indention + rv
-
- return rv
-
-
+ indention + line if line else line for line in lines
+ )
+
+ if first:
+ rv = indention + rv
+
+ return rv
+
+
@pass_environment
def do_truncate(
env: "Environment",
@@ -861,45 +861,45 @@ def do_truncate(
end: str = "...",
leeway: t.Optional[int] = None,
) -> str:
- """Return a truncated copy of the string. The length is specified
- with the first parameter which defaults to ``255``. If the second
- parameter is ``true`` the filter will cut the text at length. Otherwise
- it will discard the last word. If the text was in fact
- truncated it will append an ellipsis sign (``"..."``). If you want a
- different ellipsis sign than ``"..."`` you can specify it using the
- third parameter. Strings that only exceed the length by the tolerance
- margin given in the fourth parameter will not be truncated.
-
- .. sourcecode:: jinja
-
- {{ "foo bar baz qux"|truncate(9) }}
- -> "foo..."
- {{ "foo bar baz qux"|truncate(9, True) }}
- -> "foo ba..."
- {{ "foo bar baz qux"|truncate(11) }}
- -> "foo bar baz qux"
- {{ "foo bar baz qux"|truncate(11, False, '...', 0) }}
- -> "foo bar..."
-
+ """Return a truncated copy of the string. The length is specified
+ with the first parameter which defaults to ``255``. If the second
+ parameter is ``true`` the filter will cut the text at length. Otherwise
+ it will discard the last word. If the text was in fact
+ truncated it will append an ellipsis sign (``"..."``). If you want a
+ different ellipsis sign than ``"..."`` you can specify it using the
+ third parameter. Strings that only exceed the length by the tolerance
+ margin given in the fourth parameter will not be truncated.
+
+ .. sourcecode:: jinja
+
+ {{ "foo bar baz qux"|truncate(9) }}
+ -> "foo..."
+ {{ "foo bar baz qux"|truncate(9, True) }}
+ -> "foo ba..."
+ {{ "foo bar baz qux"|truncate(11) }}
+ -> "foo bar baz qux"
+ {{ "foo bar baz qux"|truncate(11, False, '...', 0) }}
+ -> "foo bar..."
+
The default leeway on newer Jinja versions is 5 and was 0 before but
- can be reconfigured globally.
- """
- if leeway is None:
+ can be reconfigured globally.
+ """
+ if leeway is None:
leeway = env.policies["truncate.leeway"]
assert length >= len(end), f"expected length >= {len(end)}, got {length}"
assert leeway >= 0, f"expected leeway >= 0, got {leeway}"
- if len(s) <= length + leeway:
- return s
+ if len(s) <= length + leeway:
+ return s
- if killwords:
+ if killwords:
return s[: length - len(end)] + end
result = s[: length - len(end)].rsplit(" ", 1)[0]
- return result + end
-
-
+ return result + end
+
+
@pass_environment
def do_wordwrap(
environment: "Environment",
@@ -929,12 +929,12 @@ def do_wordwrap(
.. versionchanged:: 2.7
Added the ``wrapstring`` parameter.
- """
+ """
import textwrap
if wrapstring is None:
- wrapstring = environment.newline_sequence
-
+ wrapstring = environment.newline_sequence
+
# textwrap.wrap doesn't consider existing newlines when wrapping.
# If the string has a newline before width, wrap will still insert
# a newline at width, resulting in a short line. Instead, split and
@@ -954,55 +954,55 @@ def do_wordwrap(
for line in s.splitlines()
]
)
-
+
_word_re = re.compile(r"\w+")
def do_wordcount(s: str) -> int:
- """Count the words in that string."""
+ """Count the words in that string."""
return len(_word_re.findall(soft_str(s)))
-
-
+
+
def do_int(value: t.Any, default: int = 0, base: int = 10) -> int:
- """Convert the value into an integer. If the
- conversion doesn't work it will return ``0``. You can
- override this default using the first parameter. You
- can also override the default base (10) in the second
- parameter, which handles input with prefixes such as
- 0b, 0o and 0x for bases 2, 8 and 16 respectively.
- The base is ignored for decimal numbers and non-string values.
- """
- try:
+ """Convert the value into an integer. If the
+ conversion doesn't work it will return ``0``. You can
+ override this default using the first parameter. You
+ can also override the default base (10) in the second
+ parameter, which handles input with prefixes such as
+ 0b, 0o and 0x for bases 2, 8 and 16 respectively.
+ The base is ignored for decimal numbers and non-string values.
+ """
+ try:
if isinstance(value, str):
- return int(value, base)
-
- return int(value)
- except (TypeError, ValueError):
- # this quirk is necessary so that "42.23"|int gives 42.
- try:
- return int(float(value))
- except (TypeError, ValueError):
- return default
-
-
+ return int(value, base)
+
+ return int(value)
+ except (TypeError, ValueError):
+ # this quirk is necessary so that "42.23"|int gives 42.
+ try:
+ return int(float(value))
+ except (TypeError, ValueError):
+ return default
+
+
def do_float(value: t.Any, default: float = 0.0) -> float:
- """Convert the value into a floating point number. If the
- conversion doesn't work it will return ``0.0``. You can
- override this default using the first parameter.
- """
- try:
- return float(value)
- except (TypeError, ValueError):
- return default
-
-
+ """Convert the value into a floating point number. If the
+ conversion doesn't work it will return ``0.0``. You can
+ override this default using the first parameter.
+ """
+ try:
+ return float(value)
+ except (TypeError, ValueError):
+ return default
+
+
def do_format(value: str, *args: t.Any, **kwargs: t.Any) -> str:
"""Apply the given values to a `printf-style`_ format string, like
``string % values``.
-
- .. sourcecode:: jinja
-
+
+ .. sourcecode:: jinja
+
{{ "%s, %s!"|format(greeting, name) }}
Hello, World!
@@ -1016,71 +1016,71 @@ def do_format(value: str, *args: t.Any, **kwargs: t.Any) -> str:
.. _printf-style: https://docs.python.org/library/stdtypes.html
#printf-style-string-formatting
- """
- if args and kwargs:
+ """
+ if args and kwargs:
raise FilterArgumentError(
"can't handle positional and keyword arguments at the same time"
)
-
+
return soft_str(value) % (kwargs or args)
-
+
def do_trim(value: str, chars: t.Optional[str] = None) -> str:
"""Strip leading and trailing characters, by default whitespace."""
return soft_str(value).strip(chars)
-
-
+
+
def do_striptags(value: "t.Union[str, HasHTML]") -> str:
"""Strip SGML/XML tags and replace adjacent whitespace by one space."""
if hasattr(value, "__html__"):
value = t.cast("HasHTML", value).__html__()
-
+
return Markup(str(value)).striptags()
-
+
def sync_do_slice(
value: "t.Collection[V]", slices: int, fill_with: "t.Optional[V]" = None
) -> "t.Iterator[t.List[V]]":
- """Slice an iterator and return a list of lists containing
- those items. Useful if you want to create a div containing
- three ul tags that represent columns:
-
- .. sourcecode:: html+jinja
-
+ """Slice an iterator and return a list of lists containing
+ those items. Useful if you want to create a div containing
+ three ul tags that represent columns:
+
+ .. sourcecode:: html+jinja
+
<div class="columnwrapper">
- {%- for column in items|slice(3) %}
- <ul class="column-{{ loop.index }}">
- {%- for item in column %}
- <li>{{ item }}</li>
- {%- endfor %}
- </ul>
- {%- endfor %}
- </div>
-
- If you pass it a second argument it's used to fill missing
- values on the last iteration.
- """
- seq = list(value)
- length = len(seq)
- items_per_slice = length // slices
- slices_with_extra = length % slices
- offset = 0
-
- for slice_number in range(slices):
- start = offset + slice_number * items_per_slice
-
- if slice_number < slices_with_extra:
- offset += 1
-
- end = offset + (slice_number + 1) * items_per_slice
- tmp = seq[start:end]
-
- if fill_with is not None and slice_number >= slices_with_extra:
- tmp.append(fill_with)
-
- yield tmp
-
-
+ {%- for column in items|slice(3) %}
+ <ul class="column-{{ loop.index }}">
+ {%- for item in column %}
+ <li>{{ item }}</li>
+ {%- endfor %}
+ </ul>
+ {%- endfor %}
+ </div>
+
+ If you pass it a second argument it's used to fill missing
+ values on the last iteration.
+ """
+ seq = list(value)
+ length = len(seq)
+ items_per_slice = length // slices
+ slices_with_extra = length % slices
+ offset = 0
+
+ for slice_number in range(slices):
+ start = offset + slice_number * items_per_slice
+
+ if slice_number < slices_with_extra:
+ offset += 1
+
+ end = offset + (slice_number + 1) * items_per_slice
+ tmp = seq[start:end]
+
+ if fill_with is not None and slice_number >= slices_with_extra:
+ tmp.append(fill_with)
+
+ yield tmp
+
+
@async_variant(sync_do_slice) # type: ignore
async def do_slice(
value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
@@ -1093,84 +1093,84 @@ async def do_slice(
def do_batch(
value: "t.Iterable[V]", linecount: int, fill_with: "t.Optional[V]" = None
) -> "t.Iterator[t.List[V]]":
- """
- A filter that batches items. It works pretty much like `slice`
- just the other way round. It returns a list of lists with the
- given number of items. If you provide a second parameter this
- is used to fill up missing items. See this example:
-
- .. sourcecode:: html+jinja
-
- <table>
- {%- for row in items|batch(3, '&nbsp;') %}
- <tr>
- {%- for column in row %}
- <td>{{ column }}</td>
- {%- endfor %}
- </tr>
- {%- endfor %}
- </table>
- """
+ """
+ A filter that batches items. It works pretty much like `slice`
+ just the other way round. It returns a list of lists with the
+ given number of items. If you provide a second parameter this
+ is used to fill up missing items. See this example:
+
+ .. sourcecode:: html+jinja
+
+ <table>
+ {%- for row in items|batch(3, '&nbsp;') %}
+ <tr>
+ {%- for column in row %}
+ <td>{{ column }}</td>
+ {%- endfor %}
+ </tr>
+ {%- endfor %}
+ </table>
+ """
tmp: "t.List[V]" = []
- for item in value:
- if len(tmp) == linecount:
- yield tmp
- tmp = []
+ for item in value:
+ if len(tmp) == linecount:
+ yield tmp
+ tmp = []
- tmp.append(item)
-
- if tmp:
- if fill_with is not None and len(tmp) < linecount:
- tmp += [fill_with] * (linecount - len(tmp))
-
- yield tmp
+ tmp.append(item)
+ if tmp:
+ if fill_with is not None and len(tmp) < linecount:
+ tmp += [fill_with] * (linecount - len(tmp))
+ yield tmp
+
+
def do_round(
value: float,
precision: int = 0,
method: 'te.Literal["common", "ceil", "floor"]' = "common",
) -> float:
- """Round the number to a given precision. The first
- parameter specifies the precision (default is ``0``), the
- second the rounding method:
-
- - ``'common'`` rounds either up or down
- - ``'ceil'`` always rounds up
- - ``'floor'`` always rounds down
-
- If you don't specify a method ``'common'`` is used.
-
- .. sourcecode:: jinja
-
- {{ 42.55|round }}
- -> 43.0
- {{ 42.55|round(1, 'floor') }}
- -> 42.5
-
- Note that even if rounded to 0 precision, a float is returned. If
- you need a real integer, pipe it through `int`:
-
- .. sourcecode:: jinja
-
- {{ 42.55|round|int }}
- -> 43
- """
+ """Round the number to a given precision. The first
+ parameter specifies the precision (default is ``0``), the
+ second the rounding method:
+
+ - ``'common'`` rounds either up or down
+ - ``'ceil'`` always rounds up
+ - ``'floor'`` always rounds down
+
+ If you don't specify a method ``'common'`` is used.
+
+ .. sourcecode:: jinja
+
+ {{ 42.55|round }}
+ -> 43.0
+ {{ 42.55|round(1, 'floor') }}
+ -> 42.5
+
+ Note that even if rounded to 0 precision, a float is returned. If
+ you need a real integer, pipe it through `int`:
+
+ .. sourcecode:: jinja
+
+ {{ 42.55|round|int }}
+ -> 43
+ """
if method not in {"common", "ceil", "floor"}:
raise FilterArgumentError("method must be common, ceil or floor")
if method == "common":
- return round(value, precision)
+ return round(value, precision)
- func = getattr(math, method)
+ func = getattr(math, method)
return t.cast(float, func(value * (10 ** precision)) / (10 ** precision))
-
-
+
+
class _GroupTuple(t.NamedTuple):
grouper: t.Any
list: t.List
-
+
# Use the regular tuple repr to hide this subclass if users print
# out the value during debugging.
def __repr__(self) -> str:
@@ -1192,13 +1192,13 @@ def sync_do_groupby(
nested access, like ``"address.city"``. Unlike Python's ``groupby``,
the values are sorted first so only one group is returned for each
unique value.
-
+
For example, a list of ``User`` objects with a ``city`` attribute
can be rendered in groups. In this example, ``grouper`` refers to
the ``city`` value of the group.
-
- .. sourcecode:: html+jinja
-
+
+ .. sourcecode:: html+jinja
+
<ul>{% for city, items in users|groupby("city") %}
<li>{{ city }}
<ul>{% for user in items %}
@@ -1206,17 +1206,17 @@ def sync_do_groupby(
{% endfor %}</ul>
</li>
{% endfor %}</ul>
-
+
``groupby`` yields namedtuples of ``(grouper, list)``, which
can be used instead of the tuple unpacking above. ``grouper`` is the
value of the attribute, and ``list`` is the items with that value.
-
- .. sourcecode:: html+jinja
-
+
+ .. sourcecode:: html+jinja
+
<ul>{% for group in users|groupby("city") %}
<li>{{ group.grouper }}: {{ group.list|join(", ") }}
{% endfor %}</ul>
-
+
You can specify a ``default`` value to use if an object in the list
does not have the given attribute.
@@ -1229,16 +1229,16 @@ def sync_do_groupby(
.. versionchanged:: 3.0
Added the ``default`` parameter.
- .. versionchanged:: 2.6
+ .. versionchanged:: 2.6
The attribute supports dot notation for nested access.
- """
+ """
expr = make_attrgetter(environment, attribute, default=default)
return [
_GroupTuple(key, list(values))
for key, values in groupby(sorted(value, key=expr), expr)
]
-
-
+
+
@async_variant(sync_do_groupby) # type: ignore
async def do_groupby(
environment: "Environment",
@@ -1260,26 +1260,26 @@ def sync_do_sum(
attribute: t.Optional[t.Union[str, int]] = None,
start: V = 0, # type: ignore
) -> V:
- """Returns the sum of a sequence of numbers plus the value of parameter
- 'start' (which defaults to 0). When the sequence is empty it returns
- start.
-
- It is also possible to sum up only certain attributes:
-
- .. sourcecode:: jinja
-
- Total: {{ items|sum(attribute='price') }}
-
- .. versionchanged:: 2.6
- The `attribute` parameter was added to allow suming up over
- attributes. Also the `start` parameter was moved on to the right.
- """
- if attribute is not None:
+ """Returns the sum of a sequence of numbers plus the value of parameter
+ 'start' (which defaults to 0). When the sequence is empty it returns
+ start.
+
+ It is also possible to sum up only certain attributes:
+
+ .. sourcecode:: jinja
+
+ Total: {{ items|sum(attribute='price') }}
+
+ .. versionchanged:: 2.6
+ The `attribute` parameter was added to allow suming up over
+ attributes. Also the `start` parameter was moved on to the right.
+ """
+ if attribute is not None:
iterable = map(make_attrgetter(environment, attribute), iterable)
- return sum(iterable, start)
-
-
+ return sum(iterable, start)
+
+
@async_variant(sync_do_sum) # type: ignore
async def do_sum(
environment: "Environment",
@@ -1303,29 +1303,29 @@ async def do_sum(
def sync_do_list(value: "t.Iterable[V]") -> "t.List[V]":
- """Convert the value into a list. If it was a string the returned list
- will be a list of characters.
- """
- return list(value)
-
-
+ """Convert the value into a list. If it was a string the returned list
+ will be a list of characters.
+ """
+ return list(value)
+
+
@async_variant(sync_do_list) # type: ignore
async def do_list(value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]") -> "t.List[V]":
return await auto_to_list(value)
def do_mark_safe(value: str) -> Markup:
- """Mark the value as safe which means that in an environment with automatic
- escaping enabled this variable will not be escaped.
- """
- return Markup(value)
-
-
+ """Mark the value as safe which means that in an environment with automatic
+ escaping enabled this variable will not be escaped.
+ """
+ return Markup(value)
+
+
def do_mark_unsafe(value: str) -> str:
- """Mark a value as unsafe. This is the reverse operation for :func:`safe`."""
+ """Mark a value as unsafe. This is the reverse operation for :func:`safe`."""
return str(value)
-
-
+
+
@typing.overload
def do_reverse(value: str) -> str:
...
@@ -1337,54 +1337,54 @@ def do_reverse(value: "t.Iterable[V]") -> "t.Iterable[V]":
def do_reverse(value: t.Union[str, t.Iterable[V]]) -> t.Union[str, t.Iterable[V]]:
- """Reverse the object or return an iterator that iterates over it the other
- way round.
- """
+ """Reverse the object or return an iterator that iterates over it the other
+ way round.
+ """
if isinstance(value, str):
- return value[::-1]
+ return value[::-1]
- try:
+ try:
return reversed(value) # type: ignore
- except TypeError:
- try:
- rv = list(value)
- rv.reverse()
- return rv
+ except TypeError:
+ try:
+ rv = list(value)
+ rv.reverse()
+ return rv
except TypeError as e:
raise FilterArgumentError("argument must be iterable") from e
-
-
+
+
@pass_environment
def do_attr(
environment: "Environment", obj: t.Any, name: str
) -> t.Union[Undefined, t.Any]:
- """Get an attribute of an object. ``foo|attr("bar")`` works like
- ``foo.bar`` just that always an attribute is returned and items are not
- looked up.
-
- See :ref:`Notes on subscriptions <notes-on-subscriptions>` for more details.
- """
- try:
- name = str(name)
- except UnicodeError:
- pass
- else:
- try:
- value = getattr(obj, name)
- except AttributeError:
- pass
- else:
+ """Get an attribute of an object. ``foo|attr("bar")`` works like
+ ``foo.bar`` just that always an attribute is returned and items are not
+ looked up.
+
+ See :ref:`Notes on subscriptions <notes-on-subscriptions>` for more details.
+ """
+ try:
+ name = str(name)
+ except UnicodeError:
+ pass
+ else:
+ try:
+ value = getattr(obj, name)
+ except AttributeError:
+ pass
+ else:
if environment.sandboxed:
environment = t.cast("SandboxedEnvironment", environment)
if not environment.is_safe_attribute(obj, name, value):
return environment.unsafe_undefined(obj, name)
- return value
-
- return environment.undefined(obj=obj, name=name)
-
+ return value
+ return environment.undefined(obj=obj, name=name)
+
+
@typing.overload
def sync_do_map(
context: "Context", value: t.Iterable, name: str, *args: t.Any, **kwargs: t.Any
@@ -1407,17 +1407,17 @@ def sync_do_map(
def sync_do_map(
context: "Context", value: t.Iterable, *args: t.Any, **kwargs: t.Any
) -> t.Iterable:
- """Applies a filter on a sequence of objects or looks up an attribute.
- This is useful when dealing with lists of objects but you are really
- only interested in a certain value of it.
-
- The basic usage is mapping on an attribute. Imagine you have a list
- of users but you are only interested in a list of usernames:
-
- .. sourcecode:: jinja
-
- Users on this page: {{ users|map(attribute='username')|join(', ') }}
-
+ """Applies a filter on a sequence of objects or looks up an attribute.
+ This is useful when dealing with lists of objects but you are really
+ only interested in a certain value of it.
+
+ The basic usage is mapping on an attribute. Imagine you have a list
+ of users but you are only interested in a list of usernames:
+
+ .. sourcecode:: jinja
+
+ Users on this page: {{ users|map(attribute='username')|join(', ') }}
+
You can specify a ``default`` value to use if an object in the list
does not have the given attribute.
@@ -1425,14 +1425,14 @@ def sync_do_map(
{{ users|map(attribute="username", default="Anonymous")|join(", ") }}
- Alternatively you can let it invoke a filter by passing the name of the
- filter and the arguments afterwards. A good example would be applying a
- text conversion filter on a sequence:
-
- .. sourcecode:: jinja
-
- Users on this page: {{ titles|map('lower')|join(', ') }}
-
+ Alternatively you can let it invoke a filter by passing the name of the
+ filter and the arguments afterwards. A good example would be applying a
+ text conversion filter on a sequence:
+
+ .. sourcecode:: jinja
+
+ Users on this page: {{ titles|map('lower')|join(', ') }}
+
Similar to a generator comprehension such as:
.. code-block:: python
@@ -1444,15 +1444,15 @@ def sync_do_map(
.. versionchanged:: 2.11.0
Added the ``default`` parameter.
- .. versionadded:: 2.7
- """
+ .. versionadded:: 2.7
+ """
if value:
func = prepare_map(context, args, kwargs)
for item in value:
- yield func(item)
-
-
+ yield func(item)
+
+
@typing.overload
def do_map(
context: "Context",
@@ -1493,21 +1493,21 @@ async def do_map(
def sync_do_select(
context: "Context", value: "t.Iterable[V]", *args: t.Any, **kwargs: t.Any
) -> "t.Iterator[V]":
- """Filters a sequence of objects by applying a test to each object,
- and only selecting the objects with the test succeeding.
-
- If no test is specified, each object will be evaluated as a boolean.
-
- Example usage:
-
- .. sourcecode:: jinja
-
- {{ numbers|select("odd") }}
- {{ numbers|select("odd") }}
- {{ numbers|select("divisibleby", 3) }}
- {{ numbers|select("lessthan", 42) }}
- {{ strings|select("equalto", "mystring") }}
-
+ """Filters a sequence of objects by applying a test to each object,
+ and only selecting the objects with the test succeeding.
+
+ If no test is specified, each object will be evaluated as a boolean.
+
+ Example usage:
+
+ .. sourcecode:: jinja
+
+ {{ numbers|select("odd") }}
+ {{ numbers|select("odd") }}
+ {{ numbers|select("divisibleby", 3) }}
+ {{ numbers|select("lessthan", 42) }}
+ {{ strings|select("equalto", "mystring") }}
+
Similar to a generator comprehension such as:
.. code-block:: python
@@ -1515,11 +1515,11 @@ def sync_do_select(
(n for n in numbers if test_odd(n))
(n for n in numbers if test_divisibleby(n, 3))
- .. versionadded:: 2.7
- """
+ .. versionadded:: 2.7
+ """
return select_or_reject(context, value, args, kwargs, lambda x: x, False)
-
-
+
+
@async_variant(sync_do_select) # type: ignore
async def do_select(
context: "Context",
@@ -1534,28 +1534,28 @@ async def do_select(
def sync_do_reject(
context: "Context", value: "t.Iterable[V]", *args: t.Any, **kwargs: t.Any
) -> "t.Iterator[V]":
- """Filters a sequence of objects by applying a test to each object,
- and rejecting the objects with the test succeeding.
-
- If no test is specified, each object will be evaluated as a boolean.
-
- Example usage:
-
- .. sourcecode:: jinja
-
- {{ numbers|reject("odd") }}
-
+ """Filters a sequence of objects by applying a test to each object,
+ and rejecting the objects with the test succeeding.
+
+ If no test is specified, each object will be evaluated as a boolean.
+
+ Example usage:
+
+ .. sourcecode:: jinja
+
+ {{ numbers|reject("odd") }}
+
Similar to a generator comprehension such as:
.. code-block:: python
(n for n in numbers if not test_odd(n))
- .. versionadded:: 2.7
- """
+ .. versionadded:: 2.7
+ """
return select_or_reject(context, value, args, kwargs, lambda x: not x, False)
-
-
+
+
@async_variant(sync_do_reject) # type: ignore
async def do_reject(
context: "Context",
@@ -1570,20 +1570,20 @@ async def do_reject(
def sync_do_selectattr(
context: "Context", value: "t.Iterable[V]", *args: t.Any, **kwargs: t.Any
) -> "t.Iterator[V]":
- """Filters a sequence of objects by applying a test to the specified
- attribute of each object, and only selecting the objects with the
- test succeeding.
-
- If no test is specified, the attribute's value will be evaluated as
- a boolean.
-
- Example usage:
-
- .. sourcecode:: jinja
-
- {{ users|selectattr("is_active") }}
- {{ users|selectattr("email", "none") }}
-
+ """Filters a sequence of objects by applying a test to the specified
+ attribute of each object, and only selecting the objects with the
+ test succeeding.
+
+ If no test is specified, the attribute's value will be evaluated as
+ a boolean.
+
+ Example usage:
+
+ .. sourcecode:: jinja
+
+ {{ users|selectattr("is_active") }}
+ {{ users|selectattr("email", "none") }}
+
Similar to a generator comprehension such as:
.. code-block:: python
@@ -1591,11 +1591,11 @@ def sync_do_selectattr(
(u for user in users if user.is_active)
(u for user in users if test_none(user.email))
- .. versionadded:: 2.7
- """
+ .. versionadded:: 2.7
+ """
return select_or_reject(context, value, args, kwargs, lambda x: x, True)
-
-
+
+
@async_variant(sync_do_selectattr) # type: ignore
async def do_selectattr(
context: "Context",
@@ -1610,18 +1610,18 @@ async def do_selectattr(
def sync_do_rejectattr(
context: "Context", value: "t.Iterable[V]", *args: t.Any, **kwargs: t.Any
) -> "t.Iterator[V]":
- """Filters a sequence of objects by applying a test to the specified
- attribute of each object, and rejecting the objects with the test
- succeeding.
-
- If no test is specified, the attribute's value will be evaluated as
- a boolean.
-
- .. sourcecode:: jinja
-
- {{ users|rejectattr("is_active") }}
- {{ users|rejectattr("email", "none") }}
-
+ """Filters a sequence of objects by applying a test to the specified
+ attribute of each object, and rejecting the objects with the test
+ succeeding.
+
+ If no test is specified, the attribute's value will be evaluated as
+ a boolean.
+
+ .. sourcecode:: jinja
+
+ {{ users|rejectattr("is_active") }}
+ {{ users|rejectattr("email", "none") }}
+
Similar to a generator comprehension such as:
.. code-block:: python
@@ -1629,11 +1629,11 @@ def sync_do_rejectattr(
(u for user in users if not user.is_active)
(u for user in users if not test_none(user.email))
- .. versionadded:: 2.7
- """
+ .. versionadded:: 2.7
+ """
return select_or_reject(context, value, args, kwargs, lambda x: not x, True)
-
-
+
+
@async_variant(sync_do_rejectattr) # type: ignore
async def do_rejectattr(
context: "Context",
@@ -1642,37 +1642,37 @@ async def do_rejectattr(
**kwargs: t.Any,
) -> "t.AsyncIterator[V]":
return async_select_or_reject(context, value, args, kwargs, lambda x: not x, True)
-
-
+
+
@pass_eval_context
def do_tojson(
eval_ctx: "EvalContext", value: t.Any, indent: t.Optional[int] = None
) -> Markup:
"""Serialize an object to a string of JSON, and mark it safe to
render in HTML. This filter is only for use in HTML documents.
-
+
The returned string is safe to render in HTML documents and
``<script>`` tags. The exception is in HTML attributes that are
double quoted; either use single quotes or the ``|forceescape``
filter.
-
+
:param value: The object to serialize to JSON.
:param indent: The ``indent`` parameter passed to ``dumps``, for
pretty-printing the value.
-
- .. versionadded:: 2.9
- """
- policies = eval_ctx.environment.policies
+
+ .. versionadded:: 2.9
+ """
+ policies = eval_ctx.environment.policies
dumps = policies["json.dumps_function"]
kwargs = policies["json.dumps_kwargs"]
- if indent is not None:
+ if indent is not None:
kwargs = kwargs.copy()
kwargs["indent"] = indent
-
+
return htmlsafe_json_dumps(value, dumps=dumps, **kwargs)
-
-
+
+
def prepare_map(
context: "Context", args: t.Tuple, kwargs: t.Dict[str, t.Any]
) -> t.Callable[[t.Any], t.Any]:
@@ -1680,27 +1680,27 @@ def prepare_map(
attribute = kwargs.pop("attribute")
default = kwargs.pop("default", None)
- if kwargs:
+ if kwargs:
raise FilterArgumentError(
f"Unexpected keyword argument {next(iter(kwargs))!r}"
)
func = make_attrgetter(context.environment, attribute, default=default)
- else:
- try:
+ else:
+ try:
name = args[0]
args = args[1:]
- except LookupError:
+ except LookupError:
raise FilterArgumentError("map requires a filter argument") from None
-
+
def func(item: t.Any) -> t.Any:
return context.environment.call_filter(
name, item, args, kwargs, context=context
)
return func
-
-
+
+
def prepare_select_or_reject(
context: "Context",
args: t.Tuple,
@@ -1708,33 +1708,33 @@ def prepare_select_or_reject(
modfunc: t.Callable[[t.Any], t.Any],
lookup_attr: bool,
) -> t.Callable[[t.Any], t.Any]:
- if lookup_attr:
- try:
+ if lookup_attr:
+ try:
attr = args[0]
- except LookupError:
+ except LookupError:
raise FilterArgumentError("Missing parameter for attribute name") from None
- transfunc = make_attrgetter(context.environment, attr)
- off = 1
- else:
- off = 0
-
+ transfunc = make_attrgetter(context.environment, attr)
+ off = 1
+ else:
+ off = 0
+
def transfunc(x: V) -> V:
return x
- try:
+ try:
name = args[off]
args = args[1 + off :]
def func(item: t.Any) -> t.Any:
return context.environment.call_test(name, item, args, kwargs)
- except LookupError:
+ except LookupError:
func = bool # type: ignore
-
+
return lambda item: modfunc(func(transfunc(item)))
-
-
+
+
def select_or_reject(
context: "Context",
value: "t.Iterable[V]",
@@ -1747,10 +1747,10 @@ def select_or_reject(
func = prepare_select_or_reject(context, args, kwargs, modfunc, lookup_attr)
for item in value:
- if func(item):
- yield item
-
-
+ if func(item):
+ yield item
+
+
async def async_select_or_reject(
context: "Context",
value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
@@ -1767,7 +1767,7 @@ async def async_select_or_reject(
yield item
-FILTERS = {
+FILTERS = {
"abs": abs,
"attr": do_attr,
"batch": do_batch,
@@ -1821,4 +1821,4 @@ FILTERS = {
"wordwrap": do_wordwrap,
"xmlattr": do_xmlattr,
"tojson": do_tojson,
-}
+}
diff --git a/contrib/python/Jinja2/py3/jinja2/idtracking.py b/contrib/python/Jinja2/py3/jinja2/idtracking.py
index 38c525ee31..1181f8a524 100644
--- a/contrib/python/Jinja2/py3/jinja2/idtracking.py
+++ b/contrib/python/Jinja2/py3/jinja2/idtracking.py
@@ -2,183 +2,183 @@ import typing as t
from . import nodes
from .visitor import NodeVisitor
-
+
VAR_LOAD_PARAMETER = "param"
VAR_LOAD_RESOLVE = "resolve"
VAR_LOAD_ALIAS = "alias"
VAR_LOAD_UNDEFINED = "undefined"
-
-
+
+
def find_symbols(
nodes: t.Iterable[nodes.Node], parent_symbols: t.Optional["Symbols"] = None
) -> "Symbols":
- sym = Symbols(parent=parent_symbols)
- visitor = FrameSymbolVisitor(sym)
- for node in nodes:
- visitor.visit(node)
- return sym
-
-
+ sym = Symbols(parent=parent_symbols)
+ visitor = FrameSymbolVisitor(sym)
+ for node in nodes:
+ visitor.visit(node)
+ return sym
+
+
def symbols_for_node(
node: nodes.Node, parent_symbols: t.Optional["Symbols"] = None
) -> "Symbols":
- sym = Symbols(parent=parent_symbols)
- sym.analyze_node(node)
- return sym
-
-
+ sym = Symbols(parent=parent_symbols)
+ sym.analyze_node(node)
+ return sym
+
+
class Symbols:
def __init__(
self, parent: t.Optional["Symbols"] = None, level: t.Optional[int] = None
) -> None:
- if level is None:
- if parent is None:
- level = 0
- else:
- level = parent.level + 1
+ if level is None:
+ if parent is None:
+ level = 0
+ else:
+ level = parent.level + 1
self.level: int = level
- self.parent = parent
+ self.parent = parent
self.refs: t.Dict[str, str] = {}
self.loads: t.Dict[str, t.Any] = {}
self.stores: t.Set[str] = set()
-
+
def analyze_node(self, node: nodes.Node, **kwargs: t.Any) -> None:
- visitor = RootVisitor(self)
- visitor.visit(node, **kwargs)
-
+ visitor = RootVisitor(self)
+ visitor.visit(node, **kwargs)
+
def _define_ref(
self, name: str, load: t.Optional[t.Tuple[str, t.Optional[str]]] = None
) -> str:
ident = f"l_{self.level}_{name}"
- self.refs[name] = ident
- if load is not None:
- self.loads[ident] = load
- return ident
-
+ self.refs[name] = ident
+ if load is not None:
+ self.loads[ident] = load
+ return ident
+
def find_load(self, target: str) -> t.Optional[t.Any]:
- if target in self.loads:
- return self.loads[target]
-
- if self.parent is not None:
- return self.parent.find_load(target)
+ if target in self.loads:
+ return self.loads[target]
+ if self.parent is not None:
+ return self.parent.find_load(target)
+
return None
def find_ref(self, name: str) -> t.Optional[str]:
- if name in self.refs:
- return self.refs[name]
-
- if self.parent is not None:
- return self.parent.find_ref(name)
+ if name in self.refs:
+ return self.refs[name]
+ if self.parent is not None:
+ return self.parent.find_ref(name)
+
return None
def ref(self, name: str) -> str:
- rv = self.find_ref(name)
- if rv is None:
+ rv = self.find_ref(name)
+ if rv is None:
raise AssertionError(
"Tried to resolve a name to a reference that was"
f" unknown to the frame ({name!r})"
)
- return rv
-
+ return rv
+
def copy(self) -> "Symbols":
rv = t.cast(Symbols, object.__new__(self.__class__))
- rv.__dict__.update(self.__dict__)
- rv.refs = self.refs.copy()
- rv.loads = self.loads.copy()
- rv.stores = self.stores.copy()
- return rv
-
+ rv.__dict__.update(self.__dict__)
+ rv.refs = self.refs.copy()
+ rv.loads = self.loads.copy()
+ rv.stores = self.stores.copy()
+ return rv
+
def store(self, name: str) -> None:
- self.stores.add(name)
-
- # If we have not see the name referenced yet, we need to figure
- # out what to set it to.
- if name not in self.refs:
- # If there is a parent scope we check if the name has a
- # reference there. If it does it means we might have to alias
- # to a variable there.
- if self.parent is not None:
- outer_ref = self.parent.find_ref(name)
- if outer_ref is not None:
- self._define_ref(name, load=(VAR_LOAD_ALIAS, outer_ref))
- return
-
- # Otherwise we can just set it to undefined.
- self._define_ref(name, load=(VAR_LOAD_UNDEFINED, None))
-
+ self.stores.add(name)
+
+ # If we have not see the name referenced yet, we need to figure
+ # out what to set it to.
+ if name not in self.refs:
+ # If there is a parent scope we check if the name has a
+ # reference there. If it does it means we might have to alias
+ # to a variable there.
+ if self.parent is not None:
+ outer_ref = self.parent.find_ref(name)
+ if outer_ref is not None:
+ self._define_ref(name, load=(VAR_LOAD_ALIAS, outer_ref))
+ return
+
+ # Otherwise we can just set it to undefined.
+ self._define_ref(name, load=(VAR_LOAD_UNDEFINED, None))
+
def declare_parameter(self, name: str) -> str:
- self.stores.add(name)
- return self._define_ref(name, load=(VAR_LOAD_PARAMETER, None))
-
+ self.stores.add(name)
+ return self._define_ref(name, load=(VAR_LOAD_PARAMETER, None))
+
def load(self, name: str) -> None:
if self.find_ref(name) is None:
- self._define_ref(name, load=(VAR_LOAD_RESOLVE, name))
-
+ self._define_ref(name, load=(VAR_LOAD_RESOLVE, name))
+
def branch_update(self, branch_symbols: t.Sequence["Symbols"]) -> None:
stores: t.Dict[str, int] = {}
- for branch in branch_symbols:
- for target in branch.stores:
- if target in self.stores:
- continue
- stores[target] = stores.get(target, 0) + 1
-
- for sym in branch_symbols:
- self.refs.update(sym.refs)
- self.loads.update(sym.loads)
- self.stores.update(sym.stores)
-
+ for branch in branch_symbols:
+ for target in branch.stores:
+ if target in self.stores:
+ continue
+ stores[target] = stores.get(target, 0) + 1
+
+ for sym in branch_symbols:
+ self.refs.update(sym.refs)
+ self.loads.update(sym.loads)
+ self.stores.update(sym.stores)
+
for name, branch_count in stores.items():
- if branch_count == len(branch_symbols):
- continue
+ if branch_count == len(branch_symbols):
+ continue
target = self.find_ref(name) # type: ignore
assert target is not None, "should not happen"
-
- if self.parent is not None:
- outer_target = self.parent.find_ref(name)
- if outer_target is not None:
- self.loads[target] = (VAR_LOAD_ALIAS, outer_target)
- continue
- self.loads[target] = (VAR_LOAD_RESOLVE, name)
-
+
+ if self.parent is not None:
+ outer_target = self.parent.find_ref(name)
+ if outer_target is not None:
+ self.loads[target] = (VAR_LOAD_ALIAS, outer_target)
+ continue
+ self.loads[target] = (VAR_LOAD_RESOLVE, name)
+
def dump_stores(self) -> t.Dict[str, str]:
rv: t.Dict[str, str] = {}
node: t.Optional["Symbols"] = self
- while node is not None:
+ while node is not None:
for name in sorted(node.stores):
- if name not in rv:
+ if name not in rv:
rv[name] = self.find_ref(name) # type: ignore
- node = node.parent
-
- return rv
+ node = node.parent
+ return rv
+
def dump_param_targets(self) -> t.Set[str]:
- rv = set()
+ rv = set()
node: t.Optional["Symbols"] = self
- while node is not None:
+ while node is not None:
for target, (instr, _) in self.loads.items():
- if instr == VAR_LOAD_PARAMETER:
- rv.add(target)
-
- node = node.parent
-
- return rv
+ if instr == VAR_LOAD_PARAMETER:
+ rv.add(target)
+ node = node.parent
-class RootVisitor(NodeVisitor):
+ return rv
+
+
+class RootVisitor(NodeVisitor):
def __init__(self, symbols: "Symbols") -> None:
- self.sym_visitor = FrameSymbolVisitor(symbols)
-
+ self.sym_visitor = FrameSymbolVisitor(symbols)
+
def _simple_visit(self, node: nodes.Node, **kwargs: t.Any) -> None:
- for child in node.iter_child_nodes():
- self.sym_visitor.visit(child)
-
+ for child in node.iter_child_nodes():
+ self.sym_visitor.visit(child)
+
visit_Template = _simple_visit
visit_Block = _simple_visit
visit_Macro = _simple_visit
@@ -186,133 +186,133 @@ class RootVisitor(NodeVisitor):
visit_Scope = _simple_visit
visit_If = _simple_visit
visit_ScopedEvalContextModifier = _simple_visit
-
+
def visit_AssignBlock(self, node: nodes.AssignBlock, **kwargs: t.Any) -> None:
- for child in node.body:
- self.sym_visitor.visit(child)
-
+ for child in node.body:
+ self.sym_visitor.visit(child)
+
def visit_CallBlock(self, node: nodes.CallBlock, **kwargs: t.Any) -> None:
for child in node.iter_child_nodes(exclude=("call",)):
- self.sym_visitor.visit(child)
-
+ self.sym_visitor.visit(child)
+
def visit_OverlayScope(self, node: nodes.OverlayScope, **kwargs: t.Any) -> None:
- for child in node.body:
- self.sym_visitor.visit(child)
-
+ for child in node.body:
+ self.sym_visitor.visit(child)
+
def visit_For(
self, node: nodes.For, for_branch: str = "body", **kwargs: t.Any
) -> None:
if for_branch == "body":
- self.sym_visitor.visit(node.target, store_as_param=True)
- branch = node.body
+ self.sym_visitor.visit(node.target, store_as_param=True)
+ branch = node.body
elif for_branch == "else":
- branch = node.else_
+ branch = node.else_
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:
+ 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")
-
+
if branch:
for item in branch:
self.sym_visitor.visit(item)
def visit_With(self, node: nodes.With, **kwargs: t.Any) -> None:
- for target in node.targets:
- self.sym_visitor.visit(target)
- for child in node.body:
- self.sym_visitor.visit(child)
-
+ for target in node.targets:
+ self.sym_visitor.visit(target)
+ for child in node.body:
+ self.sym_visitor.visit(child)
+
def generic_visit(self, node: nodes.Node, *args: t.Any, **kwargs: t.Any) -> None:
raise NotImplementedError(f"Cannot find symbols for {type(node).__name__!r}")
-
-
-class FrameSymbolVisitor(NodeVisitor):
- """A visitor for `Frame.inspect`."""
-
+
+
+class FrameSymbolVisitor(NodeVisitor):
+ """A visitor for `Frame.inspect`."""
+
def __init__(self, symbols: "Symbols") -> None:
- self.symbols = symbols
-
+ self.symbols = symbols
+
def visit_Name(
self, node: nodes.Name, store_as_param: bool = False, **kwargs: t.Any
) -> None:
- """All assignments to names go through this function."""
+ """All assignments to names go through this function."""
if store_as_param or node.ctx == "param":
- self.symbols.declare_parameter(node.name)
+ self.symbols.declare_parameter(node.name)
elif node.ctx == "store":
- self.symbols.store(node.name)
+ self.symbols.store(node.name)
elif node.ctx == "load":
- self.symbols.load(node.name)
-
+ self.symbols.load(node.name)
+
def visit_NSRef(self, node: nodes.NSRef, **kwargs: t.Any) -> None:
- self.symbols.load(node.name)
-
+ self.symbols.load(node.name)
+
def visit_If(self, node: nodes.If, **kwargs: t.Any) -> None:
- self.visit(node.test, **kwargs)
- original_symbols = self.symbols
-
+ self.visit(node.test, **kwargs)
+ original_symbols = self.symbols
+
def inner_visit(nodes: t.Iterable[nodes.Node]) -> "Symbols":
- self.symbols = rv = original_symbols.copy()
-
- for subnode in nodes:
- self.visit(subnode, **kwargs)
-
- self.symbols = original_symbols
- return rv
-
- body_symbols = inner_visit(node.body)
- elif_symbols = inner_visit(node.elif_)
- else_symbols = inner_visit(node.else_ or ())
- self.symbols.branch_update([body_symbols, elif_symbols, else_symbols])
-
+ self.symbols = rv = original_symbols.copy()
+
+ for subnode in nodes:
+ self.visit(subnode, **kwargs)
+
+ self.symbols = original_symbols
+ return rv
+
+ body_symbols = inner_visit(node.body)
+ elif_symbols = inner_visit(node.elif_)
+ else_symbols = inner_visit(node.else_ or ())
+ self.symbols.branch_update([body_symbols, elif_symbols, else_symbols])
+
def visit_Macro(self, node: nodes.Macro, **kwargs: t.Any) -> None:
- self.symbols.store(node.name)
-
+ self.symbols.store(node.name)
+
def visit_Import(self, node: nodes.Import, **kwargs: t.Any) -> None:
- self.generic_visit(node, **kwargs)
- self.symbols.store(node.target)
-
+ self.generic_visit(node, **kwargs)
+ self.symbols.store(node.target)
+
def visit_FromImport(self, node: nodes.FromImport, **kwargs: t.Any) -> None:
- self.generic_visit(node, **kwargs)
-
- for name in node.names:
- if isinstance(name, tuple):
- self.symbols.store(name[1])
- else:
- self.symbols.store(name)
-
+ self.generic_visit(node, **kwargs)
+
+ for name in node.names:
+ if isinstance(name, tuple):
+ self.symbols.store(name[1])
+ else:
+ self.symbols.store(name)
+
def visit_Assign(self, node: nodes.Assign, **kwargs: t.Any) -> None:
- """Visit assignments in the correct order."""
- self.visit(node.node, **kwargs)
- self.visit(node.target, **kwargs)
-
+ """Visit assignments in the correct order."""
+ self.visit(node.node, **kwargs)
+ self.visit(node.target, **kwargs)
+
def visit_For(self, node: nodes.For, **kwargs: t.Any) -> None:
- """Visiting stops at for blocks. However the block sequence
- is visited as part of the outer scope.
- """
- self.visit(node.iter, **kwargs)
-
+ """Visiting stops at for blocks. However the block sequence
+ is visited as part of the outer scope.
+ """
+ self.visit(node.iter, **kwargs)
+
def visit_CallBlock(self, node: nodes.CallBlock, **kwargs: t.Any) -> None:
- self.visit(node.call, **kwargs)
-
+ self.visit(node.call, **kwargs)
+
def visit_FilterBlock(self, node: nodes.FilterBlock, **kwargs: t.Any) -> None:
- self.visit(node.filter, **kwargs)
-
+ self.visit(node.filter, **kwargs)
+
def visit_With(self, node: nodes.With, **kwargs: t.Any) -> None:
- for target in node.values:
- self.visit(target)
-
+ for target in node.values:
+ self.visit(target)
+
def visit_AssignBlock(self, node: nodes.AssignBlock, **kwargs: t.Any) -> None:
- """Stop visiting at block assigns."""
- self.visit(node.target, **kwargs)
-
+ """Stop visiting at block assigns."""
+ self.visit(node.target, **kwargs)
+
def visit_Scope(self, node: nodes.Scope, **kwargs: t.Any) -> None:
- """Stop visiting at scopes."""
-
+ """Stop visiting at scopes."""
+
def visit_Block(self, node: nodes.Block, **kwargs: t.Any) -> None:
- """Stop visiting at blocks."""
-
+ """Stop visiting at blocks."""
+
def visit_OverlayScope(self, node: nodes.OverlayScope, **kwargs: t.Any) -> None:
- """Do not visit into overlay scopes."""
+ """Do not visit into overlay scopes."""
diff --git a/contrib/python/Jinja2/py3/jinja2/lexer.py b/contrib/python/Jinja2/py3/jinja2/lexer.py
index c25ab0f690..2817bf989f 100644
--- a/contrib/python/Jinja2/py3/jinja2/lexer.py
+++ b/contrib/python/Jinja2/py3/jinja2/lexer.py
@@ -2,26 +2,26 @@
is used to do some preprocessing. It filters out invalid operators like
the bitshift operators we don't allow in templates. It separates
template code and python code in expressions.
-"""
-import re
+"""
+import re
import typing as t
from ast import literal_eval
-from collections import deque
+from collections import deque
from sys import intern
-
+
from ._identifier import pattern as name_re
from .exceptions import TemplateSyntaxError
from .utils import LRUCache
-
+
if t.TYPE_CHECKING:
import typing_extensions as te
from .environment import Environment
-# cache for the lexers. Exists in order to be able to have multiple
-# environments with the same lexer
+# cache for the lexers. Exists in order to be able to have multiple
+# environments with the same lexer
_lexer_cache: t.MutableMapping[t.Tuple, "Lexer"] = LRUCache(50) # type: ignore
-
-# static regular expressions
+
+# static regular expressions
whitespace_re = re.compile(r"\s+")
newline_re = re.compile(r"(\r\n|\r|\n)")
string_re = re.compile(
@@ -56,8 +56,8 @@ float_re = re.compile(
""",
re.IGNORECASE | re.VERBOSE,
)
-
-# internal the tokens and keep references to them
+
+# internal the tokens and keep references to them
TOKEN_ADD = intern("add")
TOKEN_ASSIGN = intern("assign")
TOKEN_COLON = intern("colon")
@@ -107,9 +107,9 @@ TOKEN_LINECOMMENT = intern("linecomment")
TOKEN_DATA = intern("data")
TOKEN_INITIAL = intern("initial")
TOKEN_EOF = intern("eof")
-
-# bind operators to token types
-operators = {
+
+# bind operators to token types
+operators = {
"+": TOKEN_ADD,
"-": TOKEN_SUB,
"/": TOKEN_DIV,
@@ -136,14 +136,14 @@ operators = {
"|": TOKEN_PIPE,
",": TOKEN_COMMA,
";": TOKEN_SEMICOLON,
-}
-
+}
+
reverse_operators = {v: k for k, v in operators.items()}
assert len(operators) == len(reverse_operators), "operators dropped"
operator_re = re.compile(
f"({'|'.join(re.escape(x) for x in sorted(operators, key=lambda x: -len(x)))})"
)
-
+
ignored_tokens = frozenset(
[
TOKEN_COMMENT_BEGIN,
@@ -158,13 +158,13 @@ ignored_tokens = frozenset(
ignore_if_empty = frozenset(
[TOKEN_WHITESPACE, TOKEN_DATA, TOKEN_COMMENT, TOKEN_LINECOMMENT]
)
-
-
+
+
def _describe_token_type(token_type: str) -> str:
- if token_type in reverse_operators:
- return reverse_operators[token_type]
+ if token_type in reverse_operators:
+ return reverse_operators[token_type]
- return {
+ return {
TOKEN_COMMENT_BEGIN: "begin of comment",
TOKEN_COMMENT_END: "end of comment",
TOKEN_COMMENT: "comment",
@@ -177,41 +177,41 @@ def _describe_token_type(token_type: str) -> str:
TOKEN_LINESTATEMENT_END: "end of line statement",
TOKEN_DATA: "template data / text",
TOKEN_EOF: "end of template",
- }.get(token_type, token_type)
-
-
+ }.get(token_type, token_type)
+
+
def describe_token(token: "Token") -> str:
- """Returns a description of the token."""
+ """Returns a description of the token."""
if token.type == TOKEN_NAME:
- return token.value
-
- return _describe_token_type(token.type)
-
+ return token.value
+ return _describe_token_type(token.type)
+
+
def describe_token_expr(expr: str) -> str:
- """Like `describe_token` but for token expressions."""
+ """Like `describe_token` but for token expressions."""
if ":" in expr:
type, value = expr.split(":", 1)
if type == TOKEN_NAME:
- return value
- else:
- type = expr
-
- return _describe_token_type(type)
-
+ return value
+ else:
+ type = expr
+ return _describe_token_type(type)
+
+
def count_newlines(value: str) -> int:
- """Count the number of newline characters in the string. This is
- useful for extensions that filter a stream.
- """
- return len(newline_re.findall(value))
-
-
+ """Count the number of newline characters in the string. This is
+ useful for extensions that filter a stream.
+ """
+ return len(newline_re.findall(value))
+
+
def compile_rules(environment: "Environment") -> t.List[t.Tuple[str, str]]:
- """Compiles all the rules from the environment into a list of rules."""
- e = re.escape
- rules = [
+ """Compiles all the rules from the environment into a list of rules."""
+ e = re.escape
+ rules = [
(
len(environment.comment_start_string),
TOKEN_COMMENT_BEGIN,
@@ -227,9 +227,9 @@ def compile_rules(environment: "Environment") -> t.List[t.Tuple[str, str]]:
TOKEN_VARIABLE_BEGIN,
e(environment.variable_start_string),
),
- ]
-
- if environment.line_statement_prefix is not None:
+ ]
+
+ if environment.line_statement_prefix is not None:
rules.append(
(
len(environment.line_statement_prefix),
@@ -237,7 +237,7 @@ def compile_rules(environment: "Environment") -> t.List[t.Tuple[str, str]]:
r"^[ \t\v]*" + e(environment.line_statement_prefix),
)
)
- if environment.line_comment_prefix is not None:
+ if environment.line_comment_prefix is not None:
rules.append(
(
len(environment.line_comment_prefix),
@@ -245,25 +245,25 @@ def compile_rules(environment: "Environment") -> t.List[t.Tuple[str, str]]:
r"(?:^|(?<=\S))[^\S\r\n]*" + e(environment.line_comment_prefix),
)
)
-
- return [x[1:] for x in sorted(rules, reverse=True)]
-
-
+
+ return [x[1:] for x in sorted(rules, reverse=True)]
+
+
class Failure:
- """Class that raises a `TemplateSyntaxError` if called.
- Used by the `Lexer` to specify known errors.
- """
-
+ """Class that raises a `TemplateSyntaxError` if called.
+ Used by the `Lexer` to specify known errors.
+ """
+
def __init__(
self, message: str, cls: t.Type[TemplateSyntaxError] = TemplateSyntaxError
) -> None:
- self.message = message
- self.error_class = cls
-
+ self.message = message
+ self.error_class = cls
+
def __call__(self, lineno: int, filename: str) -> "te.NoReturn":
- raise self.error_class(self.message, lineno, filename)
-
-
+ raise self.error_class(self.message, lineno, filename)
+
+
class Token(t.NamedTuple):
lineno: int
type: str
@@ -271,141 +271,141 @@ class Token(t.NamedTuple):
def __str__(self) -> str:
return describe_token(self)
-
+
def test(self, expr: str) -> bool:
- """Test a token against a token expression. This can either be a
- token type or ``'token_type:token_value'``. This can only test
- against string values and types.
- """
- # here we do a regular string equality check as test_any is usually
- # passed an iterable of not interned strings.
- if self.type == expr:
- return True
+ """Test a token against a token expression. This can either be a
+ token type or ``'token_type:token_value'``. This can only test
+ against string values and types.
+ """
+ # here we do a regular string equality check as test_any is usually
+ # passed an iterable of not interned strings.
+ if self.type == expr:
+ return True
if ":" in expr:
return expr.split(":", 1) == [self.type, self.value]
- return False
-
+ return False
+
def test_any(self, *iterable: str) -> bool:
- """Test against multiple token expressions."""
+ """Test against multiple token expressions."""
return any(self.test(expr) for expr in iterable)
-
-
+
+
class TokenStreamIterator:
- """The iterator for tokenstreams. Iterate over the stream
- until the eof token is reached.
- """
-
+ """The iterator for tokenstreams. Iterate over the stream
+ until the eof token is reached.
+ """
+
def __init__(self, stream: "TokenStream") -> None:
- self.stream = stream
-
+ self.stream = stream
+
def __iter__(self) -> "TokenStreamIterator":
- return self
-
+ return self
+
def __next__(self) -> Token:
- token = self.stream.current
+ token = self.stream.current
- if token.type is TOKEN_EOF:
- self.stream.close()
+ if token.type is TOKEN_EOF:
+ self.stream.close()
raise StopIteration
- next(self.stream)
- return token
-
-
+ next(self.stream)
+ return token
+
+
class TokenStream:
- """A token stream is an iterable that yields :class:`Token`\\s. The
- parser however does not iterate over it but calls :meth:`next` to go
- one token ahead. The current active token is stored as :attr:`current`.
- """
-
+ """A token stream is an iterable that yields :class:`Token`\\s. The
+ parser however does not iterate over it but calls :meth:`next` to go
+ one token ahead. The current active token is stored as :attr:`current`.
+ """
+
def __init__(
self,
generator: t.Iterable[Token],
name: t.Optional[str],
filename: t.Optional[str],
):
- self._iter = iter(generator)
+ self._iter = iter(generator)
self._pushed: "te.Deque[Token]" = deque()
- self.name = name
- self.filename = filename
- self.closed = False
+ self.name = name
+ self.filename = filename
+ self.closed = False
self.current = Token(1, TOKEN_INITIAL, "")
- next(self)
-
+ next(self)
+
def __iter__(self) -> TokenStreamIterator:
- return TokenStreamIterator(self)
-
+ return TokenStreamIterator(self)
+
def __bool__(self) -> bool:
- return bool(self._pushed) or self.current.type is not TOKEN_EOF
+ return bool(self._pushed) or self.current.type is not TOKEN_EOF
@property
def eos(self) -> bool:
"""Are we at the end of the stream?"""
return not self
-
+
def push(self, token: Token) -> None:
- """Push a token back to the stream."""
- self._pushed.append(token)
-
+ """Push a token back to the stream."""
+ self._pushed.append(token)
+
def look(self) -> Token:
- """Look at the next token."""
- old_token = next(self)
- result = self.current
- self.push(result)
- self.current = old_token
- return result
-
+ """Look at the next token."""
+ old_token = next(self)
+ result = self.current
+ self.push(result)
+ self.current = old_token
+ return result
+
def skip(self, n: int = 1) -> None:
- """Got n tokens ahead."""
+ """Got n tokens ahead."""
for _ in range(n):
- next(self)
-
+ next(self)
+
def next_if(self, expr: str) -> t.Optional[Token]:
- """Perform the token test and return the token if it matched.
- Otherwise the return value is `None`.
- """
- if self.current.test(expr):
- return next(self)
-
+ """Perform the token test and return the token if it matched.
+ Otherwise the return value is `None`.
+ """
+ if self.current.test(expr):
+ return next(self)
+
return None
def skip_if(self, expr: str) -> bool:
- """Like :meth:`next_if` but only returns `True` or `False`."""
- return self.next_if(expr) is not None
-
+ """Like :meth:`next_if` but only returns `True` or `False`."""
+ return self.next_if(expr) is not None
+
def __next__(self) -> Token:
- """Go one token ahead and return the old one.
-
- Use the built-in :func:`next` instead of calling this directly.
- """
- rv = self.current
-
- if self._pushed:
- self.current = self._pushed.popleft()
- elif self.current.type is not TOKEN_EOF:
- try:
- self.current = next(self._iter)
- except StopIteration:
- self.close()
-
- return rv
-
+ """Go one token ahead and return the old one.
+
+ Use the built-in :func:`next` instead of calling this directly.
+ """
+ rv = self.current
+
+ if self._pushed:
+ self.current = self._pushed.popleft()
+ elif self.current.type is not TOKEN_EOF:
+ try:
+ self.current = next(self._iter)
+ except StopIteration:
+ self.close()
+
+ return rv
+
def close(self) -> None:
- """Close the stream."""
+ """Close the stream."""
self.current = Token(self.current.lineno, TOKEN_EOF, "")
self._iter = iter(())
- self.closed = True
-
+ self.closed = True
+
def expect(self, expr: str) -> Token:
- """Expect a given token type and return it. This accepts the same
- argument as :meth:`jinja2.lexer.Token.test`.
- """
- if not self.current.test(expr):
- expr = describe_token_expr(expr)
+ """Expect a given token type and return it. This accepts the same
+ argument as :meth:`jinja2.lexer.Token.test`.
+ """
+ if not self.current.test(expr):
+ expr = describe_token_expr(expr)
- if self.current.type is TOKEN_EOF:
+ if self.current.type is TOKEN_EOF:
raise TemplateSyntaxError(
f"unexpected end of template, expected {expr!r}.",
self.current.lineno,
@@ -419,12 +419,12 @@ class TokenStream:
self.name,
self.filename,
)
-
+
return next(self)
-
+
def get_lexer(environment: "Environment") -> "Lexer":
- """Return a lexer which is probably cached."""
+ """Return a lexer which is probably cached."""
key = (
environment.block_start_string,
environment.block_end_string,
@@ -439,14 +439,14 @@ def get_lexer(environment: "Environment") -> "Lexer":
environment.newline_sequence,
environment.keep_trailing_newline,
)
- lexer = _lexer_cache.get(key)
+ lexer = _lexer_cache.get(key)
- if lexer is None:
+ if lexer is None:
_lexer_cache[key] = lexer = Lexer(environment)
- return lexer
-
-
+ return lexer
+
+
class OptionalLStrip(tuple):
"""A special tuple for marking a point in the state that can have
lstrip applied.
@@ -467,21 +467,21 @@ class _Rule(t.NamedTuple):
class Lexer:
- """Class that implements a lexer for a given environment. Automatically
- created by the environment class, usually you don't have to do that.
-
- Note that the lexer is not automatically bound to an environment.
- Multiple environments can share the same lexer.
- """
-
+ """Class that implements a lexer for a given environment. Automatically
+ created by the environment class, usually you don't have to do that.
+
+ Note that the lexer is not automatically bound to an environment.
+ Multiple environments can share the same lexer.
+ """
+
def __init__(self, environment: "Environment") -> None:
- # shortcuts
- e = re.escape
-
+ # shortcuts
+ e = re.escape
+
def c(x: str) -> t.Pattern[str]:
return re.compile(x, re.M | re.S)
- # lexing rules for tags
+ # lexing rules for tags
tag_rules: t.List[_Rule] = [
_Rule(whitespace_re, TOKEN_WHITESPACE, None),
_Rule(float_re, TOKEN_FLOAT, None),
@@ -489,31 +489,31 @@ class Lexer:
_Rule(name_re, TOKEN_NAME, None),
_Rule(string_re, TOKEN_STRING, None),
_Rule(operator_re, TOKEN_OPERATOR, None),
- ]
-
- # assemble the root lexing rule. because "|" is ungreedy
- # we have to sort by length so that the lexer continues working
- # as expected when we have parsing rules like <% for block and
- # <%= for variables. (if someone wants asp like syntax)
- # variables are just part of the rules if variable processing
- # is required.
- root_tag_rules = compile_rules(environment)
-
+ ]
+
+ # assemble the root lexing rule. because "|" is ungreedy
+ # we have to sort by length so that the lexer continues working
+ # as expected when we have parsing rules like <% for block and
+ # <%= for variables. (if someone wants asp like syntax)
+ # variables are just part of the rules if variable processing
+ # is required.
+ root_tag_rules = compile_rules(environment)
+
block_start_re = e(environment.block_start_string)
block_end_re = e(environment.block_end_string)
comment_end_re = e(environment.comment_end_string)
variable_end_re = e(environment.variable_end_string)
- # block suffix if trimming is enabled
+ # block suffix if trimming is enabled
block_suffix_re = "\\n?" if environment.trim_blocks else ""
-
+
# If lstrip is enabled, it should not be applied if there is any
# non-whitespace between the newline and block.
self.lstrip_unless_re = c(r"[^ \t]") if environment.lstrip_blocks else None
-
- self.newline_sequence = environment.newline_sequence
- self.keep_trailing_newline = environment.keep_trailing_newline
-
+
+ self.newline_sequence = environment.newline_sequence
+ self.keep_trailing_newline = environment.keep_trailing_newline
+
root_raw_re = (
fr"(?P<raw_begin>{block_start_re}(\-|\+|)\s*raw\s*"
fr"(?:\-{block_end_re}\s*|{block_end_re}))"
@@ -522,20 +522,20 @@ class Lexer:
[root_raw_re] + [fr"(?P<{n}>{r}(\-|\+|))" for n, r in root_tag_rules]
)
- # global lexing rules
+ # global lexing rules
self.rules: t.Dict[str, t.List[_Rule]] = {
"root": [
- # directives
+ # directives
_Rule(
c(fr"(.*?)(?:{root_parts_re})"),
OptionalLStrip(TOKEN_DATA, "#bygroup"), # type: ignore
"#bygroup",
),
- # data
+ # data
_Rule(c(".+"), TOKEN_DATA, None),
- ],
- # comments
- TOKEN_COMMENT_BEGIN: [
+ ],
+ # comments
+ TOKEN_COMMENT_BEGIN: [
_Rule(
c(
fr"(.*?)((?:\+{comment_end_re}|\-{comment_end_re}\s*"
@@ -545,9 +545,9 @@ class Lexer:
"#pop",
),
_Rule(c(r"(.)"), (Failure("Missing end of comment tag"),), None),
- ],
- # blocks
- TOKEN_BLOCK_BEGIN: [
+ ],
+ # blocks
+ TOKEN_BLOCK_BEGIN: [
_Rule(
c(
fr"(?:\+{block_end_re}|\-{block_end_re}\s*"
@@ -558,8 +558,8 @@ class Lexer:
),
]
+ tag_rules,
- # variables
- TOKEN_VARIABLE_BEGIN: [
+ # variables
+ TOKEN_VARIABLE_BEGIN: [
_Rule(
c(fr"\-{variable_end_re}\s*|{variable_end_re}"),
TOKEN_VARIABLE_END,
@@ -567,8 +567,8 @@ class Lexer:
)
]
+ tag_rules,
- # raw block
- TOKEN_RAW_BEGIN: [
+ # raw block
+ TOKEN_RAW_BEGIN: [
_Rule(
c(
fr"(.*?)((?:{block_start_re}(\-|\+|))\s*endraw\s*"
@@ -579,28 +579,28 @@ class Lexer:
"#pop",
),
_Rule(c(r"(.)"), (Failure("Missing end of raw directive"),), None),
- ],
- # line statements
- TOKEN_LINESTATEMENT_BEGIN: [
+ ],
+ # line statements
+ TOKEN_LINESTATEMENT_BEGIN: [
_Rule(c(r"\s*(\n|$)"), TOKEN_LINESTATEMENT_END, "#pop")
]
+ tag_rules,
- # line comments
- TOKEN_LINECOMMENT_BEGIN: [
+ # line comments
+ TOKEN_LINECOMMENT_BEGIN: [
_Rule(
c(r"(.*?)()(?=\n|$)"),
(TOKEN_LINECOMMENT, TOKEN_LINECOMMENT_END),
"#pop",
)
],
- }
-
+ }
+
def _normalize_newlines(self, value: str) -> str:
"""Replace all newlines with the configured sequence in strings
and template data.
"""
- return newline_re.sub(self.newline_sequence, value)
-
+ return newline_re.sub(self.newline_sequence, value)
+
def tokenize(
self,
source: str,
@@ -609,21 +609,21 @@ class Lexer:
state: t.Optional[str] = None,
) -> TokenStream:
"""Calls tokeniter + tokenize and wraps it in a token stream."""
- stream = self.tokeniter(source, name, filename, state)
- return TokenStream(self.wrap(stream, name, filename), name, filename)
-
+ stream = self.tokeniter(source, name, filename, state)
+ return TokenStream(self.wrap(stream, name, filename), name, filename)
+
def wrap(
self,
stream: t.Iterable[t.Tuple[int, str, str]],
name: t.Optional[str] = None,
filename: t.Optional[str] = None,
) -> t.Iterator[Token]:
- """This is called with the stream as returned by `tokenize` and wraps
- every token in a :class:`Token` and converts the value.
- """
+ """This is called with the stream as returned by `tokenize` and wraps
+ every token in a :class:`Token` and converts the value.
+ """
for lineno, token, value_str in stream:
- if token in ignored_tokens:
- continue
+ if token in ignored_tokens:
+ continue
value: t.Any = value_str
@@ -631,9 +631,9 @@ class Lexer:
token = TOKEN_BLOCK_BEGIN
elif token == TOKEN_LINESTATEMENT_END:
token = TOKEN_BLOCK_END
- # we are not interested in those tokens in the parser
+ # we are not interested in those tokens in the parser
elif token in (TOKEN_RAW_BEGIN, TOKEN_RAW_END):
- continue
+ continue
elif token == TOKEN_DATA:
value = self._normalize_newlines(value_str)
elif token == "keyword":
@@ -642,18 +642,18 @@ class Lexer:
value = value_str
if not value.isidentifier():
- raise TemplateSyntaxError(
+ raise TemplateSyntaxError(
"Invalid character in identifier", lineno, name, filename
)
elif token == TOKEN_STRING:
- # try to unescape string
- try:
+ # try to unescape string
+ try:
value = (
self._normalize_newlines(value_str[1:-1])
.encode("ascii", "backslashreplace")
.decode("unicode-escape")
)
- except Exception as e:
+ except Exception as e:
msg = str(e).split(":")[-1].strip()
raise TemplateSyntaxError(msg, lineno, name, filename) from e
elif token == TOKEN_INTEGER:
@@ -664,8 +664,8 @@ class Lexer:
elif token == TOKEN_OPERATOR:
token = operators[value_str]
- yield Token(lineno, token, value)
-
+ yield Token(lineno, token, value)
+
def tokeniter(
self,
source: str,
@@ -673,56 +673,56 @@ class Lexer:
filename: t.Optional[str] = None,
state: t.Optional[str] = None,
) -> t.Iterator[t.Tuple[int, str, str]]:
- """This method tokenizes the text and returns the tokens in a
+ """This method tokenizes the text and returns the tokens in a
generator. Use this method if you just want to tokenize a template.
.. versionchanged:: 3.0
Only ``\\n``, ``\\r\\n`` and ``\\r`` are treated as line
breaks.
- """
+ """
lines = newline_re.split(source)[::2]
if not self.keep_trailing_newline and lines[-1] == "":
del lines[-1]
source = "\n".join(lines)
- pos = 0
- lineno = 1
+ pos = 0
+ lineno = 1
stack = ["root"]
if state is not None and state != "root":
assert state in ("variable", "block"), "invalid state"
stack.append(state + "_begin")
- statetokens = self.rules[stack[-1]]
- source_length = len(source)
+ statetokens = self.rules[stack[-1]]
+ source_length = len(source)
balancing_stack: t.List[str] = []
lstrip_unless_re = self.lstrip_unless_re
newlines_stripped = 0
line_starting = True
-
+
while True:
- # tokenizer loop
- for regex, tokens, new_state in statetokens:
- m = regex.match(source, pos)
-
- # if no match we try again with the next rule
- if m is None:
- continue
-
- # we only match blocks and variables if braces / parentheses
- # are balanced. continue parsing with the lower rule which
- # is the operator rule. do this only if the end tags look
- # like operators
+ # tokenizer loop
+ for regex, tokens, new_state in statetokens:
+ m = regex.match(source, pos)
+
+ # if no match we try again with the next rule
+ if m is None:
+ continue
+
+ # we only match blocks and variables if braces / parentheses
+ # are balanced. continue parsing with the lower rule which
+ # is the operator rule. do this only if the end tags look
+ # like operators
if balancing_stack and tokens in (
TOKEN_VARIABLE_END,
TOKEN_BLOCK_END,
TOKEN_LINESTATEMENT_END,
):
- continue
-
- # tuples support more options
- if isinstance(tokens, tuple):
+ continue
+
+ # tuples support more options
+ if isinstance(tokens, tuple):
groups = m.groups()
if isinstance(tokens, OptionalLStrip):
@@ -756,39 +756,39 @@ class Lexer:
if not lstrip_unless_re.search(text, l_pos):
groups = [text[:l_pos], *groups[1:]]
- for idx, token in enumerate(tokens):
- # failure group
- if token.__class__ is Failure:
- raise token(lineno, filename)
- # bygroup is a bit more complex, in that case we
- # yield for the current token the first named
- # group that matched
+ for idx, token in enumerate(tokens):
+ # failure group
+ if token.__class__ is Failure:
+ raise token(lineno, filename)
+ # bygroup is a bit more complex, in that case we
+ # yield for the current token the first named
+ # group that matched
elif token == "#bygroup":
for key, value in m.groupdict().items():
- if value is not None:
- yield lineno, key, value
+ if value is not None:
+ yield lineno, key, value
lineno += value.count("\n")
- break
- else:
+ break
+ else:
raise RuntimeError(
f"{regex!r} wanted to resolve the token dynamically"
" but no group matched"
)
- # normal group
- else:
+ # normal group
+ else:
data = groups[idx]
- if data or token not in ignore_if_empty:
- yield lineno, token, data
+ if data or token not in ignore_if_empty:
+ yield lineno, token, data
lineno += data.count("\n") + newlines_stripped
newlines_stripped = 0
+
+ # strings as token just are yielded as it.
+ else:
+ data = m.group()
- # strings as token just are yielded as it.
- else:
- data = m.group()
-
- # update brace/parentheses balance
+ # update brace/parentheses balance
if tokens == TOKEN_OPERATOR:
if data == "{":
balancing_stack.append("}")
@@ -797,14 +797,14 @@ class Lexer:
elif data == "[":
balancing_stack.append("]")
elif data in ("}", ")", "]"):
- if not balancing_stack:
+ if not balancing_stack:
raise TemplateSyntaxError(
f"unexpected '{data}'", lineno, name, filename
)
- expected_op = balancing_stack.pop()
+ expected_op = balancing_stack.pop()
- if expected_op != data:
+ if expected_op != data:
raise TemplateSyntaxError(
f"unexpected '{data}', expected '{expected_op}'",
lineno,
@@ -812,58 +812,58 @@ class Lexer:
filename,
)
- # yield items
- if data or tokens not in ignore_if_empty:
- yield lineno, tokens, data
+ # yield items
+ if data or tokens not in ignore_if_empty:
+ 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
- pos2 = m.end()
-
- # handle state changes
- if new_state is not None:
- # remove the uppermost state
+ # 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
+ pos2 = m.end()
+
+ # handle state changes
+ if new_state is not None:
+ # remove the uppermost state
if new_state == "#pop":
- stack.pop()
- # resolve the new state by group checking
+ stack.pop()
+ # resolve the new state by group checking
elif new_state == "#bygroup":
for key, value in m.groupdict().items():
- if value is not None:
- stack.append(key)
- break
- else:
+ if value is not None:
+ stack.append(key)
+ break
+ else:
raise RuntimeError(
f"{regex!r} wanted to resolve the new state dynamically"
f" but no group matched"
)
- # direct state name given
- else:
- stack.append(new_state)
-
- statetokens = self.rules[stack[-1]]
- # we are still at the same position and no stack change.
- # this means a loop without break condition, avoid that and
- # raise error
- elif pos2 == pos:
+ # direct state name given
+ else:
+ stack.append(new_state)
+
+ statetokens = self.rules[stack[-1]]
+ # we are still at the same position and no stack change.
+ # this means a loop without break condition, avoid that and
+ # raise error
+ elif pos2 == pos:
raise RuntimeError(
f"{regex!r} yielded empty string without stack change"
)
- # publish new function and start again
- pos = pos2
- break
- # if loop terminated without break we haven't found a single match
- # either we are at the end of the file or we have a problem
- else:
- # end of text
- if pos >= source_length:
- return
-
- # something went wrong
+ # publish new function and start again
+ pos = pos2
+ break
+ # if loop terminated without break we haven't found a single match
+ # either we are at the end of the file or we have a problem
+ else:
+ # end of text
+ if pos >= source_length:
+ return
+
+ # something went wrong
raise TemplateSyntaxError(
f"unexpected char {source[pos]!r} at {pos}", lineno, name, filename
)
diff --git a/contrib/python/Jinja2/py3/jinja2/loaders.py b/contrib/python/Jinja2/py3/jinja2/loaders.py
index cc58eca221..c4b35e0325 100644
--- a/contrib/python/Jinja2/py3/jinja2/loaders.py
+++ b/contrib/python/Jinja2/py3/jinja2/loaders.py
@@ -1,22 +1,22 @@
"""API and implementations for loading templates from different data
sources.
-"""
+"""
import importlib.util
-import os
-import sys
+import os
+import sys
import pkgutil
import typing as t
-import weakref
+import weakref
import zipimport
from collections import abc
from hashlib import sha1
from importlib import import_module
-from types import ModuleType
-
+from types import ModuleType
+
from .exceptions import TemplateNotFound
from .utils import internalcode
from .utils import open_if_exists
-
+
if t.TYPE_CHECKING:
from .environment import Environment
from .environment import Template
@@ -25,147 +25,147 @@ import __res as arcadia_res
def split_template_path(template: str) -> t.List[str]:
- """Split a path into segments and perform a sanity check. If it detects
- '..' in the path it will raise a `TemplateNotFound` error.
- """
- pieces = []
+ """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 (
os.path.sep in piece
or (os.path.altsep and os.path.altsep in piece)
or piece == os.path.pardir
):
- raise TemplateNotFound(template)
+ raise TemplateNotFound(template)
elif piece and piece != ".":
- pieces.append(piece)
- return pieces
-
-
+ pieces.append(piece)
+ return pieces
+
+
class BaseLoader:
- """Baseclass for all loaders. Subclass this and override `get_source` to
- implement a custom loading mechanism. The environment provides a
- `get_template` method that calls the loader's `load` method to get the
- :class:`Template` object.
-
- A very basic example for a loader that looks up templates on the file
- system could look like this::
-
- from jinja2 import BaseLoader, TemplateNotFound
- from os.path import join, exists, getmtime
-
- class MyLoader(BaseLoader):
-
- def __init__(self, path):
- self.path = path
-
- def get_source(self, environment, template):
- path = join(self.path, template)
- if not exists(path):
- raise TemplateNotFound(template)
- mtime = getmtime(path)
+ """Baseclass for all loaders. Subclass this and override `get_source` to
+ implement a custom loading mechanism. The environment provides a
+ `get_template` method that calls the loader's `load` method to get the
+ :class:`Template` object.
+
+ A very basic example for a loader that looks up templates on the file
+ system could look like this::
+
+ from jinja2 import BaseLoader, TemplateNotFound
+ from os.path import join, exists, getmtime
+
+ class MyLoader(BaseLoader):
+
+ def __init__(self, path):
+ self.path = path
+
+ def get_source(self, environment, template):
+ path = join(self.path, template)
+ if not exists(path):
+ raise TemplateNotFound(template)
+ mtime = getmtime(path)
with open(path) as f:
source = f.read()
- return source, path, lambda: mtime == getmtime(path)
- """
-
- #: if set to `False` it indicates that the loader cannot provide access
- #: to the source of templates.
- #:
- #: .. versionadded:: 2.4
- has_source_access = True
-
+ return source, path, lambda: mtime == getmtime(path)
+ """
+
+ #: if set to `False` it indicates that the loader cannot provide access
+ #: to the source of templates.
+ #:
+ #: .. versionadded:: 2.4
+ has_source_access = True
+
def get_source(
self, environment: "Environment", template: str
) -> t.Tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]]:
- """Get the template source, filename and reload helper for a template.
- It's passed the environment and template name and has to return a
- tuple in the form ``(source, filename, uptodate)`` or raise a
- `TemplateNotFound` error if it can't locate the template.
-
- The source part of the returned tuple must be the source of the
+ """Get the template source, filename and reload helper for a template.
+ It's passed the environment and template name and has to return a
+ tuple in the form ``(source, filename, uptodate)`` or raise a
+ `TemplateNotFound` error if it can't locate the template.
+
+ The source part of the returned tuple must be the source of the
template as a string. The filename should be the name of the
file on the filesystem if it was loaded from there, otherwise
``None``. The filename is used by Python for the tracebacks
- if no loader extension is used.
-
- The last item in the tuple is the `uptodate` function. If auto
- reloading is enabled it's always called to check if the template
- changed. No arguments are passed so the function must store the
- old state somewhere (for example in a closure). If it returns `False`
- the template will be reloaded.
- """
- if not self.has_source_access:
+ if no loader extension is used.
+
+ The last item in the tuple is the `uptodate` function. If auto
+ reloading is enabled it's always called to check if the template
+ changed. No arguments are passed so the function must store the
+ old state somewhere (for example in a closure). If it returns `False`
+ the template will be reloaded.
+ """
+ if not self.has_source_access:
raise RuntimeError(
f"{type(self).__name__} cannot provide access to the source"
)
- raise TemplateNotFound(template)
-
+ raise TemplateNotFound(template)
+
def list_templates(self) -> t.List[str]:
- """Iterates over all templates. If the loader does not support that
- it should raise a :exc:`TypeError` which is the default behavior.
- """
+ """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")
-
- @internalcode
+
+ @internalcode
def load(
self,
environment: "Environment",
name: str,
globals: t.Optional[t.MutableMapping[str, t.Any]] = None,
) -> "Template":
- """Loads a template. This method looks up the template in the cache
- or loads one by calling :meth:`get_source`. Subclasses should not
- override this method as loaders working on collections of other
- loaders (such as :class:`PrefixLoader` or :class:`ChoiceLoader`)
- will not call this method but `get_source` directly.
- """
- code = None
- if globals is None:
- globals = {}
-
- # first we try to get the source for this template together
- # with the filename and the uptodate function.
- source, filename, uptodate = self.get_source(environment, name)
-
- # try to load the code from the bytecode cache if there is a
- # bytecode cache configured.
- bcc = environment.bytecode_cache
- if bcc is not None:
- bucket = bcc.get_bucket(environment, name, filename, source)
- code = bucket.code
-
- # if we don't have code so far (not cached, no longer up to
- # date) etc. we compile the template
- if code is None:
- code = environment.compile(source, name, filename)
-
- # if the bytecode cache is available and the bucket doesn't
- # have a code so far, we give the bucket the new code and put
- # it back to the bytecode cache.
- if bcc is not None and bucket.code is None:
- bucket.code = code
- bcc.set_bucket(bucket)
-
+ """Loads a template. This method looks up the template in the cache
+ or loads one by calling :meth:`get_source`. Subclasses should not
+ override this method as loaders working on collections of other
+ loaders (such as :class:`PrefixLoader` or :class:`ChoiceLoader`)
+ will not call this method but `get_source` directly.
+ """
+ code = None
+ if globals is None:
+ globals = {}
+
+ # first we try to get the source for this template together
+ # with the filename and the uptodate function.
+ source, filename, uptodate = self.get_source(environment, name)
+
+ # try to load the code from the bytecode cache if there is a
+ # bytecode cache configured.
+ bcc = environment.bytecode_cache
+ if bcc is not None:
+ bucket = bcc.get_bucket(environment, name, filename, source)
+ code = bucket.code
+
+ # if we don't have code so far (not cached, no longer up to
+ # date) etc. we compile the template
+ if code is None:
+ code = environment.compile(source, name, filename)
+
+ # if the bytecode cache is available and the bucket doesn't
+ # have a code so far, we give the bucket the new code and put
+ # it back to the bytecode cache.
+ if bcc is not None and bucket.code is None:
+ bucket.code = code
+ bcc.set_bucket(bucket)
+
return environment.template_class.from_code(
environment, code, globals, uptodate
)
-
-
-class FileSystemLoader(BaseLoader):
+
+
+class FileSystemLoader(BaseLoader):
"""Load templates from a directory in the file system.
-
+
The path can be relative or absolute. Relative paths are relative to
the current working directory.
-
+
.. code-block:: python
-
+
loader = FileSystemLoader("templates")
-
+
A list of paths can be given. The directories will be searched in
order, stopping at the first matching template.
-
+
.. code-block:: python
-
+
loader = FileSystemLoader(["/override/templates", "/default/templates"])
:param searchpath: A path, or list of paths, to the directory that
@@ -176,8 +176,8 @@ class FileSystemLoader(BaseLoader):
.. versionchanged:: 2.8
Added the ``followlinks`` parameter.
- """
-
+ """
+
def __init__(
self,
searchpath: t.Union[str, os.PathLike, t.Sequence[t.Union[str, os.PathLike]]],
@@ -185,67 +185,67 @@ class FileSystemLoader(BaseLoader):
followlinks: bool = False,
) -> None:
if not isinstance(searchpath, abc.Iterable) or isinstance(searchpath, str):
- searchpath = [searchpath]
+ searchpath = [searchpath]
self.searchpath = [os.fspath(p) for p in searchpath]
- self.encoding = encoding
- self.followlinks = followlinks
-
+ self.encoding = encoding
+ self.followlinks = followlinks
+
def get_source(
self, environment: "Environment", template: str
) -> t.Tuple[str, str, t.Callable[[], bool]]:
- pieces = split_template_path(template)
- for searchpath in self.searchpath:
+ pieces = split_template_path(template)
+ for searchpath in self.searchpath:
filename = os.path.join(searchpath, *pieces)
- f = open_if_exists(filename)
- if f is None:
- continue
- try:
- contents = f.read().decode(self.encoding)
- finally:
- f.close()
-
+ f = open_if_exists(filename)
+ if f is None:
+ continue
+ try:
+ contents = f.read().decode(self.encoding)
+ finally:
+ f.close()
+
mtime = os.path.getmtime(filename)
-
+
def uptodate() -> bool:
- try:
+ try:
return os.path.getmtime(filename) == mtime
- except OSError:
- return False
-
- return contents, filename, uptodate
- raise TemplateNotFound(template)
+ except OSError:
+ return False
+ return contents, filename, uptodate
+ raise TemplateNotFound(template)
+
def list_templates(self) -> t.List[str]:
- found = set()
- for searchpath in self.searchpath:
- walk_dir = os.walk(searchpath, followlinks=self.followlinks)
+ found = set()
+ for searchpath in self.searchpath:
+ walk_dir = os.walk(searchpath, followlinks=self.followlinks)
for dirpath, _, filenames in walk_dir:
- for filename in filenames:
+ for filename in filenames:
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)
- return sorted(found)
-
-
-class PackageLoader(BaseLoader):
+ template = template[2:]
+ if template not in found:
+ found.add(template)
+ return sorted(found)
+
+
+class PackageLoader(BaseLoader):
"""Load templates from a directory in a Python 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.
-
+
The following example looks up templates in the ``pages`` directory
within the ``project.ui`` package.
-
+
.. code-block:: python
loader = PackageLoader("project.ui", "pages")
@@ -265,8 +265,8 @@ class PackageLoader(BaseLoader):
.. versionchanged:: 3.0
Limited PEP 420 namespace package support.
- """
-
+ """
+
def __init__(
self,
package_name: str,
@@ -283,8 +283,8 @@ class PackageLoader(BaseLoader):
self.package_path = package_path
self.package_name = package_name
- self.encoding = encoding
-
+ self.encoding = encoding
+
# Make sure the package exists. This also makes namespace
# packages work, otherwise get_loader returns None.
package = import_module(package_name)
@@ -316,7 +316,7 @@ class PackageLoader(BaseLoader):
for root in roots:
root = os.path.join(root, package_path)
-
+
if os.path.isdir(root):
template_root = root
break
@@ -328,13 +328,13 @@ class PackageLoader(BaseLoader):
)
self._template_root = template_root
-
+
def get_source(
self, environment: "Environment", template: str
) -> t.Tuple[str, str, t.Optional[t.Callable[[], bool]]]:
p = os.path.join(self._template_root, *split_template_path(template))
up_to_date: t.Optional[t.Callable[[], bool]]
-
+
if self._archive is None and hasattr(self, "_package"):
try:
source = pkgutil.get_data(self.package_name, os.path.join(self.package_path, *split_template_path(template)))
@@ -408,52 +408,52 @@ class PackageLoader(BaseLoader):
if name.startswith(prefix) and name[-1] != os.path.sep:
results.append(name[offset:].replace(os.path.sep, "/"))
- results.sort()
- return results
-
-
-class DictLoader(BaseLoader):
+ results.sort()
+ return results
+
+
+class DictLoader(BaseLoader):
"""Loads a template from a Python dict mapping template names to
template source. This loader is useful for unittesting:
-
- >>> loader = DictLoader({'index.html': 'source here'})
-
- Because auto reloading is rarely useful this is disabled per default.
- """
-
+
+ >>> loader = DictLoader({'index.html': 'source here'})
+
+ Because auto reloading is rarely useful this is disabled per default.
+ """
+
def __init__(self, mapping: t.Mapping[str, str]) -> None:
- self.mapping = mapping
-
+ self.mapping = mapping
+
def get_source(
self, environment: "Environment", template: str
) -> t.Tuple[str, None, t.Callable[[], bool]]:
- if template in self.mapping:
- source = self.mapping[template]
- return source, None, lambda: source == self.mapping.get(template)
- raise TemplateNotFound(template)
-
+ if template in self.mapping:
+ source = self.mapping[template]
+ return source, None, lambda: source == self.mapping.get(template)
+ raise TemplateNotFound(template)
+
def list_templates(self) -> t.List[str]:
- return sorted(self.mapping)
-
-
-class FunctionLoader(BaseLoader):
- """A loader that is passed a function which does the loading. The
- function receives the name of the template and has to return either
+ return sorted(self.mapping)
+
+
+class FunctionLoader(BaseLoader):
+ """A loader that is passed a function which does the loading. The
+ function receives the name of the template and has to return either
a string with the template source, a tuple in the form ``(source,
- filename, uptodatefunc)`` or `None` if the template does not exist.
-
- >>> def load_template(name):
- ... if name == 'index.html':
- ... return '...'
- ...
- >>> loader = FunctionLoader(load_template)
-
- The `uptodatefunc` is a function that is called if autoreload is enabled
- and has to return `True` if the template is still up to date. For more
- details have a look at :meth:`BaseLoader.get_source` which has the same
- return value.
- """
-
+ filename, uptodatefunc)`` or `None` if the template does not exist.
+
+ >>> def load_template(name):
+ ... if name == 'index.html':
+ ... return '...'
+ ...
+ >>> loader = FunctionLoader(load_template)
+
+ The `uptodatefunc` is a function that is called if autoreload is enabled
+ and has to return `True` if the template is still up to date. For more
+ details have a look at :meth:`BaseLoader.get_source` which has the same
+ return value.
+ """
+
def __init__(
self,
load_func: t.Callable[
@@ -465,222 +465,222 @@ class FunctionLoader(BaseLoader):
],
],
) -> None:
- self.load_func = load_func
-
+ self.load_func = load_func
+
def get_source(
self, environment: "Environment", template: str
) -> t.Tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]]:
- rv = self.load_func(template)
+ rv = self.load_func(template)
- if rv is None:
- raise TemplateNotFound(template)
+ if rv is None:
+ raise TemplateNotFound(template)
if isinstance(rv, str):
- return rv, None, None
-
- return rv
-
-
-class PrefixLoader(BaseLoader):
- """A loader that is passed a dict of loaders where each loader is bound
- to a prefix. The prefix is delimited from the template by a slash per
- default, which can be changed by setting the `delimiter` argument to
- something else::
-
- loader = PrefixLoader({
- 'app1': PackageLoader('mypackage.app1'),
- 'app2': PackageLoader('mypackage.app2')
- })
-
- By loading ``'app1/index.html'`` the file from the app1 package is loaded,
- by loading ``'app2/index.html'`` the file from the second.
- """
-
+ return rv, None, None
+
+ return rv
+
+
+class PrefixLoader(BaseLoader):
+ """A loader that is passed a dict of loaders where each loader is bound
+ to a prefix. The prefix is delimited from the template by a slash per
+ default, which can be changed by setting the `delimiter` argument to
+ something else::
+
+ loader = PrefixLoader({
+ 'app1': PackageLoader('mypackage.app1'),
+ 'app2': PackageLoader('mypackage.app2')
+ })
+
+ By loading ``'app1/index.html'`` the file from the app1 package is loaded,
+ by loading ``'app2/index.html'`` the file from the second.
+ """
+
def __init__(
self, mapping: t.Mapping[str, BaseLoader], delimiter: str = "/"
) -> None:
- self.mapping = mapping
- self.delimiter = delimiter
-
+ self.mapping = mapping
+ self.delimiter = delimiter
+
def get_loader(self, template: str) -> t.Tuple[BaseLoader, str]:
- try:
- prefix, name = template.split(self.delimiter, 1)
- loader = self.mapping[prefix]
+ try:
+ prefix, name = template.split(self.delimiter, 1)
+ loader = self.mapping[prefix]
except (ValueError, KeyError) as e:
raise TemplateNotFound(template) from e
- return loader, name
-
+ return loader, name
+
def get_source(
self, environment: "Environment", template: str
) -> t.Tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]]:
- loader, name = self.get_loader(template)
- try:
- return loader.get_source(environment, name)
+ loader, name = self.get_loader(template)
+ try:
+ return loader.get_source(environment, name)
except TemplateNotFound as e:
- # re-raise the exception with the correct filename here.
- # (the one that includes the prefix)
+ # re-raise the exception with the correct filename here.
+ # (the one that includes the prefix)
raise TemplateNotFound(template) from e
-
- @internalcode
+
+ @internalcode
def load(
self,
environment: "Environment",
name: str,
globals: t.Optional[t.MutableMapping[str, t.Any]] = None,
) -> "Template":
- loader, local_name = self.get_loader(name)
- try:
- return loader.load(environment, local_name, globals)
+ loader, local_name = self.get_loader(name)
+ try:
+ return loader.load(environment, local_name, globals)
except TemplateNotFound as e:
- # re-raise the exception with the correct filename here.
- # (the one that includes the prefix)
+ # re-raise the exception with the correct filename here.
+ # (the one that includes the prefix)
raise TemplateNotFound(name) from e
-
+
def list_templates(self) -> t.List[str]:
- result = []
+ result = []
for prefix, loader in self.mapping.items():
- for template in loader.list_templates():
- result.append(prefix + self.delimiter + template)
- return result
-
-
-class ChoiceLoader(BaseLoader):
- """This loader works like the `PrefixLoader` just that no prefix is
- specified. If a template could not be found by one loader the next one
- is tried.
-
- >>> loader = ChoiceLoader([
- ... FileSystemLoader('/path/to/user/templates'),
- ... FileSystemLoader('/path/to/system/templates')
- ... ])
-
- This is useful if you want to allow users to override builtin templates
- from a different location.
- """
-
+ for template in loader.list_templates():
+ result.append(prefix + self.delimiter + template)
+ return result
+
+
+class ChoiceLoader(BaseLoader):
+ """This loader works like the `PrefixLoader` just that no prefix is
+ specified. If a template could not be found by one loader the next one
+ is tried.
+
+ >>> loader = ChoiceLoader([
+ ... FileSystemLoader('/path/to/user/templates'),
+ ... FileSystemLoader('/path/to/system/templates')
+ ... ])
+
+ This is useful if you want to allow users to override builtin templates
+ from a different location.
+ """
+
def __init__(self, loaders: t.Sequence[BaseLoader]) -> None:
- self.loaders = loaders
-
+ self.loaders = loaders
+
def get_source(
self, environment: "Environment", template: str
) -> t.Tuple[str, t.Optional[str], t.Optional[t.Callable[[], bool]]]:
- for loader in self.loaders:
- try:
- return loader.get_source(environment, template)
- except TemplateNotFound:
- pass
- raise TemplateNotFound(template)
-
- @internalcode
+ for loader in self.loaders:
+ try:
+ return loader.get_source(environment, template)
+ except TemplateNotFound:
+ pass
+ raise TemplateNotFound(template)
+
+ @internalcode
def load(
self,
environment: "Environment",
name: str,
globals: t.Optional[t.MutableMapping[str, t.Any]] = None,
) -> "Template":
- for loader in self.loaders:
- try:
- return loader.load(environment, name, globals)
- except TemplateNotFound:
- pass
- raise TemplateNotFound(name)
-
+ for loader in self.loaders:
+ try:
+ return loader.load(environment, name, globals)
+ except TemplateNotFound:
+ pass
+ raise TemplateNotFound(name)
+
def list_templates(self) -> t.List[str]:
- found = set()
- for loader in self.loaders:
- found.update(loader.list_templates())
- return sorted(found)
-
-
-class _TemplateModule(ModuleType):
- """Like a normal module but with support for weak references"""
-
-
-class ModuleLoader(BaseLoader):
- """This loader loads templates from precompiled templates.
-
- Example usage:
-
- >>> loader = ChoiceLoader([
- ... ModuleLoader('/path/to/compiled/templates'),
- ... FileSystemLoader('/path/to/templates')
- ... ])
-
- Templates can be precompiled with :meth:`Environment.compile_templates`.
- """
-
- has_source_access = False
-
+ found = set()
+ for loader in self.loaders:
+ found.update(loader.list_templates())
+ return sorted(found)
+
+
+class _TemplateModule(ModuleType):
+ """Like a normal module but with support for weak references"""
+
+
+class ModuleLoader(BaseLoader):
+ """This loader loads templates from precompiled templates.
+
+ Example usage:
+
+ >>> loader = ChoiceLoader([
+ ... ModuleLoader('/path/to/compiled/templates'),
+ ... FileSystemLoader('/path/to/templates')
+ ... ])
+
+ Templates can be precompiled with :meth:`Environment.compile_templates`.
+ """
+
+ has_source_access = False
+
def __init__(
self, path: t.Union[str, os.PathLike, t.Sequence[t.Union[str, os.PathLike]]]
) -> None:
package_name = f"_jinja2_module_templates_{id(self):x}"
-
- # create a fake module that looks for the templates in the
- # path given.
- mod = _TemplateModule(package_name)
+
+ # create a fake module that looks for the templates in the
+ # path given.
+ mod = _TemplateModule(package_name)
if not isinstance(path, abc.Iterable) or isinstance(path, str):
- path = [path]
-
+ path = [path]
+
mod.__path__ = [os.fspath(p) for p in path] # type: ignore
-
+
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
- # loader that created it goes out of business.
- self.module = mod
- self.package_name = package_name
-
- @staticmethod
+ # the only strong reference, the sys.modules entry is weak
+ # so that the garbage collector can remove it once the
+ # loader that created it goes out of business.
+ self.module = mod
+ self.package_name = package_name
+
+ @staticmethod
def get_template_key(name: str) -> str:
return "tmpl_" + sha1(name.encode("utf-8")).hexdigest()
-
- @staticmethod
+
+ @staticmethod
def get_module_filename(name: str) -> str:
return ModuleLoader.get_template_key(name) + ".py"
-
- @internalcode
+
+ @internalcode
def load(
self,
environment: "Environment",
name: str,
globals: t.Optional[t.MutableMapping[str, t.Any]] = None,
) -> "Template":
- key = self.get_template_key(name)
+ key = self.get_template_key(name)
module = f"{self.package_name}.{key}"
- mod = getattr(self.module, module, None)
+ mod = getattr(self.module, module, None)
- if mod is None:
- try:
+ if mod is None:
+ try:
mod = __import__(module, None, None, ["root"])
except ImportError as e:
raise TemplateNotFound(name) from e
-
- # remove the entry from sys.modules, we only want the attribute
- # on the module object we have stored on the loader.
- sys.modules.pop(module, None)
-
+
+ # remove the entry from sys.modules, we only want the attribute
+ # on the module object we have stored on the loader.
+ sys.modules.pop(module, None)
+
if globals is None:
globals = {}
- return environment.template_class.from_module_dict(
+ return environment.template_class.from_module_dict(
environment, mod.__dict__, globals
)
-
-
-class ResourceLoader(BaseLoader):
- def __init__(self, prefix, module_loader):
- self.prefix = prefix
- self.module_loader = module_loader
-
- def get_source(self, environment, template):
- if self.module_loader is None:
- raise TemplateNotFound(template)
- try:
+
+
+class ResourceLoader(BaseLoader):
+ def __init__(self, prefix, module_loader):
+ self.prefix = prefix
+ self.module_loader = module_loader
+
+ def get_source(self, environment, template):
+ if self.module_loader is None:
+ raise TemplateNotFound(template)
+ try:
return self.module_loader.get_data(os.path.join(self.prefix, template)).decode('utf-8'), None, None
- except IOError:
+ except IOError:
raise TemplateNotFound(template)
diff --git a/contrib/python/Jinja2/py3/jinja2/meta.py b/contrib/python/Jinja2/py3/jinja2/meta.py
index 0057d6eaba..68bc177a32 100644
--- a/contrib/python/Jinja2/py3/jinja2/meta.py
+++ b/contrib/python/Jinja2/py3/jinja2/meta.py
@@ -1,111 +1,111 @@
"""Functions that expose information about templates that might be
interesting for introspection.
-"""
+"""
import typing as t
from . import nodes
from .compiler import CodeGenerator
from .compiler import Frame
-
+
if t.TYPE_CHECKING:
from .environment import Environment
+
-
-class TrackingCodeGenerator(CodeGenerator):
- """We abuse the code generator for introspection."""
-
+class TrackingCodeGenerator(CodeGenerator):
+ """We abuse the code generator for introspection."""
+
def __init__(self, environment: "Environment") -> None:
super().__init__(environment, "<introspection>", "<introspection>")
self.undeclared_identifiers: t.Set[str] = set()
-
+
def write(self, x: str) -> None:
- """Don't write."""
-
+ """Don't write."""
+
def enter_frame(self, frame: Frame) -> None:
- """Remember all undeclared identifiers."""
+ """Remember all undeclared identifiers."""
super().enter_frame(frame)
for _, (action, param) in frame.symbols.loads.items():
if action == "resolve" and param not in self.environment.globals:
- self.undeclared_identifiers.add(param)
-
-
+ self.undeclared_identifiers.add(param)
+
+
def find_undeclared_variables(ast: nodes.Template) -> t.Set[str]:
- """Returns a set of all variables in the AST that will be looked up from
- the context at runtime. Because at compile time it's not known which
- variables will be used depending on the path the execution takes at
- runtime, all variables are returned.
-
- >>> from jinja2 import Environment, meta
- >>> env = Environment()
- >>> ast = env.parse('{% set foo = 42 %}{{ bar + foo }}')
+ """Returns a set of all variables in the AST that will be looked up from
+ the context at runtime. Because at compile time it's not known which
+ variables will be used depending on the path the execution takes at
+ runtime, all variables are returned.
+
+ >>> from jinja2 import Environment, meta
+ >>> env = Environment()
+ >>> ast = env.parse('{% set foo = 42 %}{{ bar + foo }}')
>>> meta.find_undeclared_variables(ast) == {'bar'}
- True
-
- .. admonition:: Implementation
-
- Internally the code generator is used for finding undeclared variables.
- This is good to know because the code generator might raise a
- :exc:`TemplateAssertionError` during compilation and as a matter of
- fact this function can currently raise that exception as well.
- """
+ True
+
+ .. admonition:: Implementation
+
+ Internally the code generator is used for finding undeclared variables.
+ This is good to know because the code generator might raise a
+ :exc:`TemplateAssertionError` during compilation and as a matter of
+ fact this function can currently raise that exception as well.
+ """
codegen = TrackingCodeGenerator(ast.environment) # type: ignore
- codegen.visit(ast)
- return codegen.undeclared_identifiers
-
-
+ codegen.visit(ast)
+ return codegen.undeclared_identifiers
+
+
_ref_types = (nodes.Extends, nodes.FromImport, nodes.Import, nodes.Include)
_RefType = t.Union[nodes.Extends, nodes.FromImport, nodes.Import, nodes.Include]
def find_referenced_templates(ast: nodes.Template) -> t.Iterator[t.Optional[str]]:
- """Finds all the referenced templates from the AST. This will return an
- iterator over all the hardcoded template extensions, inclusions and
- imports. If dynamic inheritance or inclusion is used, `None` will be
- yielded.
-
- >>> from jinja2 import Environment, meta
- >>> env = Environment()
- >>> ast = env.parse('{% extends "layout.html" %}{% include helper %}')
- >>> list(meta.find_referenced_templates(ast))
- ['layout.html', None]
-
- This function is useful for dependency tracking. For example if you want
- to rebuild parts of the website after a layout template has changed.
- """
+ """Finds all the referenced templates from the AST. This will return an
+ iterator over all the hardcoded template extensions, inclusions and
+ imports. If dynamic inheritance or inclusion is used, `None` will be
+ yielded.
+
+ >>> from jinja2 import Environment, meta
+ >>> env = Environment()
+ >>> ast = env.parse('{% extends "layout.html" %}{% include helper %}')
+ >>> list(meta.find_referenced_templates(ast))
+ ['layout.html', None]
+
+ This function is useful for dependency tracking. For example if you want
+ to rebuild parts of the website after a layout template has changed.
+ """
template_name: t.Any
for node in ast.find_all(_ref_types):
template: nodes.Expr = node.template # type: ignore
if not isinstance(template, nodes.Const):
- # a tuple with some non consts in there
+ # a tuple with some non consts in there
if isinstance(template, (nodes.Tuple, nodes.List)):
for template_name in template.items:
- # something const, only yield the strings and ignore
- # non-string consts that really just make no sense
- if isinstance(template_name, nodes.Const):
+ # something const, only yield the strings and ignore
+ # non-string consts that really just make no sense
+ if isinstance(template_name, nodes.Const):
if isinstance(template_name.value, str):
- yield template_name.value
- # something dynamic in there
- else:
- yield None
- # something dynamic we don't know about here
- else:
- yield None
- continue
- # constant is a basestring, direct template name
+ yield template_name.value
+ # something dynamic in there
+ else:
+ yield None
+ # something dynamic we don't know about here
+ else:
+ yield None
+ continue
+ # constant is a basestring, direct template name
if isinstance(template.value, str):
yield template.value
- # 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
+ # 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(
template.value, (tuple, list)
):
for template_name in template.value:
if isinstance(template_name, str):
- yield template_name
- # something else we don't care about, we could warn here
- else:
- yield None
+ yield template_name
+ # something else we don't care about, we could warn here
+ else:
+ yield None
diff --git a/contrib/python/Jinja2/py3/jinja2/nativetypes.py b/contrib/python/Jinja2/py3/jinja2/nativetypes.py
index 20597d50ab..9aa62fce57 100644
--- a/contrib/python/Jinja2/py3/jinja2/nativetypes.py
+++ b/contrib/python/Jinja2/py3/jinja2/nativetypes.py
@@ -1,16 +1,16 @@
import typing as t
-from ast import literal_eval
+from ast import literal_eval
from ast import parse
from itertools import chain
from itertools import islice
-
+
from . import nodes
from .compiler import CodeGenerator
from .compiler import Frame
from .compiler import has_safe_repr
from .environment import Environment
from .environment import Template
-
+
def native_concat(values: t.Iterable[t.Any]) -> t.Optional[t.Any]:
"""Return a native Python type from the list of compiled nodes. If
@@ -20,97 +20,97 @@ def native_concat(values: t.Iterable[t.Any]) -> t.Optional[t.Any]:
the string is returned.
:param values: Iterable of outputs to concatenate.
- """
+ """
head = list(islice(values, 2))
-
- if not head:
- return None
-
- if len(head) == 1:
+
+ if not head:
+ return None
+
+ if len(head) == 1:
raw = head[0]
if not isinstance(raw, str):
return raw
- else:
+ else:
raw = "".join([str(v) for v in chain(head, values)])
-
- try:
+
+ try:
return literal_eval(
# In Python 3.10+ ast.literal_eval removes leading spaces/tabs
# from the given string. For backwards compatibility we need to
# parse the string ourselves without removing leading spaces/tabs.
parse(raw, mode="eval")
)
- except (ValueError, SyntaxError, MemoryError):
+ except (ValueError, SyntaxError, MemoryError):
return raw
-
-
-class NativeCodeGenerator(CodeGenerator):
+
+
+class NativeCodeGenerator(CodeGenerator):
"""A code generator which renders Python types by not adding
``str()`` around output nodes.
- """
-
+ """
+
@staticmethod
def _default_finalize(value: t.Any) -> t.Any:
return value
-
+
def _output_const_repr(self, group: t.Iterable[t.Any]) -> str:
return repr("".join([str(v) for v in group]))
-
+
def _output_child_to_const(
self, node: nodes.Expr, frame: Frame, finalize: CodeGenerator._FinalizeInfo
) -> t.Any:
const = node.as_const(frame.eval_ctx)
-
+
if not has_safe_repr(const):
raise nodes.Impossible()
-
+
if isinstance(node, nodes.TemplateData):
return const
-
+
return finalize.const(const) # type: ignore
-
+
def _output_child_pre(
self, node: nodes.Expr, frame: Frame, finalize: CodeGenerator._FinalizeInfo
) -> None:
if finalize.src is not None:
self.write(finalize.src)
-
+
def _output_child_post(
self, node: nodes.Expr, frame: Frame, finalize: CodeGenerator._FinalizeInfo
) -> None:
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: t.Any, **kwargs: t.Any) -> t.Any:
"""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.
- """
+ """
ctx = self.new_context(dict(*args, **kwargs))
-
- try:
+
+ try:
return native_concat(self.root_render_func(ctx)) # type: ignore
- except Exception:
+ except Exception:
return self.environment.handle_exception()
-
+
async def render_async(self, *args: t.Any, **kwargs: t.Any) -> t.Any:
if not self.environment.is_async:
raise RuntimeError(
"The environment was not created with async mode enabled."
)
-
+
ctx = self.new_context(dict(*args, **kwargs))
try:
diff --git a/contrib/python/Jinja2/py3/jinja2/nodes.py b/contrib/python/Jinja2/py3/jinja2/nodes.py
index b2f88d9d9c..8849eb1206 100644
--- a/contrib/python/Jinja2/py3/jinja2/nodes.py
+++ b/contrib/python/Jinja2/py3/jinja2/nodes.py
@@ -1,16 +1,16 @@
"""AST nodes generated by the parser for the compiler. Also provides
some node tree helper functions used by the parser and compiler in order
to normalize nodes.
-"""
+"""
import inspect
-import operator
+import operator
import typing as t
-from collections import deque
-
+from collections import deque
+
from markupsafe import Markup
-
+
from .utils import _PassArg
-
+
if t.TYPE_CHECKING:
import typing_extensions as te
from .environment import Environment
@@ -25,14 +25,14 @@ _binop_to_func: t.Dict[str, t.Callable[[t.Any, t.Any], t.Any]] = {
"%": operator.mod,
"+": operator.add,
"-": operator.sub,
-}
-
+}
+
_uaop_to_func: t.Dict[str, t.Callable[[t.Any], t.Any]] = {
"not": operator.not_,
"+": operator.pos,
"-": operator.neg,
}
-
+
_cmpop_to_func: t.Dict[str, t.Callable[[t.Any, t.Any], t.Any]] = {
"eq": operator.eq,
"ne": operator.ne,
@@ -42,287 +42,287 @@ _cmpop_to_func: t.Dict[str, t.Callable[[t.Any, t.Any], t.Any]] = {
"lteq": operator.le,
"in": lambda a, b: a in b,
"notin": lambda a, b: a not in b,
-}
-
-
-class Impossible(Exception):
- """Raised if the node could not perform a requested action."""
-
-
-class NodeType(type):
- """A metaclass for nodes that handles the field and attribute
- inheritance. fields and attributes from the parent class are
- automatically forwarded to the child."""
-
+}
+
+
+class Impossible(Exception):
+ """Raised if the node could not perform a requested action."""
+
+
+class NodeType(type):
+ """A metaclass for nodes that handles the field and attribute
+ inheritance. fields and attributes from the parent class are
+ automatically forwarded to the child."""
+
def __new__(mcs, name, bases, d): # type: ignore
for attr in "fields", "attributes":
- storage = []
+ storage = []
storage.extend(getattr(bases[0] if bases else object, attr, ()))
- storage.extend(d.get(attr, ()))
+ storage.extend(d.get(attr, ()))
assert len(bases) <= 1, "multiple inheritance not allowed"
assert len(storage) == len(set(storage)), "layout conflict"
- d[attr] = tuple(storage)
+ d[attr] = tuple(storage)
d.setdefault("abstract", False)
return type.__new__(mcs, name, bases, d)
-
-
+
+
class EvalContext:
- """Holds evaluation time information. Custom attributes can be attached
- to it in extensions.
- """
-
+ """Holds evaluation time information. Custom attributes can be attached
+ to it in extensions.
+ """
+
def __init__(
self, environment: "Environment", template_name: t.Optional[str] = None
) -> None:
- self.environment = environment
- if callable(environment.autoescape):
- self.autoescape = environment.autoescape(template_name)
- else:
- self.autoescape = environment.autoescape
- self.volatile = False
-
+ self.environment = environment
+ if callable(environment.autoescape):
+ self.autoescape = environment.autoescape(template_name)
+ else:
+ self.autoescape = environment.autoescape
+ self.volatile = False
+
def save(self) -> t.Mapping[str, t.Any]:
- return self.__dict__.copy()
-
+ return self.__dict__.copy()
+
def revert(self, old: t.Mapping[str, t.Any]) -> None:
- self.__dict__.clear()
- self.__dict__.update(old)
-
-
+ self.__dict__.clear()
+ self.__dict__.update(old)
+
+
def get_eval_context(node: "Node", ctx: t.Optional[EvalContext]) -> EvalContext:
- if ctx is None:
- if node.environment is None:
+ if ctx is None:
+ if node.environment is None:
raise RuntimeError(
"if no eval context is passed, the node must have an"
" attached environment."
)
- return EvalContext(node.environment)
- return ctx
-
-
+ return EvalContext(node.environment)
+ return ctx
+
+
class Node(metaclass=NodeType):
"""Baseclass for all Jinja nodes. There are a number of nodes available
- of different types. There are four major types:
-
- - :class:`Stmt`: statements
- - :class:`Expr`: expressions
- - :class:`Helper`: helper nodes
- - :class:`Template`: the outermost wrapper node
-
- All nodes have fields and attributes. Fields may be other nodes, lists,
- or arbitrary values. Fields are passed to the constructor as regular
- positional arguments, attributes as keyword arguments. Each node has
- two attributes: `lineno` (the line number of the node) and `environment`.
- The `environment` attribute is set at the end of the parsing process for
- all nodes automatically.
- """
+ of different types. There are four major types:
+
+ - :class:`Stmt`: statements
+ - :class:`Expr`: expressions
+ - :class:`Helper`: helper nodes
+ - :class:`Template`: the outermost wrapper node
+
+ All nodes have fields and attributes. Fields may be other nodes, lists,
+ or arbitrary values. Fields are passed to the constructor as regular
+ positional arguments, attributes as keyword arguments. Each node has
+ two attributes: `lineno` (the line number of the node) and `environment`.
+ The `environment` attribute is set at the end of the parsing process for
+ all nodes automatically.
+ """
fields: t.Tuple[str, ...] = ()
attributes: t.Tuple[str, ...] = ("lineno", "environment")
- abstract = True
-
+ abstract = True
+
lineno: int
environment: t.Optional["Environment"]
def __init__(self, *fields: t.Any, **attributes: t.Any) -> None:
- if self.abstract:
+ if self.abstract:
raise TypeError("abstract nodes are not instantiable")
- if fields:
- if len(fields) != len(self.fields):
- if not self.fields:
+ if fields:
+ if len(fields) != len(self.fields):
+ if not self.fields:
raise TypeError(f"{type(self).__name__!r} takes 0 arguments")
raise TypeError(
f"{type(self).__name__!r} takes 0 or {len(self.fields)}"
f" argument{'s' if len(self.fields) != 1 else ''}"
)
for name, arg in zip(self.fields, fields):
- setattr(self, name, arg)
- for attr in self.attributes:
- setattr(self, attr, attributes.pop(attr, None))
- if attributes:
+ setattr(self, name, arg)
+ for attr in self.attributes:
+ setattr(self, attr, attributes.pop(attr, None))
+ if attributes:
raise TypeError(f"unknown attribute {next(iter(attributes))!r}")
-
+
def iter_fields(
self,
exclude: t.Optional[t.Container[str]] = None,
only: t.Optional[t.Container[str]] = None,
) -> t.Iterator[t.Tuple[str, t.Any]]:
- """This method iterates over all fields that are defined and yields
- ``(key, value)`` tuples. Per default all fields are returned, but
- it's possible to limit that to some fields by providing the `only`
- parameter or to exclude some using the `exclude` parameter. Both
- should be sets or tuples of field names.
- """
- for name in self.fields:
+ """This method iterates over all fields that are defined and yields
+ ``(key, value)`` tuples. Per default all fields are returned, but
+ it's possible to limit that to some fields by providing the `only`
+ parameter or to exclude some using the `exclude` parameter. Both
+ should be sets or tuples of field names.
+ """
+ for name in self.fields:
if (
(exclude is None and only is None)
or (exclude is not None and name not in exclude)
or (only is not None and name in only)
):
- try:
- yield name, getattr(self, name)
- except AttributeError:
- pass
-
+ try:
+ yield name, getattr(self, name)
+ except AttributeError:
+ pass
+
def iter_child_nodes(
self,
exclude: t.Optional[t.Container[str]] = None,
only: t.Optional[t.Container[str]] = None,
) -> t.Iterator["Node"]:
- """Iterates over all direct child nodes of the node. This iterates
- over all fields and yields the values of they are nodes. If the value
- of a field is a list all the nodes in that list are returned.
- """
+ """Iterates over all direct child nodes of the node. This iterates
+ over all fields and yields the values of they are nodes. If the value
+ of a field is a list all the nodes in that list are returned.
+ """
for _, item in self.iter_fields(exclude, only):
- if isinstance(item, list):
- for n in item:
- if isinstance(n, Node):
- yield n
- elif isinstance(item, Node):
- yield item
-
+ if isinstance(item, list):
+ for n in item:
+ if isinstance(n, Node):
+ yield n
+ elif isinstance(item, Node):
+ yield item
+
def find(self, node_type: t.Type[_NodeBound]) -> t.Optional[_NodeBound]:
- """Find the first node of a given type. If no such node exists the
- return value is `None`.
- """
- for result in self.find_all(node_type):
- return result
-
+ """Find the first node of a given type. If no such node exists the
+ return value is `None`.
+ """
+ for result in self.find_all(node_type):
+ return result
+
return None
def find_all(
self, node_type: t.Union[t.Type[_NodeBound], t.Tuple[t.Type[_NodeBound], ...]]
) -> t.Iterator[_NodeBound]:
- """Find all the nodes of a given type. If the type is a tuple,
- the check is performed for any of the tuple items.
- """
- for child in self.iter_child_nodes():
- if isinstance(child, node_type):
+ """Find all the nodes of a given type. If the type is a tuple,
+ the check is performed for any of the tuple items.
+ """
+ for child in self.iter_child_nodes():
+ if isinstance(child, node_type):
yield child # type: ignore
yield from child.find_all(node_type)
-
+
def set_ctx(self, ctx: str) -> "Node":
- """Reset the context of a node and all child nodes. Per default the
- parser will all generate nodes that have a 'load' context as it's the
- most common one. This method is used in the parser to set assignment
- targets and other nodes to a store context.
- """
- todo = deque([self])
- while todo:
- node = todo.popleft()
+ """Reset the context of a node and all child nodes. Per default the
+ parser will all generate nodes that have a 'load' context as it's the
+ most common one. This method is used in the parser to set assignment
+ targets and other nodes to a store context.
+ """
+ todo = deque([self])
+ while todo:
+ node = todo.popleft()
if "ctx" in node.fields:
node.ctx = ctx # type: ignore
- todo.extend(node.iter_child_nodes())
- return self
-
+ todo.extend(node.iter_child_nodes())
+ return self
+
def set_lineno(self, lineno: int, override: bool = False) -> "Node":
- """Set the line numbers of the node and children."""
- todo = deque([self])
- while todo:
- node = todo.popleft()
+ """Set the line numbers of the node and children."""
+ todo = deque([self])
+ while todo:
+ node = todo.popleft()
if "lineno" in node.attributes:
- if node.lineno is None or override:
- node.lineno = lineno
- todo.extend(node.iter_child_nodes())
- return self
-
+ if node.lineno is None or override:
+ node.lineno = lineno
+ todo.extend(node.iter_child_nodes())
+ return self
+
def set_environment(self, environment: "Environment") -> "Node":
- """Set the environment for all nodes."""
- todo = deque([self])
- while todo:
- node = todo.popleft()
- node.environment = environment
- todo.extend(node.iter_child_nodes())
- return self
-
+ """Set the environment for all nodes."""
+ todo = deque([self])
+ while todo:
+ node = todo.popleft()
+ node.environment = environment
+ todo.extend(node.iter_child_nodes())
+ return self
+
def __eq__(self, other: t.Any) -> bool:
if type(self) is not type(other):
return NotImplemented
-
+
return tuple(self.iter_fields()) == tuple(other.iter_fields())
-
+
__hash__ = object.__hash__
-
+
def __repr__(self) -> str:
args_str = ", ".join(f"{a}={getattr(self, a, None)!r}" for a in self.fields)
return f"{type(self).__name__}({args_str})"
-
+
def dump(self) -> str:
def _dump(node: t.Union[Node, t.Any]) -> None:
- if not isinstance(node, Node):
- buf.append(repr(node))
- return
-
+ if not isinstance(node, Node):
+ buf.append(repr(node))
+ return
+
buf.append(f"nodes.{type(node).__name__}(")
- if not node.fields:
+ if not node.fields:
buf.append(")")
- return
- for idx, field in enumerate(node.fields):
- if idx:
+ return
+ for idx, field in enumerate(node.fields):
+ if idx:
buf.append(", ")
- value = getattr(node, field)
- if isinstance(value, list):
+ value = getattr(node, field)
+ if isinstance(value, list):
buf.append("[")
- for idx, item in enumerate(value):
- if idx:
+ for idx, item in enumerate(value):
+ if idx:
buf.append(", ")
- _dump(item)
+ _dump(item)
buf.append("]")
- else:
- _dump(value)
+ else:
+ _dump(value)
buf.append(")")
buf: t.List[str] = []
- _dump(self)
+ _dump(self)
return "".join(buf)
-
-
-class Stmt(Node):
- """Base node for all statements."""
-
- abstract = True
-
-
-class Helper(Node):
- """Nodes that exist in a specific context only."""
-
- abstract = True
-
-
-class Template(Node):
- """Node that represents a template. This must be the outermost node that
- is passed to the compiler.
- """
-
+
+
+class Stmt(Node):
+ """Base node for all statements."""
+
+ abstract = True
+
+
+class Helper(Node):
+ """Nodes that exist in a specific context only."""
+
+ abstract = True
+
+
+class Template(Node):
+ """Node that represents a template. This must be the outermost node that
+ is passed to the compiler.
+ """
+
fields = ("body",)
body: t.List[Node]
+
-
-class Output(Stmt):
- """A node that holds multiple expressions which are then printed out.
- This is used both for the `print` statement and the regular template data.
- """
-
+class Output(Stmt):
+ """A node that holds multiple expressions which are then printed out.
+ This is used both for the `print` statement and the regular template data.
+ """
+
fields = ("nodes",)
nodes: t.List["Expr"]
+
-
-class Extends(Stmt):
- """Represents an extends statement."""
-
+class Extends(Stmt):
+ """Represents an extends statement."""
+
fields = ("template",)
template: "Expr"
-
-
-class For(Stmt):
- """The for loop. `target` is the target for the iteration (usually a
- :class:`Name` or :class:`Tuple`), `iter` the iterable. `body` is a list
- of nodes that are used as loop-body, and `else_` a list of nodes for the
- `else` block. If no else node exists it has to be an empty list.
-
- For filtered nodes an expression can be stored as `test`, otherwise `None`.
- """
-
+
+
+class For(Stmt):
+ """The for loop. `target` is the target for the iteration (usually a
+ :class:`Name` or :class:`Tuple`), `iter` the iterable. `body` is a list
+ of nodes that are used as loop-body, and `else_` a list of nodes for the
+ `else` block. If no else node exists it has to be an empty list.
+
+ For filtered nodes an expression can be stored as `test`, otherwise `None`.
+ """
+
fields = ("target", "iter", "body", "else_", "test", "recursive")
target: Node
iter: Node
@@ -330,71 +330,71 @@ class For(Stmt):
else_: t.List[Node]
test: t.Optional[Node]
recursive: bool
+
-
-class If(Stmt):
- """If `test` is true, `body` is rendered, else `else_`."""
-
+class If(Stmt):
+ """If `test` is true, `body` is rendered, else `else_`."""
+
fields = ("test", "body", "elif_", "else_")
test: Node
body: t.List[Node]
elif_: t.List["If"]
else_: t.List[Node]
-
-
-class Macro(Stmt):
- """A macro definition. `name` is the name of the macro, `args` a list of
- arguments and `defaults` a list of defaults if there are any. `body` is
- a list of nodes for the macro body.
- """
-
+
+
+class Macro(Stmt):
+ """A macro definition. `name` is the name of the macro, `args` a list of
+ arguments and `defaults` a list of defaults if there are any. `body` is
+ a list of nodes for the macro body.
+ """
+
fields = ("name", "args", "defaults", "body")
name: str
args: t.List["Name"]
defaults: t.List["Expr"]
body: t.List[Node]
+
-
-class CallBlock(Stmt):
- """Like a macro without a name but a call instead. `call` is called with
- the unnamed macro as `caller` argument this node holds.
- """
-
+class CallBlock(Stmt):
+ """Like a macro without a name but a call instead. `call` is called with
+ the unnamed macro as `caller` argument this node holds.
+ """
+
fields = ("call", "args", "defaults", "body")
call: "Call"
args: t.List["Name"]
defaults: t.List["Expr"]
body: t.List[Node]
+
-
-class FilterBlock(Stmt):
- """Node for filter sections."""
-
+class FilterBlock(Stmt):
+ """Node for filter sections."""
+
fields = ("body", "filter")
body: t.List[Node]
filter: "Filter"
-
-
-class With(Stmt):
- """Specific node for with statements. In older versions of Jinja the
- with statement was implemented on the base of the `Scope` node instead.
-
- .. versionadded:: 2.9.3
- """
-
+
+
+class With(Stmt):
+ """Specific node for with statements. In older versions of Jinja the
+ with statement was implemented on the base of the `Scope` node instead.
+
+ .. versionadded:: 2.9.3
+ """
+
fields = ("targets", "values", "body")
targets: t.List["Expr"]
values: t.List["Expr"]
body: t.List[Node]
+
-
-class Block(Stmt):
+class Block(Stmt):
"""A node that represents a block.
-
+
.. versionchanged:: 3.0.0
the `required` field was added.
"""
-
+
fields = ("name", "body", "scoped", "required")
name: str
body: t.List[Node]
@@ -402,272 +402,272 @@ class Block(Stmt):
required: bool
-class Include(Stmt):
- """A node that represents the include tag."""
-
+class Include(Stmt):
+ """A node that represents the include tag."""
+
fields = ("template", "with_context", "ignore_missing")
template: "Expr"
with_context: bool
ignore_missing: bool
+
-
-class Import(Stmt):
- """A node that represents the import tag."""
-
+class Import(Stmt):
+ """A node that represents the import tag."""
+
fields = ("template", "target", "with_context")
template: "Expr"
target: str
with_context: bool
-
-
-class FromImport(Stmt):
- """A node that represents the from import tag. It's important to not
- pass unsafe names to the name attribute. The compiler translates the
- attribute lookups directly into getattr calls and does *not* use the
- subscript callback of the interface. As exported variables may not
- start with double underscores (which the parser asserts) this is not a
- problem for regular Jinja code, but if this node is used in an extension
- extra care must be taken.
-
- The list of names may contain tuples if aliases are wanted.
- """
-
+
+
+class FromImport(Stmt):
+ """A node that represents the from import tag. It's important to not
+ pass unsafe names to the name attribute. The compiler translates the
+ attribute lookups directly into getattr calls and does *not* use the
+ subscript callback of the interface. As exported variables may not
+ start with double underscores (which the parser asserts) this is not a
+ problem for regular Jinja code, but if this node is used in an extension
+ extra care must be taken.
+
+ The list of names may contain tuples if aliases are wanted.
+ """
+
fields = ("template", "names", "with_context")
template: "Expr"
names: t.List[t.Union[str, t.Tuple[str, str]]]
with_context: bool
+
-
-class ExprStmt(Stmt):
- """A statement that evaluates an expression and discards the result."""
-
+class ExprStmt(Stmt):
+ """A statement that evaluates an expression and discards the result."""
+
fields = ("node",)
node: Node
+
-
-class Assign(Stmt):
- """Assigns an expression to a target."""
-
+class Assign(Stmt):
+ """Assigns an expression to a target."""
+
fields = ("target", "node")
target: "Expr"
node: Node
+
-
-class AssignBlock(Stmt):
- """Assigns a block to a target."""
-
+class AssignBlock(Stmt):
+ """Assigns a block to a target."""
+
fields = ("target", "filter", "body")
target: "Expr"
filter: t.Optional["Filter"]
body: t.List[Node]
+
+class Expr(Node):
+ """Baseclass for all expressions."""
-class Expr(Node):
- """Baseclass for all expressions."""
-
- abstract = True
-
+ abstract = True
+
def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:
- """Return the value of the expression as constant or raise
- :exc:`Impossible` if this was not possible.
-
- An :class:`EvalContext` can be provided, if none is given
- a default context is created which requires the nodes to have
- an attached environment.
-
- .. versionchanged:: 2.4
- the `eval_ctx` parameter was added.
- """
- raise Impossible()
-
+ """Return the value of the expression as constant or raise
+ :exc:`Impossible` if this was not possible.
+
+ An :class:`EvalContext` can be provided, if none is given
+ a default context is created which requires the nodes to have
+ an attached environment.
+
+ .. versionchanged:: 2.4
+ the `eval_ctx` parameter was added.
+ """
+ raise Impossible()
+
def can_assign(self) -> bool:
- """Check if it's possible to assign something to this node."""
- return False
-
-
-class BinExpr(Expr):
- """Baseclass for all binary expressions."""
+ """Check if it's possible to assign something to this node."""
+ return False
+
+
+class BinExpr(Expr):
+ """Baseclass for all binary expressions."""
fields = ("left", "right")
left: Expr
right: Expr
operator: str
- abstract = True
-
+ abstract = True
+
def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:
- eval_ctx = get_eval_context(self, eval_ctx)
+ eval_ctx = get_eval_context(self, eval_ctx)
- # intercepted operators cannot be folded at compile time
+ # intercepted operators cannot be folded at compile time
if (
eval_ctx.environment.sandboxed
and self.operator in eval_ctx.environment.intercepted_binops # type: ignore
):
- raise Impossible()
- f = _binop_to_func[self.operator]
- try:
- return f(self.left.as_const(eval_ctx), self.right.as_const(eval_ctx))
+ raise Impossible()
+ f = _binop_to_func[self.operator]
+ try:
+ return f(self.left.as_const(eval_ctx), self.right.as_const(eval_ctx))
except Exception as e:
raise Impossible() from e
-
-
-class UnaryExpr(Expr):
- """Baseclass for all unary expressions."""
+
+
+class UnaryExpr(Expr):
+ """Baseclass for all unary expressions."""
fields = ("node",)
node: Expr
operator: str
- abstract = True
-
+ abstract = True
+
def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:
- eval_ctx = get_eval_context(self, eval_ctx)
+ eval_ctx = get_eval_context(self, eval_ctx)
- # intercepted operators cannot be folded at compile time
+ # intercepted operators cannot be folded at compile time
if (
eval_ctx.environment.sandboxed
and self.operator in eval_ctx.environment.intercepted_unops # type: ignore
):
- raise Impossible()
- f = _uaop_to_func[self.operator]
- try:
- return f(self.node.as_const(eval_ctx))
+ raise Impossible()
+ f = _uaop_to_func[self.operator]
+ try:
+ return f(self.node.as_const(eval_ctx))
except Exception as e:
raise Impossible() from e
-
-
-class Name(Expr):
- """Looks up a name or stores a value in a name.
- The `ctx` of the node can be one of the following values:
-
- - `store`: store a value in the name
- - `load`: load that name
- - `param`: like `store` but if the name was defined as function parameter.
- """
-
+
+
+class Name(Expr):
+ """Looks up a name or stores a value in a name.
+ The `ctx` of the node can be one of the following values:
+
+ - `store`: store a value in the name
+ - `load`: load that name
+ - `param`: like `store` but if the name was defined as function parameter.
+ """
+
fields = ("name", "ctx")
name: str
ctx: str
def can_assign(self) -> bool:
return self.name not in {"true", "false", "none", "True", "False", "None"}
-
-
-class NSRef(Expr):
- """Reference to a namespace value assignment"""
-
+
+
+class NSRef(Expr):
+ """Reference to a namespace value assignment"""
+
fields = ("name", "attr")
name: str
attr: str
def can_assign(self) -> bool:
- # We don't need any special checks here; NSRef assignments have a
- # runtime check to ensure the target is a namespace object which will
- # have been checked already as it is created using a normal assignment
- # which goes through a `Name` node.
- return True
-
-
-class Literal(Expr):
- """Baseclass for literals."""
-
- abstract = True
-
-
-class Const(Literal):
- """All constant values. The parser will return this node for simple
- constants such as ``42`` or ``"foo"`` but it can be used to store more
- complex values such as lists too. Only constants with a safe
- representation (objects where ``eval(repr(x)) == x`` is true).
- """
-
+ # We don't need any special checks here; NSRef assignments have a
+ # runtime check to ensure the target is a namespace object which will
+ # have been checked already as it is created using a normal assignment
+ # which goes through a `Name` node.
+ return True
+
+
+class Literal(Expr):
+ """Baseclass for literals."""
+
+ abstract = True
+
+
+class Const(Literal):
+ """All constant values. The parser will return this node for simple
+ constants such as ``42`` or ``"foo"`` but it can be used to store more
+ complex values such as lists too. Only constants with a safe
+ representation (objects where ``eval(repr(x)) == x`` is true).
+ """
+
fields = ("value",)
value: t.Any
def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:
return self.value
-
- @classmethod
+
+ @classmethod
def from_untrusted(
cls,
value: t.Any,
lineno: t.Optional[int] = None,
environment: "t.Optional[Environment]" = None,
) -> "Const":
- """Return a const object if the value is representable as
- constant value in the generated code, otherwise it will raise
- an `Impossible` exception.
- """
- from .compiler import has_safe_repr
-
- if not has_safe_repr(value):
- raise Impossible()
- return cls(value, lineno=lineno, environment=environment)
-
-
-class TemplateData(Literal):
- """A constant template string."""
-
+ """Return a const object if the value is representable as
+ constant value in the generated code, otherwise it will raise
+ an `Impossible` exception.
+ """
+ from .compiler import has_safe_repr
+
+ if not has_safe_repr(value):
+ raise Impossible()
+ return cls(value, lineno=lineno, environment=environment)
+
+
+class TemplateData(Literal):
+ """A constant template string."""
+
fields = ("data",)
data: str
def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> str:
- eval_ctx = get_eval_context(self, eval_ctx)
- if eval_ctx.volatile:
- raise Impossible()
- if eval_ctx.autoescape:
- return Markup(self.data)
- return self.data
-
-
-class Tuple(Literal):
- """For loop unpacking and some other things like multiple arguments
- for subscripts. Like for :class:`Name` `ctx` specifies if the tuple
- is used for loading the names or storing.
- """
-
+ eval_ctx = get_eval_context(self, eval_ctx)
+ if eval_ctx.volatile:
+ raise Impossible()
+ if eval_ctx.autoescape:
+ return Markup(self.data)
+ return self.data
+
+
+class Tuple(Literal):
+ """For loop unpacking and some other things like multiple arguments
+ for subscripts. Like for :class:`Name` `ctx` specifies if the tuple
+ is used for loading the names or storing.
+ """
+
fields = ("items", "ctx")
items: t.List[Expr]
ctx: str
def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Tuple[t.Any, ...]:
- eval_ctx = get_eval_context(self, eval_ctx)
- return tuple(x.as_const(eval_ctx) for x in self.items)
-
+ eval_ctx = get_eval_context(self, eval_ctx)
+ return tuple(x.as_const(eval_ctx) for x in self.items)
+
def can_assign(self) -> bool:
- for item in self.items:
- if not item.can_assign():
- return False
- return True
-
-
-class List(Literal):
- """Any list literal such as ``[1, 2, 3]``"""
-
+ for item in self.items:
+ if not item.can_assign():
+ return False
+ return True
+
+
+class List(Literal):
+ """Any list literal such as ``[1, 2, 3]``"""
+
fields = ("items",)
items: t.List[Expr]
def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.List[t.Any]:
- eval_ctx = get_eval_context(self, eval_ctx)
- return [x.as_const(eval_ctx) for x in self.items]
-
-
-class Dict(Literal):
- """Any dict literal such as ``{1: 2, 3: 4}``. The items must be a list of
- :class:`Pair` nodes.
- """
-
+ eval_ctx = get_eval_context(self, eval_ctx)
+ return [x.as_const(eval_ctx) for x in self.items]
+
+
+class Dict(Literal):
+ """Any dict literal such as ``{1: 2, 3: 4}``. The items must be a list of
+ :class:`Pair` nodes.
+ """
+
fields = ("items",)
items: t.List["Pair"]
def as_const(
self, eval_ctx: t.Optional[EvalContext] = None
) -> t.Dict[t.Any, t.Any]:
- eval_ctx = get_eval_context(self, eval_ctx)
- return dict(x.as_const(eval_ctx) for x in self.items)
-
-
-class Pair(Helper):
- """A key, value pair for dicts."""
-
+ eval_ctx = get_eval_context(self, eval_ctx)
+ return dict(x.as_const(eval_ctx) for x in self.items)
+
+
+class Pair(Helper):
+ """A key, value pair for dicts."""
+
fields = ("key", "value")
key: Expr
value: Expr
@@ -675,65 +675,65 @@ class Pair(Helper):
def as_const(
self, eval_ctx: t.Optional[EvalContext] = None
) -> t.Tuple[t.Any, t.Any]:
- eval_ctx = get_eval_context(self, eval_ctx)
- return self.key.as_const(eval_ctx), self.value.as_const(eval_ctx)
-
-
-class Keyword(Helper):
- """A key, value pair for keyword arguments where key is a string."""
-
+ eval_ctx = get_eval_context(self, eval_ctx)
+ return self.key.as_const(eval_ctx), self.value.as_const(eval_ctx)
+
+
+class Keyword(Helper):
+ """A key, value pair for keyword arguments where key is a string."""
+
fields = ("key", "value")
key: str
value: Expr
def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Tuple[str, t.Any]:
- eval_ctx = get_eval_context(self, eval_ctx)
- return self.key, self.value.as_const(eval_ctx)
-
-
-class CondExpr(Expr):
- """A conditional expression (inline if expression). (``{{
- foo if bar else baz }}``)
- """
-
+ eval_ctx = get_eval_context(self, eval_ctx)
+ return self.key, self.value.as_const(eval_ctx)
+
+
+class CondExpr(Expr):
+ """A conditional expression (inline if expression). (``{{
+ foo if bar else baz }}``)
+ """
+
fields = ("test", "expr1", "expr2")
test: Expr
expr1: Expr
expr2: t.Optional[Expr]
def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:
- eval_ctx = get_eval_context(self, eval_ctx)
- if self.test.as_const(eval_ctx):
- return self.expr1.as_const(eval_ctx)
-
- # if we evaluate to an undefined object, we better do that at runtime
- if self.expr2 is None:
- raise Impossible()
-
- return self.expr2.as_const(eval_ctx)
-
-
+ eval_ctx = get_eval_context(self, eval_ctx)
+ if self.test.as_const(eval_ctx):
+ return self.expr1.as_const(eval_ctx)
+
+ # if we evaluate to an undefined object, we better do that at runtime
+ if self.expr2 is None:
+ raise Impossible()
+
+ return self.expr2.as_const(eval_ctx)
+
+
def args_as_const(
node: t.Union["_FilterTestCommon", "Call"], eval_ctx: t.Optional[EvalContext]
) -> t.Tuple[t.List[t.Any], t.Dict[t.Any, t.Any]]:
- args = [x.as_const(eval_ctx) for x in node.args]
- kwargs = dict(x.as_const(eval_ctx) for x in node.kwargs)
-
- if node.dyn_args is not None:
- try:
- args.extend(node.dyn_args.as_const(eval_ctx))
+ args = [x.as_const(eval_ctx) for x in node.args]
+ kwargs = dict(x.as_const(eval_ctx) for x in node.kwargs)
+
+ if node.dyn_args is not None:
+ try:
+ args.extend(node.dyn_args.as_const(eval_ctx))
except Exception as e:
raise Impossible() from e
-
- if node.dyn_kwargs is not None:
- try:
- kwargs.update(node.dyn_kwargs.as_const(eval_ctx))
+
+ if node.dyn_kwargs is not None:
+ try:
+ kwargs.update(node.dyn_kwargs.as_const(eval_ctx))
except Exception as e:
raise Impossible() from e
-
- return args, kwargs
-
-
+
+ return args, kwargs
+
+
class _FilterTestCommon(Expr):
fields = ("node", "name", "args", "kwargs", "dyn_args", "dyn_kwargs")
node: Expr
@@ -744,65 +744,65 @@ class _FilterTestCommon(Expr):
dyn_kwargs: t.Optional[Expr]
abstract = True
_is_filter = True
-
+
def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:
- eval_ctx = get_eval_context(self, eval_ctx)
-
+ eval_ctx = get_eval_context(self, eval_ctx)
+
if eval_ctx.volatile:
- raise Impossible()
-
+ raise Impossible()
+
if self._is_filter:
env_map = eval_ctx.environment.filters
else:
env_map = eval_ctx.environment.tests
-
+
func = env_map.get(self.name)
pass_arg = _PassArg.from_obj(func) # type: ignore
if func is None or pass_arg is _PassArg.context:
- raise Impossible()
-
+ raise Impossible()
+
if eval_ctx.environment.is_async and (
getattr(func, "jinja_async_variant", False) is True
or inspect.iscoroutinefunction(func)
- ):
- raise Impossible()
-
- args, kwargs = args_as_const(self, eval_ctx)
- args.insert(0, self.node.as_const(eval_ctx))
-
+ ):
+ raise Impossible()
+
+ args, kwargs = args_as_const(self, eval_ctx)
+ args.insert(0, self.node.as_const(eval_ctx))
+
if pass_arg is _PassArg.eval_context:
- args.insert(0, eval_ctx)
+ args.insert(0, eval_ctx)
elif pass_arg is _PassArg.environment:
args.insert(0, eval_ctx.environment)
-
- try:
+
+ try:
return func(*args, **kwargs)
except Exception as e:
raise Impossible() from e
-
-
+
+
class Filter(_FilterTestCommon):
"""Apply a filter to an expression. ``name`` is the name of the
filter, the other fields are the same as :class:`Call`.
If ``node`` is ``None``, the filter is being used in a filter block
and is applied to the content of the block.
- """
-
+ """
+
node: t.Optional[Expr] # type: ignore
-
+
def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:
if self.node is None:
- raise Impossible()
-
+ raise Impossible()
+
return super().as_const(eval_ctx=eval_ctx)
-
-
+
+
class Test(_FilterTestCommon):
"""Apply a test to an expression. ``name`` is the name of the test,
the other field are the same as :class:`Call`.
-
+
.. versionchanged:: 3.0
``as_const`` shares the same logic for filters and tests. Tests
check for volatile, async, and ``@pass_context`` etc.
@@ -812,25 +812,25 @@ class Test(_FilterTestCommon):
_is_filter = False
-class Call(Expr):
- """Calls an expression. `args` is a list of arguments, `kwargs` a list
- of keyword arguments (list of :class:`Keyword` nodes), and `dyn_args`
- and `dyn_kwargs` has to be either `None` or a node that is used as
- node for dynamic positional (``*args``) or keyword (``**kwargs``)
- arguments.
- """
-
+class Call(Expr):
+ """Calls an expression. `args` is a list of arguments, `kwargs` a list
+ of keyword arguments (list of :class:`Keyword` nodes), and `dyn_args`
+ and `dyn_kwargs` has to be either `None` or a node that is used as
+ node for dynamic positional (``*args``) or keyword (``**kwargs``)
+ arguments.
+ """
+
fields = ("node", "args", "kwargs", "dyn_args", "dyn_kwargs")
node: Expr
args: t.List[Expr]
kwargs: t.List[Keyword]
dyn_args: t.Optional[Expr]
dyn_kwargs: t.Optional[Expr]
+
-
-class Getitem(Expr):
- """Get an attribute or item from an expression and prefer the item."""
-
+class Getitem(Expr):
+ """Get an attribute or item from an expression and prefer the item."""
+
fields = ("node", "arg", "ctx")
node: Expr
arg: Expr
@@ -838,23 +838,23 @@ class Getitem(Expr):
def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:
if self.ctx != "load":
- raise Impossible()
+ raise Impossible()
eval_ctx = get_eval_context(self, eval_ctx)
- try:
+ try:
return eval_ctx.environment.getitem(
self.node.as_const(eval_ctx), self.arg.as_const(eval_ctx)
)
except Exception as e:
raise Impossible() from e
-
-
-class Getattr(Expr):
- """Get an attribute or item from an expression that is a ascii-only
- bytestring and prefer the attribute.
- """
-
+
+
+class Getattr(Expr):
+ """Get an attribute or item from an expression that is a ascii-only
+ bytestring and prefer the attribute.
+ """
+
fields = ("node", "attr", "ctx")
node: Expr
attr: str
@@ -862,212 +862,212 @@ class Getattr(Expr):
def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:
if self.ctx != "load":
- raise Impossible()
+ raise Impossible()
eval_ctx = get_eval_context(self, eval_ctx)
- try:
+ try:
return eval_ctx.environment.getattr(self.node.as_const(eval_ctx), self.attr)
except Exception as e:
raise Impossible() from e
-
-
-class Slice(Expr):
- """Represents a slice object. This must only be used as argument for
- :class:`Subscript`.
- """
-
+
+
+class Slice(Expr):
+ """Represents a slice object. This must only be used as argument for
+ :class:`Subscript`.
+ """
+
fields = ("start", "stop", "step")
start: t.Optional[Expr]
stop: t.Optional[Expr]
step: t.Optional[Expr]
def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> slice:
- eval_ctx = get_eval_context(self, eval_ctx)
+ eval_ctx = get_eval_context(self, eval_ctx)
def const(obj: t.Optional[Expr]) -> t.Optional[t.Any]:
- if obj is None:
- return None
- return obj.as_const(eval_ctx)
-
- return slice(const(self.start), const(self.stop), const(self.step))
-
-
-class Concat(Expr):
+ if obj is None:
+ return None
+ return obj.as_const(eval_ctx)
+
+ return slice(const(self.start), const(self.stop), const(self.step))
+
+
+class Concat(Expr):
"""Concatenates the list of expressions provided after converting
them to strings.
- """
-
+ """
+
fields = ("nodes",)
nodes: t.List[Expr]
def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> str:
- eval_ctx = get_eval_context(self, eval_ctx)
+ eval_ctx = get_eval_context(self, eval_ctx)
return "".join(str(x.as_const(eval_ctx)) for x in self.nodes)
-
-
-class Compare(Expr):
- """Compares an expression with some other expressions. `ops` must be a
- list of :class:`Operand`\\s.
- """
-
+
+
+class Compare(Expr):
+ """Compares an expression with some other expressions. `ops` must be a
+ list of :class:`Operand`\\s.
+ """
+
fields = ("expr", "ops")
expr: Expr
ops: t.List["Operand"]
def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:
- eval_ctx = get_eval_context(self, eval_ctx)
- result = value = self.expr.as_const(eval_ctx)
+ eval_ctx = get_eval_context(self, eval_ctx)
+ result = value = self.expr.as_const(eval_ctx)
- try:
- for op in self.ops:
- new_value = op.expr.as_const(eval_ctx)
- result = _cmpop_to_func[op.op](value, new_value)
+ try:
+ for op in self.ops:
+ new_value = op.expr.as_const(eval_ctx)
+ result = _cmpop_to_func[op.op](value, new_value)
if not result:
return False
- value = new_value
+ value = new_value
except Exception as e:
raise Impossible() from e
- return result
-
-
-class Operand(Helper):
- """Holds an operator and an expression."""
-
+ return result
+
+
+class Operand(Helper):
+ """Holds an operator and an expression."""
+
fields = ("op", "expr")
op: str
expr: Expr
-class Mul(BinExpr):
- """Multiplies the left with the right node."""
-
+class Mul(BinExpr):
+ """Multiplies the left with the right node."""
+
operator = "*"
+
-
-class Div(BinExpr):
- """Divides the left by the right node."""
-
+class Div(BinExpr):
+ """Divides the left by the right node."""
+
operator = "/"
+
-
-class FloorDiv(BinExpr):
+class FloorDiv(BinExpr):
"""Divides the left by the right node and converts the
- result into an integer by truncating.
- """
-
+ result into an integer by truncating.
+ """
+
operator = "//"
+
-
-class Add(BinExpr):
- """Add the left to the right node."""
-
+class Add(BinExpr):
+ """Add the left to the right node."""
+
operator = "+"
+
-
-class Sub(BinExpr):
- """Subtract the right from the left node."""
-
+class Sub(BinExpr):
+ """Subtract the right from the left node."""
+
operator = "-"
+
-
-class Mod(BinExpr):
- """Left modulo right."""
-
+class Mod(BinExpr):
+ """Left modulo right."""
+
operator = "%"
+
-
-class Pow(BinExpr):
- """Left to the power of right."""
-
+class Pow(BinExpr):
+ """Left to the power of right."""
+
operator = "**"
+
-
-class And(BinExpr):
- """Short circuited AND."""
-
+class And(BinExpr):
+ """Short circuited AND."""
+
operator = "and"
def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:
- eval_ctx = get_eval_context(self, eval_ctx)
- return self.left.as_const(eval_ctx) and self.right.as_const(eval_ctx)
-
-
-class Or(BinExpr):
- """Short circuited OR."""
-
+ eval_ctx = get_eval_context(self, eval_ctx)
+ return self.left.as_const(eval_ctx) and self.right.as_const(eval_ctx)
+
+
+class Or(BinExpr):
+ """Short circuited OR."""
+
operator = "or"
def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> t.Any:
- eval_ctx = get_eval_context(self, eval_ctx)
- return self.left.as_const(eval_ctx) or self.right.as_const(eval_ctx)
-
-
-class Not(UnaryExpr):
- """Negate the expression."""
-
+ eval_ctx = get_eval_context(self, eval_ctx)
+ return self.left.as_const(eval_ctx) or self.right.as_const(eval_ctx)
+
+
+class Not(UnaryExpr):
+ """Negate the expression."""
+
operator = "not"
+
-
-class Neg(UnaryExpr):
- """Make the expression negative."""
-
+class Neg(UnaryExpr):
+ """Make the expression negative."""
+
operator = "-"
+
-
-class Pos(UnaryExpr):
- """Make the expression positive (noop for most expressions)"""
-
+class Pos(UnaryExpr):
+ """Make the expression positive (noop for most expressions)"""
+
operator = "+"
-
-
-# Helpers for extensions
-
-
-class EnvironmentAttribute(Expr):
- """Loads an attribute from the environment object. This is useful for
- extensions that want to call a callback stored on the environment.
- """
-
+
+
+# Helpers for extensions
+
+
+class EnvironmentAttribute(Expr):
+ """Loads an attribute from the environment object. This is useful for
+ extensions that want to call a callback stored on the environment.
+ """
+
fields = ("name",)
name: str
-
-
-class ExtensionAttribute(Expr):
- """Returns the attribute of an extension bound to the environment.
- The identifier is the identifier of the :class:`Extension`.
-
- This node is usually constructed by calling the
- :meth:`~jinja2.ext.Extension.attr` method on an extension.
- """
-
+
+
+class ExtensionAttribute(Expr):
+ """Returns the attribute of an extension bound to the environment.
+ The identifier is the identifier of the :class:`Extension`.
+
+ This node is usually constructed by calling the
+ :meth:`~jinja2.ext.Extension.attr` method on an extension.
+ """
+
fields = ("identifier", "name")
identifier: str
name: str
-
-
-class ImportedName(Expr):
- """If created with an import name the import name is returned on node
- access. For example ``ImportedName('cgi.escape')`` returns the `escape`
- function from the cgi module on evaluation. Imports are optimized by the
- compiler so there is no need to assign them to local variables.
- """
-
+
+
+class ImportedName(Expr):
+ """If created with an import name the import name is returned on node
+ access. For example ``ImportedName('cgi.escape')`` returns the `escape`
+ function from the cgi module on evaluation. Imports are optimized by the
+ compiler so there is no need to assign them to local variables.
+ """
+
fields = ("importname",)
importname: str
+
-
-class InternalName(Expr):
- """An internal name in the compiler. You cannot create these nodes
- yourself but the parser provides a
- :meth:`~jinja2.parser.Parser.free_identifier` method that creates
- a new identifier for you. This identifier is not available from the
+class InternalName(Expr):
+ """An internal name in the compiler. You cannot create these nodes
+ yourself but the parser provides a
+ :meth:`~jinja2.parser.Parser.free_identifier` method that creates
+ a new identifier for you. This identifier is not available from the
template and is not treated specially by the compiler.
- """
-
+ """
+
fields = ("name",)
name: str
@@ -1076,59 +1076,59 @@ class InternalName(Expr):
"Can't create internal names. Use the "
"`free_identifier` method on a parser."
)
-
-
-class MarkSafe(Expr):
- """Mark the wrapped expression as safe (wrap it as `Markup`)."""
-
+
+
+class MarkSafe(Expr):
+ """Mark the wrapped expression as safe (wrap it as `Markup`)."""
+
fields = ("expr",)
expr: Expr
def as_const(self, eval_ctx: t.Optional[EvalContext] = None) -> Markup:
- eval_ctx = get_eval_context(self, eval_ctx)
- return Markup(self.expr.as_const(eval_ctx))
-
-
-class MarkSafeIfAutoescape(Expr):
- """Mark the wrapped expression as safe (wrap it as `Markup`) but
- only if autoescaping is active.
-
- .. versionadded:: 2.5
- """
-
+ eval_ctx = get_eval_context(self, eval_ctx)
+ return Markup(self.expr.as_const(eval_ctx))
+
+
+class MarkSafeIfAutoescape(Expr):
+ """Mark the wrapped expression as safe (wrap it as `Markup`) but
+ only if autoescaping is active.
+
+ .. versionadded:: 2.5
+ """
+
fields = ("expr",)
expr: Expr
def as_const(
self, eval_ctx: t.Optional[EvalContext] = None
) -> t.Union[Markup, t.Any]:
- eval_ctx = get_eval_context(self, eval_ctx)
- if eval_ctx.volatile:
- raise Impossible()
- expr = self.expr.as_const(eval_ctx)
- if eval_ctx.autoescape:
- return Markup(expr)
- return expr
-
-
-class ContextReference(Expr):
- """Returns the current template context. It can be used like a
- :class:`Name` node, with a ``'load'`` ctx and will return the
- current :class:`~jinja2.runtime.Context` object.
-
- Here an example that assigns the current template name to a
- variable named `foo`::
-
- Assign(Name('foo', ctx='store'),
- Getattr(ContextReference(), 'name'))
+ eval_ctx = get_eval_context(self, eval_ctx)
+ if eval_ctx.volatile:
+ raise Impossible()
+ expr = self.expr.as_const(eval_ctx)
+ if eval_ctx.autoescape:
+ return Markup(expr)
+ return expr
+
+
+class ContextReference(Expr):
+ """Returns the current template context. It can be used like a
+ :class:`Name` node, with a ``'load'`` ctx and will return the
+ current :class:`~jinja2.runtime.Context` object.
+
+ Here an example that assigns the current template name to a
+ variable named `foo`::
+
+ Assign(Name('foo', ctx='store'),
+ Getattr(ContextReference(), 'name'))
This is basically equivalent to using the
:func:`~jinja2.pass_context` decorator when using the high-level
API, which causes a reference to the context to be passed as the
first argument to a function.
- """
-
-
+ """
+
+
class DerivedContextReference(Expr):
"""Return the current template context including locals. Behaves
exactly like :class:`ContextReference`, but includes local
@@ -1138,64 +1138,64 @@ class DerivedContextReference(Expr):
"""
-class Continue(Stmt):
- """Continue a loop."""
-
-
-class Break(Stmt):
- """Break a loop."""
-
-
-class Scope(Stmt):
- """An artificial scope."""
-
+class Continue(Stmt):
+ """Continue a loop."""
+
+
+class Break(Stmt):
+ """Break a loop."""
+
+
+class Scope(Stmt):
+ """An artificial scope."""
+
fields = ("body",)
body: t.List[Node]
-
-
-class OverlayScope(Stmt):
- """An overlay scope for extensions. This is a largely unoptimized scope
- that however can be used to introduce completely arbitrary variables into
- a sub scope from a dictionary or dictionary like object. The `context`
- field has to evaluate to a dictionary object.
-
- Example usage::
-
- OverlayScope(context=self.call_method('get_context'),
- body=[...])
-
- .. versionadded:: 2.10
- """
-
+
+
+class OverlayScope(Stmt):
+ """An overlay scope for extensions. This is a largely unoptimized scope
+ that however can be used to introduce completely arbitrary variables into
+ a sub scope from a dictionary or dictionary like object. The `context`
+ field has to evaluate to a dictionary object.
+
+ Example usage::
+
+ OverlayScope(context=self.call_method('get_context'),
+ body=[...])
+
+ .. versionadded:: 2.10
+ """
+
fields = ("context", "body")
context: Expr
body: t.List[Node]
-
-
-class EvalContextModifier(Stmt):
- """Modifies the eval context. For each option that should be modified,
- a :class:`Keyword` has to be added to the :attr:`options` list.
-
- Example to change the `autoescape` setting::
-
- EvalContextModifier(options=[Keyword('autoescape', Const(True))])
- """
-
+
+
+class EvalContextModifier(Stmt):
+ """Modifies the eval context. For each option that should be modified,
+ a :class:`Keyword` has to be added to the :attr:`options` list.
+
+ Example to change the `autoescape` setting::
+
+ EvalContextModifier(options=[Keyword('autoescape', Const(True))])
+ """
+
fields = ("options",)
options: t.List[Keyword]
-
-
-class ScopedEvalContextModifier(EvalContextModifier):
- """Modifies the eval context and reverts it later. Works exactly like
- :class:`EvalContextModifier` but will only modify the
- :class:`~jinja2.nodes.EvalContext` for nodes in the :attr:`body`.
- """
-
+
+
+class ScopedEvalContextModifier(EvalContextModifier):
+ """Modifies the eval context and reverts it later. Works exactly like
+ :class:`EvalContextModifier` but will only modify the
+ :class:`~jinja2.nodes.EvalContext` for nodes in the :attr:`body`.
+ """
+
fields = ("body",)
body: t.List[Node]
+
-
-# make sure nobody creates custom nodes
+# make sure nobody creates custom nodes
def _failing_new(*args: t.Any, **kwargs: t.Any) -> "te.NoReturn":
raise TypeError("can't create custom node types")
diff --git a/contrib/python/Jinja2/py3/jinja2/optimizer.py b/contrib/python/Jinja2/py3/jinja2/optimizer.py
index fe1010705e..0f38e3154d 100644
--- a/contrib/python/Jinja2/py3/jinja2/optimizer.py
+++ b/contrib/python/Jinja2/py3/jinja2/optimizer.py
@@ -1,37 +1,37 @@
"""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.
-"""
+"""
import typing as t
from . import nodes
from .visitor import NodeTransformer
-
+
if t.TYPE_CHECKING:
from .environment import Environment
-
+
def optimize(node: nodes.Node, environment: "Environment") -> nodes.Node:
- """The context hint can be used to perform an static optimization
- based on the context given."""
- optimizer = Optimizer(environment)
+ """The context hint can be used to perform an static optimization
+ based on the context given."""
+ optimizer = Optimizer(environment)
return t.cast(nodes.Node, optimizer.visit(node))
-
-
-class Optimizer(NodeTransformer):
+
+
+class Optimizer(NodeTransformer):
def __init__(self, environment: "t.Optional[Environment]") -> None:
- self.environment = environment
-
+ self.environment = environment
+
def generic_visit(
self, node: nodes.Node, *args: t.Any, **kwargs: t.Any
) -> nodes.Node:
node = super().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):
diff --git a/contrib/python/Jinja2/py3/jinja2/parser.py b/contrib/python/Jinja2/py3/jinja2/parser.py
index 7ad73fcc0f..0b8f9ca61a 100644
--- a/contrib/python/Jinja2/py3/jinja2/parser.py
+++ b/contrib/python/Jinja2/py3/jinja2/parser.py
@@ -7,7 +7,7 @@ from .exceptions import TemplateAssertionError
from .exceptions import TemplateSyntaxError
from .lexer import describe_token
from .lexer import describe_token_expr
-
+
if t.TYPE_CHECKING:
import typing_extensions as te
from .environment import Environment
@@ -32,7 +32,7 @@ _statement_keywords = frozenset(
]
)
_compare_operators = frozenset(["eq", "ne", "lt", "lteq", "gt", "gteq"])
-
+
_math_nodes: t.Dict[str, t.Type[nodes.Expr]] = {
"add": nodes.Add,
"sub": nodes.Sub,
@@ -40,14 +40,14 @@ _math_nodes: t.Dict[str, t.Type[nodes.Expr]] = {
"div": nodes.Div,
"floordiv": nodes.FloorDiv,
"mod": nodes.Mod,
-}
-
-
+}
+
+
class Parser:
"""This is the central parsing class Jinja uses. It's passed to
- extensions and can be used to parse expressions or statements.
- """
-
+ extensions and can be used to parse expressions or statements.
+ """
+
def __init__(
self,
environment: "Environment",
@@ -56,35 +56,35 @@ class Parser:
filename: t.Optional[str] = None,
state: t.Optional[str] = None,
) -> None:
- self.environment = environment
- self.stream = environment._tokenize(source, name, filename, state)
- self.name = name
- self.filename = filename
- self.closed = False
+ self.environment = environment
+ self.stream = environment._tokenize(source, name, filename, state)
+ self.name = name
+ self.filename = filename
+ self.closed = False
self.extensions: t.Dict[
str, t.Callable[["Parser"], t.Union[nodes.Node, t.List[nodes.Node]]]
] = {}
- for extension in environment.iter_extensions():
- for tag in extension.tags:
- self.extensions[tag] = extension.parse
- self._last_identifier = 0
+ for extension in environment.iter_extensions():
+ for tag in extension.tags:
+ self.extensions[tag] = extension.parse
+ self._last_identifier = 0
self._tag_stack: t.List[str] = []
self._end_token_stack: t.List[t.Tuple[str, ...]] = []
-
+
def fail(
self,
msg: str,
lineno: t.Optional[int] = None,
exc: t.Type[TemplateSyntaxError] = TemplateSyntaxError,
) -> "te.NoReturn":
- """Convenience method that raises `exc` with the message, passed
- line number or last line number as well as the current name and
- filename.
- """
- if lineno is None:
- lineno = self.stream.current.lineno
- raise exc(msg, lineno, self.name, self.filename)
-
+ """Convenience method that raises `exc` with the message, passed
+ line number or last line number as well as the current name and
+ filename.
+ """
+ if lineno is None:
+ lineno = self.stream.current.lineno
+ raise exc(msg, lineno, self.name, self.filename)
+
def _fail_ut_eof(
self,
name: t.Optional[str],
@@ -92,220 +92,220 @@ class Parser:
lineno: t.Optional[int],
) -> "te.NoReturn":
expected: t.Set[str] = set()
- for exprs in end_token_stack:
+ for exprs in end_token_stack:
expected.update(map(describe_token_expr, exprs))
- if end_token_stack:
+ if end_token_stack:
currently_looking: t.Optional[str] = " or ".join(
map(repr, map(describe_token_expr, end_token_stack[-1]))
)
- else:
- currently_looking = None
-
- if name is None:
+ else:
+ currently_looking = None
+
+ if name is None:
message = ["Unexpected end of template."]
- else:
+ else:
message = [f"Encountered unknown tag {name!r}."]
-
- if currently_looking:
- if name is not None and name in expected:
+
+ if currently_looking:
+ if name is not None and name in expected:
message.append(
"You probably made a nesting mistake. Jinja is expecting this tag,"
f" but currently looking for {currently_looking}."
)
- else:
+ else:
message.append(
f"Jinja was looking for the following tags: {currently_looking}."
)
-
- if self._tag_stack:
+
+ if self._tag_stack:
message.append(
"The innermost block that needs to be closed is"
f" {self._tag_stack[-1]!r}."
)
-
+
self.fail(" ".join(message), lineno)
-
+
def fail_unknown_tag(
self, name: str, lineno: t.Optional[int] = None
) -> "te.NoReturn":
- """Called if the parser encounters an unknown tag. Tries to fail
- with a human readable error message that could help to identify
- the problem.
- """
+ """Called if the parser encounters an unknown tag. Tries to fail
+ with a human readable error message that could help to identify
+ the problem.
+ """
self._fail_ut_eof(name, self._end_token_stack, lineno)
-
+
def fail_eof(
self,
end_tokens: t.Optional[t.Tuple[str, ...]] = None,
lineno: t.Optional[int] = None,
) -> "te.NoReturn":
- """Like fail_unknown_tag but for end of template situations."""
- stack = list(self._end_token_stack)
- if end_tokens is not None:
- stack.append(end_tokens)
+ """Like fail_unknown_tag but for end of template situations."""
+ stack = list(self._end_token_stack)
+ if end_tokens is not None:
+ stack.append(end_tokens)
self._fail_ut_eof(None, stack, lineno)
-
+
def is_tuple_end(
self, extra_end_rules: t.Optional[t.Tuple[str, ...]] = None
) -> bool:
- """Are we at the end of a tuple?"""
+ """Are we at the end of a tuple?"""
if self.stream.current.type in ("variable_end", "block_end", "rparen"):
- return True
- elif extra_end_rules is not None:
+ return True
+ elif extra_end_rules is not None:
return self.stream.current.test_any(extra_end_rules) # type: ignore
- return False
-
+ return False
+
def free_identifier(self, lineno: t.Optional[int] = None) -> nodes.InternalName:
- """Return a new free identifier as :class:`~jinja2.nodes.InternalName`."""
- self._last_identifier += 1
- rv = object.__new__(nodes.InternalName)
+ """Return a new free identifier as :class:`~jinja2.nodes.InternalName`."""
+ self._last_identifier += 1
+ rv = object.__new__(nodes.InternalName)
nodes.Node.__init__(rv, f"fi{self._last_identifier}", lineno=lineno)
return rv # type: ignore
-
+
def parse_statement(self) -> t.Union[nodes.Node, t.List[nodes.Node]]:
- """Parse a single statement."""
- token = self.stream.current
+ """Parse a single statement."""
+ token = self.stream.current
if token.type != "name":
self.fail("tag name expected", token.lineno)
- self._tag_stack.append(token.value)
- pop_tag = True
- try:
- if token.value in _statement_keywords:
+ self._tag_stack.append(token.value)
+ pop_tag = True
+ try:
+ if token.value in _statement_keywords:
f = getattr(self, f"parse_{self.stream.current.value}")
return f() # type: ignore
if token.value == "call":
- return self.parse_call_block()
+ return self.parse_call_block()
if token.value == "filter":
- return self.parse_filter_block()
- ext = self.extensions.get(token.value)
- if ext is not None:
- return ext(self)
-
- # did not work out, remove the token we pushed by accident
- # from the stack so that the unknown tag fail function can
- # produce a proper error message.
- self._tag_stack.pop()
- pop_tag = False
- self.fail_unknown_tag(token.value, token.lineno)
- finally:
- if pop_tag:
- self._tag_stack.pop()
-
+ return self.parse_filter_block()
+ ext = self.extensions.get(token.value)
+ if ext is not None:
+ return ext(self)
+
+ # did not work out, remove the token we pushed by accident
+ # from the stack so that the unknown tag fail function can
+ # produce a proper error message.
+ self._tag_stack.pop()
+ pop_tag = False
+ self.fail_unknown_tag(token.value, token.lineno)
+ finally:
+ if pop_tag:
+ self._tag_stack.pop()
+
def parse_statements(
self, end_tokens: t.Tuple[str, ...], drop_needle: bool = False
) -> t.List[nodes.Node]:
- """Parse multiple statements into a list until one of the end tokens
- is reached. This is used to parse the body of statements as it also
- parses template data if appropriate. The parser checks first if the
- current token is a colon and skips it if there is one. Then it checks
- for the block end and parses until if one of the `end_tokens` is
- reached. Per default the active token in the stream at the end of
- the call is the matched end token. If this is not wanted `drop_needle`
- can be set to `True` and the end token is removed.
- """
- # the first token may be a colon for python compatibility
+ """Parse multiple statements into a list until one of the end tokens
+ is reached. This is used to parse the body of statements as it also
+ parses template data if appropriate. The parser checks first if the
+ current token is a colon and skips it if there is one. Then it checks
+ for the block end and parses until if one of the `end_tokens` is
+ reached. Per default the active token in the stream at the end of
+ the call is the matched end token. If this is not wanted `drop_needle`
+ can be set to `True` and the end token is removed.
+ """
+ # the first token may be a colon for python compatibility
self.stream.skip_if("colon")
-
- # in the future it would be possible to add whole code sections
- # by adding some sort of end of statement token and parsing those here.
+
+ # in the future it would be possible to add whole code sections
+ # by adding some sort of end of statement token and parsing those here.
self.stream.expect("block_end")
- result = self.subparse(end_tokens)
-
- # we reached the end of the template too early, the subparser
- # does not check for this, so we do that now
+ result = self.subparse(end_tokens)
+
+ # we reached the end of the template too early, the subparser
+ # does not check for this, so we do that now
if self.stream.current.type == "eof":
- self.fail_eof(end_tokens)
-
- if drop_needle:
- next(self.stream)
- return result
-
+ self.fail_eof(end_tokens)
+
+ if drop_needle:
+ next(self.stream)
+ return result
+
def parse_set(self) -> t.Union[nodes.Assign, nodes.AssignBlock]:
- """Parse an assign statement."""
- lineno = next(self.stream).lineno
- target = self.parse_assign_target(with_namespace=True)
+ """Parse an assign statement."""
+ lineno = next(self.stream).lineno
+ target = self.parse_assign_target(with_namespace=True)
if self.stream.skip_if("assign"):
- expr = self.parse_tuple()
- return nodes.Assign(target, expr, lineno=lineno)
- filter_node = self.parse_filter(None)
+ expr = self.parse_tuple()
+ return nodes.Assign(target, expr, lineno=lineno)
+ filter_node = self.parse_filter(None)
body = self.parse_statements(("name:endset",), drop_needle=True)
- return nodes.AssignBlock(target, filter_node, body, lineno=lineno)
-
+ return nodes.AssignBlock(target, filter_node, body, lineno=lineno)
+
def parse_for(self) -> nodes.For:
- """Parse a for loop."""
+ """Parse a for loop."""
lineno = self.stream.expect("name:for").lineno
target = self.parse_assign_target(extra_end_rules=("name:in",))
self.stream.expect("name:in")
iter = self.parse_tuple(
with_condexpr=False, extra_end_rules=("name:recursive",)
)
- test = None
+ test = None
if self.stream.skip_if("name:if"):
- test = self.parse_expression()
+ test = self.parse_expression()
recursive = self.stream.skip_if("name:recursive")
body = self.parse_statements(("name:endfor", "name:else"))
if next(self.stream).value == "endfor":
- else_ = []
- else:
+ else_ = []
+ else:
else_ = self.parse_statements(("name:endfor",), drop_needle=True)
return nodes.For(target, iter, body, else_, test, recursive, lineno=lineno)
-
+
def parse_if(self) -> nodes.If:
- """Parse an if construct."""
+ """Parse an if construct."""
node = result = nodes.If(lineno=self.stream.expect("name:if").lineno)
while True:
- node.test = self.parse_tuple(with_condexpr=False)
+ node.test = self.parse_tuple(with_condexpr=False)
node.body = self.parse_statements(("name:elif", "name:else", "name:endif"))
- node.elif_ = []
- node.else_ = []
- token = next(self.stream)
+ node.elif_ = []
+ node.else_ = []
+ token = next(self.stream)
if token.test("name:elif"):
- node = nodes.If(lineno=self.stream.current.lineno)
- result.elif_.append(node)
- continue
+ node = nodes.If(lineno=self.stream.current.lineno)
+ result.elif_.append(node)
+ continue
elif token.test("name:else"):
result.else_ = self.parse_statements(("name:endif",), drop_needle=True)
- break
- return result
-
+ break
+ return result
+
def parse_with(self) -> nodes.With:
- node = nodes.With(lineno=next(self.stream).lineno)
+ node = nodes.With(lineno=next(self.stream).lineno)
targets: t.List[nodes.Expr] = []
values: t.List[nodes.Expr] = []
while self.stream.current.type != "block_end":
- if targets:
+ if targets:
self.stream.expect("comma")
- target = self.parse_assign_target()
+ target = self.parse_assign_target()
target.set_ctx("param")
- targets.append(target)
+ targets.append(target)
self.stream.expect("assign")
- values.append(self.parse_expression())
- node.targets = targets
- node.values = values
+ values.append(self.parse_expression())
+ node.targets = targets
+ node.values = values
node.body = self.parse_statements(("name:endwith",), drop_needle=True)
- return node
-
+ return node
+
def parse_autoescape(self) -> nodes.Scope:
- node = nodes.ScopedEvalContextModifier(lineno=next(self.stream).lineno)
+ node = nodes.ScopedEvalContextModifier(lineno=next(self.stream).lineno)
node.options = [nodes.Keyword("autoescape", self.parse_expression())]
node.body = self.parse_statements(("name:endautoescape",), drop_needle=True)
- return nodes.Scope([node])
-
+ return nodes.Scope([node])
+
def parse_block(self) -> nodes.Block:
- node = nodes.Block(lineno=next(self.stream).lineno)
+ node = nodes.Block(lineno=next(self.stream).lineno)
node.name = self.stream.expect("name").value
node.scoped = self.stream.skip_if("name:scoped")
node.required = self.stream.skip_if("name:required")
-
- # common problem people encounter when switching from django
- # to jinja. we do not support hyphens in block names, so let's
- # raise a nicer error message in that case.
+
+ # common problem people encounter when switching from django
+ # to jinja. we do not support hyphens in block names, so let's
+ # raise a nicer error message in that case.
if self.stream.current.type == "sub":
self.fail(
"Block names in Jinja have to be valid Python identifiers and may not"
" contain hyphens, use an underscore instead."
)
-
+
node.body = self.parse_statements(("name:endblock",), drop_needle=True)
# enforce that required blocks only contain whitespace or comments
@@ -319,13 +319,13 @@ class Parser:
self.fail("Required blocks can only contain comments or whitespace")
self.stream.skip_if("name:" + node.name)
- return node
-
+ return node
+
def parse_extends(self) -> nodes.Extends:
- node = nodes.Extends(lineno=next(self.stream).lineno)
- node.template = self.parse_expression()
- return node
-
+ node = nodes.Extends(lineno=next(self.stream).lineno)
+ node.template = self.parse_expression()
+ return node
+
def parse_import_context(
self, node: _ImportInclude, default: bool
) -> _ImportInclude:
@@ -333,36 +333,36 @@ class Parser:
"name:with", "name:without"
) and self.stream.look().test("name:context"):
node.with_context = next(self.stream).value == "with"
- self.stream.skip()
- else:
- node.with_context = default
- return node
-
+ self.stream.skip()
+ else:
+ node.with_context = default
+ return node
+
def parse_include(self) -> nodes.Include:
- node = nodes.Include(lineno=next(self.stream).lineno)
- node.template = self.parse_expression()
+ node = nodes.Include(lineno=next(self.stream).lineno)
+ node.template = self.parse_expression()
if self.stream.current.test("name:ignore") and self.stream.look().test(
"name:missing"
):
- node.ignore_missing = True
- self.stream.skip(2)
- else:
- node.ignore_missing = False
- return self.parse_import_context(node, True)
-
+ node.ignore_missing = True
+ self.stream.skip(2)
+ else:
+ node.ignore_missing = False
+ return self.parse_import_context(node, True)
+
def parse_import(self) -> nodes.Import:
- node = nodes.Import(lineno=next(self.stream).lineno)
- node.template = self.parse_expression()
+ node = nodes.Import(lineno=next(self.stream).lineno)
+ node.template = self.parse_expression()
self.stream.expect("name:as")
- node.target = self.parse_assign_target(name_only=True).name
- return self.parse_import_context(node, False)
-
+ node.target = self.parse_assign_target(name_only=True).name
+ return self.parse_import_context(node, False)
+
def parse_from(self) -> nodes.FromImport:
- node = nodes.FromImport(lineno=next(self.stream).lineno)
- node.template = self.parse_expression()
+ node = nodes.FromImport(lineno=next(self.stream).lineno)
+ node.template = self.parse_expression()
self.stream.expect("name:import")
- node.names = []
-
+ node.names = []
+
def parse_context() -> bool:
if (
self.stream.current.value
@@ -373,17 +373,17 @@ class Parser:
and self.stream.look().test("name:context")
):
node.with_context = next(self.stream).value == "with"
- self.stream.skip()
- return True
- return False
-
+ self.stream.skip()
+ return True
+ return False
+
while True:
- if node.names:
+ if node.names:
self.stream.expect("comma")
if self.stream.current.type == "name":
- if parse_context():
- break
- target = self.parse_assign_target(name_only=True)
+ if parse_context():
+ break
+ target = self.parse_assign_target(name_only=True)
if target.name.startswith("_"):
self.fail(
"names starting with an underline can not be imported",
@@ -391,71 +391,71 @@ class Parser:
exc=TemplateAssertionError,
)
if self.stream.skip_if("name:as"):
- alias = self.parse_assign_target(name_only=True)
- node.names.append((target.name, alias.name))
- else:
- node.names.append(target.name)
+ alias = self.parse_assign_target(name_only=True)
+ node.names.append((target.name, alias.name))
+ else:
+ node.names.append(target.name)
if parse_context() or self.stream.current.type != "comma":
- break
- else:
+ break
+ else:
self.stream.expect("name")
if not hasattr(node, "with_context"):
- node.with_context = False
- return node
-
+ node.with_context = False
+ return node
+
def parse_signature(self, node: _MacroCall) -> None:
args = node.args = []
defaults = node.defaults = []
self.stream.expect("lparen")
while self.stream.current.type != "rparen":
- if args:
+ if args:
self.stream.expect("comma")
- arg = self.parse_assign_target(name_only=True)
+ arg = self.parse_assign_target(name_only=True)
arg.set_ctx("param")
if self.stream.skip_if("assign"):
- defaults.append(self.parse_expression())
- elif defaults:
+ defaults.append(self.parse_expression())
+ elif defaults:
self.fail("non-default argument follows default argument")
- args.append(arg)
+ args.append(arg)
self.stream.expect("rparen")
-
+
def parse_call_block(self) -> nodes.CallBlock:
- node = nodes.CallBlock(lineno=next(self.stream).lineno)
+ node = nodes.CallBlock(lineno=next(self.stream).lineno)
if self.stream.current.type == "lparen":
- self.parse_signature(node)
- else:
- node.args = []
- node.defaults = []
-
+ self.parse_signature(node)
+ else:
+ node.args = []
+ node.defaults = []
+
call_node = self.parse_expression()
if not isinstance(call_node, nodes.Call):
self.fail("expected call", node.lineno)
node.call = call_node
node.body = self.parse_statements(("name:endcall",), drop_needle=True)
- return node
-
+ return node
+
def parse_filter_block(self) -> nodes.FilterBlock:
- node = nodes.FilterBlock(lineno=next(self.stream).lineno)
+ node = nodes.FilterBlock(lineno=next(self.stream).lineno)
node.filter = self.parse_filter(None, start_inline=True) # type: ignore
node.body = self.parse_statements(("name:endfilter",), drop_needle=True)
- return node
-
+ return node
+
def parse_macro(self) -> nodes.Macro:
- node = nodes.Macro(lineno=next(self.stream).lineno)
- node.name = self.parse_assign_target(name_only=True).name
- self.parse_signature(node)
+ node = nodes.Macro(lineno=next(self.stream).lineno)
+ node.name = self.parse_assign_target(name_only=True).name
+ self.parse_signature(node)
node.body = self.parse_statements(("name:endmacro",), drop_needle=True)
- return node
-
+ return node
+
def parse_print(self) -> nodes.Output:
- node = nodes.Output(lineno=next(self.stream).lineno)
- node.nodes = []
+ node = nodes.Output(lineno=next(self.stream).lineno)
+ node.nodes = []
while self.stream.current.type != "block_end":
- if node.nodes:
+ if node.nodes:
self.stream.expect("comma")
- node.nodes.append(self.parse_expression())
- return node
-
+ node.nodes.append(self.parse_expression())
+ return node
+
@typing.overload
def parse_assign_target(
self, with_tuple: bool = ..., name_only: "te.Literal[True]" = ...
@@ -480,205 +480,205 @@ class Parser:
with_namespace: bool = False,
) -> t.Union[nodes.NSRef, nodes.Name, nodes.Tuple]:
"""Parse an assignment target. As Jinja allows assignments to
- tuples, this function can parse all allowed assignment targets. Per
- default assignments to tuples are parsed, that can be disable however
- by setting `with_tuple` to `False`. If only assignments to names are
- wanted `name_only` can be set to `True`. The `extra_end_rules`
- parameter is forwarded to the tuple parsing function. If
- `with_namespace` is enabled, a namespace assignment may be parsed.
- """
+ tuples, this function can parse all allowed assignment targets. Per
+ default assignments to tuples are parsed, that can be disable however
+ by setting `with_tuple` to `False`. If only assignments to names are
+ wanted `name_only` can be set to `True`. The `extra_end_rules`
+ parameter is forwarded to the tuple parsing function. If
+ `with_namespace` is enabled, a namespace assignment may be parsed.
+ """
target: nodes.Expr
if with_namespace and self.stream.look().type == "dot":
token = self.stream.expect("name")
- next(self.stream) # dot
+ next(self.stream) # dot
attr = self.stream.expect("name")
- target = nodes.NSRef(token.value, attr.value, lineno=token.lineno)
- elif name_only:
+ target = nodes.NSRef(token.value, attr.value, lineno=token.lineno)
+ elif name_only:
token = self.stream.expect("name")
target = nodes.Name(token.value, "store", lineno=token.lineno)
- else:
- if with_tuple:
+ else:
+ if with_tuple:
target = self.parse_tuple(
simplified=True, extra_end_rules=extra_end_rules
)
- else:
- target = self.parse_primary()
+ else:
+ target = self.parse_primary()
target.set_ctx("store")
- if not target.can_assign():
+ if not target.can_assign():
self.fail(
f"can't assign to {type(target).__name__.lower()!r}", target.lineno
)
-
+
return target # type: ignore
def parse_expression(self, with_condexpr: bool = True) -> nodes.Expr:
- """Parse an expression. Per default all expressions are parsed, if
- the optional `with_condexpr` parameter is set to `False` conditional
- expressions are not parsed.
- """
- if with_condexpr:
- return self.parse_condexpr()
- return self.parse_or()
-
+ """Parse an expression. Per default all expressions are parsed, if
+ the optional `with_condexpr` parameter is set to `False` conditional
+ expressions are not parsed.
+ """
+ if with_condexpr:
+ return self.parse_condexpr()
+ return self.parse_or()
+
def parse_condexpr(self) -> nodes.Expr:
- lineno = self.stream.current.lineno
- expr1 = self.parse_or()
+ lineno = self.stream.current.lineno
+ expr1 = self.parse_or()
expr3: t.Optional[nodes.Expr]
while self.stream.skip_if("name:if"):
- expr2 = self.parse_or()
+ expr2 = self.parse_or()
if self.stream.skip_if("name:else"):
- expr3 = self.parse_condexpr()
- else:
- expr3 = None
- expr1 = nodes.CondExpr(expr2, expr1, expr3, lineno=lineno)
- lineno = self.stream.current.lineno
- return expr1
-
+ expr3 = self.parse_condexpr()
+ else:
+ expr3 = None
+ expr1 = nodes.CondExpr(expr2, expr1, expr3, lineno=lineno)
+ lineno = self.stream.current.lineno
+ return expr1
+
def parse_or(self) -> nodes.Expr:
- lineno = self.stream.current.lineno
- left = self.parse_and()
+ lineno = self.stream.current.lineno
+ left = self.parse_and()
while self.stream.skip_if("name:or"):
- right = self.parse_and()
- left = nodes.Or(left, right, lineno=lineno)
- lineno = self.stream.current.lineno
- return left
-
+ right = self.parse_and()
+ left = nodes.Or(left, right, lineno=lineno)
+ lineno = self.stream.current.lineno
+ return left
+
def parse_and(self) -> nodes.Expr:
- lineno = self.stream.current.lineno
- left = self.parse_not()
+ lineno = self.stream.current.lineno
+ left = self.parse_not()
while self.stream.skip_if("name:and"):
- right = self.parse_not()
- left = nodes.And(left, right, lineno=lineno)
- lineno = self.stream.current.lineno
- return left
-
+ right = self.parse_not()
+ left = nodes.And(left, right, lineno=lineno)
+ lineno = self.stream.current.lineno
+ return left
+
def parse_not(self) -> nodes.Expr:
if self.stream.current.test("name:not"):
- lineno = next(self.stream).lineno
- return nodes.Not(self.parse_not(), lineno=lineno)
- return self.parse_compare()
-
+ lineno = next(self.stream).lineno
+ return nodes.Not(self.parse_not(), lineno=lineno)
+ return self.parse_compare()
+
def parse_compare(self) -> nodes.Expr:
- lineno = self.stream.current.lineno
- expr = self.parse_math1()
- ops = []
+ lineno = self.stream.current.lineno
+ expr = self.parse_math1()
+ ops = []
while True:
- token_type = self.stream.current.type
- if token_type in _compare_operators:
- next(self.stream)
- ops.append(nodes.Operand(token_type, self.parse_math1()))
+ token_type = self.stream.current.type
+ if token_type in _compare_operators:
+ next(self.stream)
+ ops.append(nodes.Operand(token_type, self.parse_math1()))
elif self.stream.skip_if("name:in"):
ops.append(nodes.Operand("in", self.parse_math1()))
elif self.stream.current.test("name:not") and self.stream.look().test(
"name:in"
):
- self.stream.skip(2)
+ self.stream.skip(2)
ops.append(nodes.Operand("notin", self.parse_math1()))
- else:
- break
- lineno = self.stream.current.lineno
- if not ops:
- return expr
- return nodes.Compare(expr, ops, lineno=lineno)
-
+ else:
+ break
+ lineno = self.stream.current.lineno
+ if not ops:
+ return expr
+ return nodes.Compare(expr, ops, lineno=lineno)
+
def parse_math1(self) -> nodes.Expr:
- lineno = self.stream.current.lineno
- left = self.parse_concat()
+ lineno = self.stream.current.lineno
+ left = self.parse_concat()
while self.stream.current.type in ("add", "sub"):
- cls = _math_nodes[self.stream.current.type]
- next(self.stream)
- right = self.parse_concat()
- left = cls(left, right, lineno=lineno)
- lineno = self.stream.current.lineno
- return left
-
+ cls = _math_nodes[self.stream.current.type]
+ next(self.stream)
+ right = self.parse_concat()
+ left = cls(left, right, lineno=lineno)
+ lineno = self.stream.current.lineno
+ return left
+
def parse_concat(self) -> nodes.Expr:
- lineno = self.stream.current.lineno
- args = [self.parse_math2()]
+ lineno = self.stream.current.lineno
+ args = [self.parse_math2()]
while self.stream.current.type == "tilde":
- next(self.stream)
- args.append(self.parse_math2())
- if len(args) == 1:
- return args[0]
- return nodes.Concat(args, lineno=lineno)
-
+ next(self.stream)
+ args.append(self.parse_math2())
+ if len(args) == 1:
+ return args[0]
+ return nodes.Concat(args, lineno=lineno)
+
def parse_math2(self) -> nodes.Expr:
- lineno = self.stream.current.lineno
- left = self.parse_pow()
+ lineno = self.stream.current.lineno
+ left = self.parse_pow()
while self.stream.current.type in ("mul", "div", "floordiv", "mod"):
- cls = _math_nodes[self.stream.current.type]
- next(self.stream)
- right = self.parse_pow()
- left = cls(left, right, lineno=lineno)
- lineno = self.stream.current.lineno
- return left
-
+ cls = _math_nodes[self.stream.current.type]
+ next(self.stream)
+ right = self.parse_pow()
+ left = cls(left, right, lineno=lineno)
+ lineno = self.stream.current.lineno
+ return left
+
def parse_pow(self) -> nodes.Expr:
- lineno = self.stream.current.lineno
- left = self.parse_unary()
+ lineno = self.stream.current.lineno
+ left = self.parse_unary()
while self.stream.current.type == "pow":
- next(self.stream)
- right = self.parse_unary()
- left = nodes.Pow(left, right, lineno=lineno)
- lineno = self.stream.current.lineno
- return left
-
+ next(self.stream)
+ right = self.parse_unary()
+ left = nodes.Pow(left, right, lineno=lineno)
+ lineno = self.stream.current.lineno
+ return left
+
def parse_unary(self, with_filter: bool = True) -> nodes.Expr:
- token_type = self.stream.current.type
- lineno = self.stream.current.lineno
+ token_type = self.stream.current.type
+ lineno = self.stream.current.lineno
node: nodes.Expr
if token_type == "sub":
- next(self.stream)
- node = nodes.Neg(self.parse_unary(False), lineno=lineno)
+ next(self.stream)
+ node = nodes.Neg(self.parse_unary(False), lineno=lineno)
elif token_type == "add":
- next(self.stream)
- node = nodes.Pos(self.parse_unary(False), lineno=lineno)
- else:
- node = self.parse_primary()
- node = self.parse_postfix(node)
- if with_filter:
- node = self.parse_filter_expr(node)
- return node
-
+ next(self.stream)
+ node = nodes.Pos(self.parse_unary(False), lineno=lineno)
+ else:
+ node = self.parse_primary()
+ node = self.parse_postfix(node)
+ if with_filter:
+ node = self.parse_filter_expr(node)
+ return node
+
def parse_primary(self) -> nodes.Expr:
- token = self.stream.current
+ token = self.stream.current
node: nodes.Expr
if token.type == "name":
if token.value in ("true", "false", "True", "False"):
node = nodes.Const(token.value in ("true", "True"), lineno=token.lineno)
elif token.value in ("none", "None"):
- node = nodes.Const(None, lineno=token.lineno)
- else:
+ node = nodes.Const(None, lineno=token.lineno)
+ else:
node = nodes.Name(token.value, "load", lineno=token.lineno)
- next(self.stream)
+ next(self.stream)
elif token.type == "string":
- next(self.stream)
- buf = [token.value]
- lineno = token.lineno
+ next(self.stream)
+ buf = [token.value]
+ lineno = token.lineno
while self.stream.current.type == "string":
- buf.append(self.stream.current.value)
- next(self.stream)
+ buf.append(self.stream.current.value)
+ next(self.stream)
node = nodes.Const("".join(buf), lineno=lineno)
elif token.type in ("integer", "float"):
- next(self.stream)
- node = nodes.Const(token.value, lineno=token.lineno)
+ next(self.stream)
+ node = nodes.Const(token.value, lineno=token.lineno)
elif token.type == "lparen":
- next(self.stream)
- node = self.parse_tuple(explicit_parentheses=True)
+ next(self.stream)
+ node = self.parse_tuple(explicit_parentheses=True)
self.stream.expect("rparen")
elif token.type == "lbracket":
- node = self.parse_list()
+ node = self.parse_list()
elif token.type == "lbrace":
- node = self.parse_dict()
- else:
+ node = self.parse_dict()
+ else:
self.fail(f"unexpected {describe_token(token)!r}", token.lineno)
- return node
-
+ return node
+
def parse_tuple(
self,
simplified: bool = False,
@@ -686,275 +686,275 @@ class Parser:
extra_end_rules: t.Optional[t.Tuple[str, ...]] = None,
explicit_parentheses: bool = False,
) -> t.Union[nodes.Tuple, nodes.Expr]:
- """Works like `parse_expression` but if multiple expressions are
- delimited by a comma a :class:`~jinja2.nodes.Tuple` node is created.
- This method could also return a regular expression instead of a tuple
- if no commas where found.
-
- The default parsing mode is a full tuple. If `simplified` is `True`
- only names and literals are parsed. The `no_condexpr` parameter is
- forwarded to :meth:`parse_expression`.
-
- Because tuples do not require delimiters and may end in a bogus comma
- an extra hint is needed that marks the end of a tuple. For example
- for loops support tuples between `for` and `in`. In that case the
- `extra_end_rules` is set to ``['name:in']``.
-
- `explicit_parentheses` is true if the parsing was triggered by an
- expression in parentheses. This is used to figure out if an empty
- tuple is a valid expression or not.
- """
- lineno = self.stream.current.lineno
- if simplified:
- parse = self.parse_primary
- elif with_condexpr:
- parse = self.parse_expression
- else:
+ """Works like `parse_expression` but if multiple expressions are
+ delimited by a comma a :class:`~jinja2.nodes.Tuple` node is created.
+ This method could also return a regular expression instead of a tuple
+ if no commas where found.
+
+ The default parsing mode is a full tuple. If `simplified` is `True`
+ only names and literals are parsed. The `no_condexpr` parameter is
+ forwarded to :meth:`parse_expression`.
+
+ Because tuples do not require delimiters and may end in a bogus comma
+ an extra hint is needed that marks the end of a tuple. For example
+ for loops support tuples between `for` and `in`. In that case the
+ `extra_end_rules` is set to ``['name:in']``.
+
+ `explicit_parentheses` is true if the parsing was triggered by an
+ expression in parentheses. This is used to figure out if an empty
+ tuple is a valid expression or not.
+ """
+ lineno = self.stream.current.lineno
+ if simplified:
+ parse = self.parse_primary
+ elif with_condexpr:
+ parse = self.parse_expression
+ else:
def parse() -> nodes.Expr:
return self.parse_expression(with_condexpr=False)
args: t.List[nodes.Expr] = []
- is_tuple = False
+ is_tuple = False
while True:
- if args:
+ if args:
self.stream.expect("comma")
- if self.is_tuple_end(extra_end_rules):
- break
- args.append(parse())
+ if self.is_tuple_end(extra_end_rules):
+ break
+ args.append(parse())
if self.stream.current.type == "comma":
- is_tuple = True
- else:
- break
- lineno = self.stream.current.lineno
-
- if not is_tuple:
- if args:
- return args[0]
-
- # if we don't have explicit parentheses, an empty tuple is
- # not a valid expression. This would mean nothing (literally
- # nothing) in the spot of an expression would be an empty
- # tuple.
- if not explicit_parentheses:
+ is_tuple = True
+ else:
+ break
+ lineno = self.stream.current.lineno
+
+ if not is_tuple:
+ if args:
+ return args[0]
+
+ # if we don't have explicit parentheses, an empty tuple is
+ # not a valid expression. This would mean nothing (literally
+ # nothing) in the spot of an expression would be an empty
+ # tuple.
+ if not explicit_parentheses:
self.fail(
"Expected an expression,"
f" got {describe_token(self.stream.current)!r}"
)
-
+
return nodes.Tuple(args, "load", lineno=lineno)
-
+
def parse_list(self) -> nodes.List:
token = self.stream.expect("lbracket")
items: t.List[nodes.Expr] = []
while self.stream.current.type != "rbracket":
- if items:
+ if items:
self.stream.expect("comma")
if self.stream.current.type == "rbracket":
- break
- items.append(self.parse_expression())
+ break
+ items.append(self.parse_expression())
self.stream.expect("rbracket")
- return nodes.List(items, lineno=token.lineno)
-
+ return nodes.List(items, lineno=token.lineno)
+
def parse_dict(self) -> nodes.Dict:
token = self.stream.expect("lbrace")
items: t.List[nodes.Pair] = []
while self.stream.current.type != "rbrace":
- if items:
+ if items:
self.stream.expect("comma")
if self.stream.current.type == "rbrace":
- break
- key = self.parse_expression()
+ break
+ key = self.parse_expression()
self.stream.expect("colon")
- value = self.parse_expression()
- items.append(nodes.Pair(key, value, lineno=key.lineno))
+ value = self.parse_expression()
+ items.append(nodes.Pair(key, value, lineno=key.lineno))
self.stream.expect("rbrace")
- return nodes.Dict(items, lineno=token.lineno)
-
+ return nodes.Dict(items, lineno=token.lineno)
+
def parse_postfix(self, node: nodes.Expr) -> nodes.Expr:
while True:
- token_type = self.stream.current.type
+ token_type = self.stream.current.type
if token_type == "dot" or token_type == "lbracket":
- node = self.parse_subscript(node)
- # calls are valid both after postfix expressions (getattr
- # and getitem) as well as filters and tests
+ node = self.parse_subscript(node)
+ # calls are valid both after postfix expressions (getattr
+ # and getitem) as well as filters and tests
elif token_type == "lparen":
- node = self.parse_call(node)
- else:
- break
- return node
-
+ node = self.parse_call(node)
+ else:
+ break
+ return node
+
def parse_filter_expr(self, node: nodes.Expr) -> nodes.Expr:
while True:
- token_type = self.stream.current.type
+ token_type = self.stream.current.type
if token_type == "pipe":
node = self.parse_filter(node) # type: ignore
elif token_type == "name" and self.stream.current.value == "is":
- node = self.parse_test(node)
- # calls are valid both after postfix expressions (getattr
- # and getitem) as well as filters and tests
+ node = self.parse_test(node)
+ # calls are valid both after postfix expressions (getattr
+ # and getitem) as well as filters and tests
elif token_type == "lparen":
- node = self.parse_call(node)
- else:
- break
- return node
-
+ node = self.parse_call(node)
+ else:
+ break
+ return node
+
def parse_subscript(
self, node: nodes.Expr
) -> t.Union[nodes.Getattr, nodes.Getitem]:
- token = next(self.stream)
+ token = next(self.stream)
arg: nodes.Expr
if token.type == "dot":
- attr_token = self.stream.current
- next(self.stream)
+ attr_token = self.stream.current
+ next(self.stream)
if attr_token.type == "name":
return nodes.Getattr(
node, attr_token.value, "load", lineno=token.lineno
)
elif attr_token.type != "integer":
self.fail("expected name or number", attr_token.lineno)
- arg = nodes.Const(attr_token.value, lineno=attr_token.lineno)
+ arg = nodes.Const(attr_token.value, lineno=attr_token.lineno)
return nodes.Getitem(node, arg, "load", lineno=token.lineno)
if token.type == "lbracket":
args: t.List[nodes.Expr] = []
while self.stream.current.type != "rbracket":
- if args:
+ if args:
self.stream.expect("comma")
- args.append(self.parse_subscribed())
+ args.append(self.parse_subscribed())
self.stream.expect("rbracket")
- if len(args) == 1:
- arg = args[0]
- else:
+ if len(args) == 1:
+ arg = args[0]
+ else:
arg = nodes.Tuple(args, "load", lineno=token.lineno)
return nodes.Getitem(node, arg, "load", lineno=token.lineno)
self.fail("expected subscript expression", token.lineno)
-
+
def parse_subscribed(self) -> nodes.Expr:
- lineno = self.stream.current.lineno
+ lineno = self.stream.current.lineno
args: t.List[t.Optional[nodes.Expr]]
-
+
if self.stream.current.type == "colon":
- next(self.stream)
- args = [None]
- else:
- node = self.parse_expression()
+ next(self.stream)
+ args = [None]
+ else:
+ node = self.parse_expression()
if self.stream.current.type != "colon":
- return node
- next(self.stream)
- args = [node]
-
+ return node
+ next(self.stream)
+ args = [node]
+
if self.stream.current.type == "colon":
- args.append(None)
+ args.append(None)
elif self.stream.current.type not in ("rbracket", "comma"):
- args.append(self.parse_expression())
- else:
- args.append(None)
-
+ args.append(self.parse_expression())
+ else:
+ args.append(None)
+
if self.stream.current.type == "colon":
- next(self.stream)
+ next(self.stream)
if self.stream.current.type not in ("rbracket", "comma"):
- args.append(self.parse_expression())
- else:
- args.append(None)
- else:
- args.append(None)
-
- return nodes.Slice(lineno=lineno, *args)
-
+ args.append(self.parse_expression())
+ else:
+ args.append(None)
+ else:
+ args.append(None)
+
+ return nodes.Slice(lineno=lineno, *args)
+
def parse_call_args(self) -> t.Tuple:
token = self.stream.expect("lparen")
- args = []
- kwargs = []
+ args = []
+ kwargs = []
dyn_args = None
dyn_kwargs = None
- require_comma = False
-
+ require_comma = False
+
def ensure(expr: bool) -> None:
- if not expr:
+ if not expr:
self.fail("invalid syntax for function call expression", token.lineno)
-
+
while self.stream.current.type != "rparen":
- if require_comma:
+ if require_comma:
self.stream.expect("comma")
- # support for trailing comma
+ # support for trailing comma
if self.stream.current.type == "rparen":
- break
+ break
if self.stream.current.type == "mul":
- ensure(dyn_args is None and dyn_kwargs is None)
- next(self.stream)
- dyn_args = self.parse_expression()
+ ensure(dyn_args is None and dyn_kwargs is None)
+ next(self.stream)
+ dyn_args = self.parse_expression()
elif self.stream.current.type == "pow":
- ensure(dyn_kwargs is None)
- next(self.stream)
- dyn_kwargs = self.parse_expression()
- else:
+ ensure(dyn_kwargs is None)
+ next(self.stream)
+ dyn_kwargs = self.parse_expression()
+ else:
if (
self.stream.current.type == "name"
and self.stream.look().type == "assign"
):
# Parsing a kwarg
ensure(dyn_kwargs is None)
- key = self.stream.current.value
- self.stream.skip(2)
- value = self.parse_expression()
+ key = self.stream.current.value
+ self.stream.skip(2)
+ value = self.parse_expression()
kwargs.append(nodes.Keyword(key, value, lineno=value.lineno))
- else:
+ else:
# Parsing an arg
ensure(dyn_args is None and dyn_kwargs is None and not kwargs)
- args.append(self.parse_expression())
-
- require_comma = True
+ args.append(self.parse_expression())
+
+ require_comma = True
self.stream.expect("rparen")
return args, kwargs, dyn_args, dyn_kwargs
-
+
def parse_call(self, node: nodes.Expr) -> nodes.Call:
# The lparen will be expected in parse_call_args, but the lineno
# needs to be recorded before the stream is advanced.
token = self.stream.current
args, kwargs, dyn_args, dyn_kwargs = self.parse_call_args()
return nodes.Call(node, args, kwargs, dyn_args, dyn_kwargs, lineno=token.lineno)
-
+
def parse_filter(
self, node: t.Optional[nodes.Expr], start_inline: bool = False
) -> t.Optional[nodes.Expr]:
while self.stream.current.type == "pipe" or start_inline:
- if not start_inline:
- next(self.stream)
+ if not start_inline:
+ next(self.stream)
token = self.stream.expect("name")
- name = token.value
+ name = token.value
while self.stream.current.type == "dot":
- next(self.stream)
+ next(self.stream)
name += "." + self.stream.expect("name").value
if self.stream.current.type == "lparen":
args, kwargs, dyn_args, dyn_kwargs = self.parse_call_args()
- else:
- args = []
- kwargs = []
- dyn_args = dyn_kwargs = None
+ else:
+ args = []
+ kwargs = []
+ dyn_args = dyn_kwargs = None
node = nodes.Filter(
node, name, args, kwargs, dyn_args, dyn_kwargs, lineno=token.lineno
)
- start_inline = False
- return node
-
+ start_inline = False
+ return node
+
def parse_test(self, node: nodes.Expr) -> nodes.Expr:
- token = next(self.stream)
+ token = next(self.stream)
if self.stream.current.test("name:not"):
- next(self.stream)
- negated = True
- else:
- negated = False
+ next(self.stream)
+ negated = True
+ else:
+ negated = False
name = self.stream.expect("name").value
while self.stream.current.type == "dot":
- next(self.stream)
+ next(self.stream)
name += "." + self.stream.expect("name").value
- dyn_args = dyn_kwargs = None
- kwargs = []
+ dyn_args = dyn_kwargs = None
+ kwargs = []
if self.stream.current.type == "lparen":
args, kwargs, dyn_args, dyn_kwargs = self.parse_call_args()
elif (
@@ -975,66 +975,66 @@ class Parser:
arg_node = self.parse_primary()
arg_node = self.parse_postfix(arg_node)
args = [arg_node]
- else:
- args = []
+ else:
+ args = []
node = nodes.Test(
node, name, args, kwargs, dyn_args, dyn_kwargs, lineno=token.lineno
)
- if negated:
- node = nodes.Not(node, lineno=token.lineno)
- return node
-
+ if negated:
+ node = nodes.Not(node, lineno=token.lineno)
+ return node
+
def subparse(
self, end_tokens: t.Optional[t.Tuple[str, ...]] = None
) -> t.List[nodes.Node]:
body: t.List[nodes.Node] = []
data_buffer: t.List[nodes.Node] = []
- add_data = data_buffer.append
-
- if end_tokens is not None:
- self._end_token_stack.append(end_tokens)
-
+ add_data = data_buffer.append
+
+ if end_tokens is not None:
+ self._end_token_stack.append(end_tokens)
+
def flush_data() -> None:
- if data_buffer:
- lineno = data_buffer[0].lineno
- body.append(nodes.Output(data_buffer[:], lineno=lineno))
- del data_buffer[:]
-
- try:
- while self.stream:
- token = self.stream.current
+ if data_buffer:
+ lineno = data_buffer[0].lineno
+ body.append(nodes.Output(data_buffer[:], lineno=lineno))
+ del data_buffer[:]
+
+ try:
+ while self.stream:
+ token = self.stream.current
if token.type == "data":
- if token.value:
+ if token.value:
add_data(nodes.TemplateData(token.value, lineno=token.lineno))
- next(self.stream)
+ next(self.stream)
elif token.type == "variable_begin":
- next(self.stream)
- add_data(self.parse_tuple(with_condexpr=True))
+ next(self.stream)
+ add_data(self.parse_tuple(with_condexpr=True))
self.stream.expect("variable_end")
elif token.type == "block_begin":
- flush_data()
- next(self.stream)
+ flush_data()
+ next(self.stream)
if end_tokens is not None and self.stream.current.test_any(
*end_tokens
):
- return body
- rv = self.parse_statement()
- if isinstance(rv, list):
- body.extend(rv)
- else:
- body.append(rv)
+ return body
+ rv = self.parse_statement()
+ if isinstance(rv, list):
+ body.extend(rv)
+ else:
+ body.append(rv)
self.stream.expect("block_end")
- else:
+ else:
raise AssertionError("internal parsing error")
-
- flush_data()
- finally:
- if end_tokens is not None:
- self._end_token_stack.pop()
- return body
-
+
+ flush_data()
+ finally:
+ if end_tokens is not None:
+ self._end_token_stack.pop()
+ return body
+
def parse(self) -> nodes.Template:
- """Parse the whole template into a `Template` node."""
- result = nodes.Template(self.subparse(), lineno=1)
- result.set_environment(self.environment)
- return result
+ """Parse the whole template into a `Template` node."""
+ result = nodes.Template(self.subparse(), lineno=1)
+ result.set_environment(self.environment)
+ return result
diff --git a/contrib/python/Jinja2/py3/jinja2/runtime.py b/contrib/python/Jinja2/py3/jinja2/runtime.py
index 2346cf2bac..998dfbef43 100644
--- a/contrib/python/Jinja2/py3/jinja2/runtime.py
+++ b/contrib/python/Jinja2/py3/jinja2/runtime.py
@@ -1,14 +1,14 @@
"""The runtime functions and state used by compiled templates."""
import functools
-import sys
+import sys
import typing as t
from collections import abc
-from itertools import chain
-
+from itertools import chain
+
from markupsafe import escape # noqa: F401
from markupsafe import Markup
from markupsafe import soft_str
-
+
from .async_utils import auto_aiter
from .async_utils import auto_await # noqa: F401
from .exceptions import TemplateNotFound # noqa: F401
@@ -22,7 +22,7 @@ from .utils import missing
from .utils import Namespace # noqa: F401
from .utils import object_type_repr
from .utils import pass_eval_context
-
+
V = t.TypeVar("V")
F = t.TypeVar("F", bound=t.Callable[..., t.Any])
@@ -41,7 +41,7 @@ if t.TYPE_CHECKING:
...
-# these variables are exported to the template runtime
+# these variables are exported to the template runtime
exported = [
"LoopContext",
"TemplateReference",
@@ -64,31 +64,31 @@ async_exported = [
"auto_aiter",
"auto_await",
]
-
-
+
+
def identity(x: V) -> V:
"""Returns its argument. Useful for certain things in the
environment.
"""
return x
-
-
+
+
def markup_join(seq: t.Iterable[t.Any]) -> str:
"""Concatenation that escapes if necessary and converts to string."""
- buf = []
+ buf = []
iterator = map(soft_str, seq)
- for arg in iterator:
- buf.append(arg)
+ for arg in iterator:
+ buf.append(arg)
if hasattr(arg, "__html__"):
return Markup("").join(chain(buf, iterator))
- return concat(buf)
-
-
+ return concat(buf)
+
+
def str_join(seq: t.Iterable[t.Any]) -> str:
"""Simple args to string conversion and concatenation."""
return concat(map(str, seq))
-
-
+
+
def unicode_join(seq: t.Iterable[t.Any]) -> str:
import warnings
@@ -111,70 +111,70 @@ def new_context(
locals: t.Optional[t.Mapping[str, t.Any]] = None,
) -> "Context":
"""Internal helper for context creation."""
- if vars is None:
- vars = {}
- if shared:
- parent = vars
- else:
- parent = dict(globals or (), **vars)
- if locals:
- # if the parent is shared a copy should be created because
- # we don't want to modify the dict passed
- if shared:
- parent = dict(parent)
+ if vars is None:
+ vars = {}
+ if shared:
+ parent = vars
+ else:
+ parent = dict(globals or (), **vars)
+ if locals:
+ # if the parent is shared a copy should be created because
+ # we don't want to modify the dict passed
+ if shared:
+ parent = dict(parent)
for key, value in locals.items():
- if value is not missing:
- parent[key] = value
+ if value is not missing:
+ parent[key] = value
return environment.context_class(
environment, parent, template_name, blocks, globals=globals
)
-
-
+
+
class TemplateReference:
- """The `self` in templates."""
-
+ """The `self` in templates."""
+
def __init__(self, context: "Context") -> None:
- self.__context = context
-
+ self.__context = context
+
def __getitem__(self, name: str) -> t.Any:
- blocks = self.__context.blocks[name]
- return BlockReference(name, self.__context, blocks, 0)
-
+ blocks = self.__context.blocks[name]
+ return BlockReference(name, self.__context, blocks, 0)
+
def __repr__(self) -> str:
return f"<{type(self).__name__} {self.__context.name!r}>"
-
-
+
+
def _dict_method_all(dict_method: F) -> F:
@functools.wraps(dict_method)
def f_all(self: "Context") -> t.Any:
return dict_method(self.get_all())
-
+
return t.cast(F, f_all)
-
-
+
+
@abc.Mapping.register
class Context:
- """The template context holds the variables of a template. It stores the
- values passed to the template and also the names the template exports.
- Creating instances is neither supported nor useful as it's created
- automatically at various stages of the template evaluation and should not
- be created by hand.
-
- The context is immutable. Modifications on :attr:`parent` **must not**
- happen and modifications on :attr:`vars` are allowed from generated
- template code only. Template filters and global functions marked as
+ """The template context holds the variables of a template. It stores the
+ values passed to the template and also the names the template exports.
+ Creating instances is neither supported nor useful as it's created
+ automatically at various stages of the template evaluation and should not
+ be created by hand.
+
+ The context is immutable. Modifications on :attr:`parent` **must not**
+ happen and modifications on :attr:`vars` are allowed from generated
+ template code only. Template filters and global functions marked as
:func:`pass_context` get the active context passed as first argument
- and are allowed to access the context read-only.
-
- The template context supports read only dict operations (`get`,
- `keys`, `values`, `items`, `iterkeys`, `itervalues`, `iteritems`,
- `__getitem__`, `__contains__`). Additionally there is a :meth:`resolve`
- method that doesn't fail with a `KeyError` but returns an
- :class:`Undefined` object for missing variables.
- """
+ and are allowed to access the context read-only.
+
+ The template context supports read only dict operations (`get`,
+ `keys`, `values`, `items`, `iterkeys`, `itervalues`, `iteritems`,
+ `__getitem__`, `__contains__`). Additionally there is a :meth:`resolve`
+ method that doesn't fail with a `KeyError` but returns an
+ :class:`Undefined` object for missing variables.
+ """
_legacy_resolve_mode: t.ClassVar[bool] = False
-
+
def __init_subclass__(cls) -> None:
if "resolve_or_missing" in cls.__dict__:
# If the subclass overrides resolve_or_missing it opts in to
@@ -202,45 +202,45 @@ class Context:
blocks: t.Dict[str, t.Callable[["Context"], t.Iterator[str]]],
globals: t.Optional[t.MutableMapping[str, t.Any]] = None,
):
- self.parent = parent
+ self.parent = parent
self.vars: t.Dict[str, t.Any] = {}
self.environment: "Environment" = environment
- self.eval_ctx = EvalContext(self.environment, name)
+ self.eval_ctx = EvalContext(self.environment, name)
self.exported_vars: t.Set[str] = set()
- self.name = name
+ self.name = name
self.globals_keys = set() if globals is None else set(globals)
-
- # create the initial mapping of blocks. Whenever template inheritance
- # takes place the runtime will update this mapping with the new blocks
- # from the template.
+
+ # create the initial mapping of blocks. Whenever template inheritance
+ # takes place the runtime will update this mapping with the new blocks
+ # from the template.
self.blocks = {k: [v] for k, v in blocks.items()}
-
+
def super(
self, name: str, current: t.Callable[["Context"], t.Iterator[str]]
) -> t.Union["BlockReference", "Undefined"]:
- """Render a parent block."""
- try:
- blocks = self.blocks[name]
- index = blocks.index(current) + 1
- blocks[index]
- except LookupError:
+ """Render a parent block."""
+ try:
+ blocks = self.blocks[name]
+ index = blocks.index(current) + 1
+ blocks[index]
+ except LookupError:
return self.environment.undefined(
f"there is no parent block called {name!r}.", name="super"
)
- return BlockReference(name, self, blocks, index)
-
+ return BlockReference(name, self, blocks, index)
+
def get(self, key: str, default: t.Any = None) -> t.Any:
"""Look up a variable by name, or return a default if the key is
not found.
:param key: The variable name to look up.
:param default: The value to return if the key is not found.
- """
- try:
- return self[key]
- except KeyError:
- return default
-
+ """
+ try:
+ return self[key]
+ except KeyError:
+ return default
+
def resolve(self, key: str) -> t.Union[t.Any, "Undefined"]:
"""Look up a variable by name, or return an :class:`Undefined`
object if the key is not found.
@@ -250,8 +250,8 @@ class Context:
functions use that method, not this one.
:param key: The variable name to look up.
- """
- if self._legacy_resolve_mode:
+ """
+ if self._legacy_resolve_mode:
if key in self.vars:
return self.vars[key]
@@ -262,11 +262,11 @@ class Context:
rv = self.resolve_or_missing(key)
- if rv is missing:
- return self.environment.undefined(name=key)
-
- return rv
+ if rv is missing:
+ return self.environment.undefined(name=key)
+ return rv
+
def resolve_or_missing(self, key: str) -> t.Any:
"""Look up a variable by name, or return a ``missing`` sentinel
if the key is not found.
@@ -276,15 +276,15 @@ class Context:
method. Don't call this method directly.
:param key: The variable name to look up.
- """
- if self._legacy_resolve_mode:
- rv = self.resolve(key)
+ """
+ if self._legacy_resolve_mode:
+ rv = self.resolve(key)
- if isinstance(rv, Undefined):
+ if isinstance(rv, Undefined):
return missing
- return rv
-
+ return rv
+
if key in self.vars:
return self.vars[key]
@@ -294,39 +294,39 @@ class Context:
return missing
def get_exported(self) -> t.Dict[str, t.Any]:
- """Get a new dict with the exported variables."""
+ """Get a new dict with the exported variables."""
return {k: self.vars[k] for k in self.exported_vars}
-
+
def get_all(self) -> t.Dict[str, t.Any]:
- """Return the complete context as dict including the exported
- variables. For optimizations reasons this might not return an
- actual copy so be careful with using it.
- """
- if not self.vars:
- return self.parent
- if not self.parent:
- return self.vars
- return dict(self.parent, **self.vars)
-
- @internalcode
+ """Return the complete context as dict including the exported
+ variables. For optimizations reasons this might not return an
+ actual copy so be careful with using it.
+ """
+ if not self.vars:
+ return self.parent
+ if not self.parent:
+ return self.vars
+ return dict(self.parent, **self.vars)
+
+ @internalcode
def call(
__self, __obj: t.Callable, *args: t.Any, **kwargs: t.Any # noqa: B902
) -> t.Union[t.Any, "Undefined"]:
- """Call the callable with the arguments and keyword arguments
- provided but inject the active context or environment as first
+ """Call the callable with the arguments and keyword arguments
+ provided but inject the active context or environment as first
argument if the callable has :func:`pass_context` or
:func:`pass_environment`.
- """
- if __debug__:
- __traceback_hide__ = True # noqa
-
- # Allow callable classes to take a context
+ """
+ if __debug__:
+ __traceback_hide__ = True # noqa
+
+ # Allow callable classes to take a context
if (
hasattr(__obj, "__call__") # noqa: B004
and _PassArg.from_obj(__obj.__call__) is not None # type: ignore
):
__obj = __obj.__call__ # type: ignore
-
+
pass_arg = _PassArg.from_obj(__obj)
if pass_arg is _PassArg.context:
@@ -345,51 +345,51 @@ class Context:
kwargs.pop("_block_vars", None)
kwargs.pop("_loop_vars", None)
- try:
- return __obj(*args, **kwargs)
- except StopIteration:
+ try:
+ return __obj(*args, **kwargs)
+ except StopIteration:
return __self.environment.undefined(
"value was undefined because a callable raised a"
" StopIteration exception"
)
-
+
def derived(self, locals: t.Optional[t.Dict[str, t.Any]] = None) -> "Context":
- """Internal helper function to create a derived context. This is
- used in situations where the system needs a new context in the same
- template that is independent.
- """
+ """Internal helper function to create a derived context. This is
+ used in situations where the system needs a new context in the same
+ template that is independent.
+ """
context = new_context(
self.environment, self.name, {}, self.get_all(), True, None, locals
)
- context.eval_ctx = self.eval_ctx
+ context.eval_ctx = self.eval_ctx
context.blocks.update((k, list(v)) for k, v in self.blocks.items())
- return context
-
+ return context
+
keys = _dict_method_all(dict.keys)
values = _dict_method_all(dict.values)
items = _dict_method_all(dict.items)
def __contains__(self, name: str) -> bool:
- return name in self.vars or name in self.parent
-
+ return name in self.vars or name in self.parent
+
def __getitem__(self, key: str) -> t.Any:
"""Look up a variable by name with ``[]`` syntax, or raise a
``KeyError`` if the key is not found.
- """
- item = self.resolve_or_missing(key)
-
- if item is missing:
- raise KeyError(key)
+ """
+ item = self.resolve_or_missing(key)
- return item
+ if item is missing:
+ raise KeyError(key)
+ return item
+
def __repr__(self) -> str:
return f"<{type(self).__name__} {self.get_all()!r} of {self.name!r}>"
-
-
+
+
class BlockReference:
- """One block on a template reference."""
-
+ """One block on a template reference."""
+
def __init__(
self,
name: str,
@@ -397,21 +397,21 @@ class BlockReference:
stack: t.List[t.Callable[["Context"], t.Iterator[str]]],
depth: int,
) -> None:
- self.name = name
- self._context = context
- self._stack = stack
- self._depth = depth
-
- @property
+ self.name = name
+ self._context = context
+ self._stack = stack
+ self._depth = depth
+
+ @property
def super(self) -> t.Union["BlockReference", "Undefined"]:
- """Super the block."""
- if self._depth + 1 >= len(self._stack):
+ """Super the block."""
+ if self._depth + 1 >= len(self._stack):
return self._context.environment.undefined(
f"there is no parent block called {self.name!r}.", name="super"
)
return BlockReference(self.name, self._context, self._stack, self._depth + 1)
-
- @internalcode
+
+ @internalcode
async def _async_call(self) -> str:
rv = concat(
[x async for x in self._stack[self._depth](self._context)] # type: ignore
@@ -427,19 +427,19 @@ class BlockReference:
if self._context.environment.is_async:
return self._async_call() # type: ignore
- rv = concat(self._stack[self._depth](self._context))
+ rv = concat(self._stack[self._depth](self._context))
- if self._context.eval_ctx.autoescape:
+ if self._context.eval_ctx.autoescape:
return Markup(rv)
- return rv
-
-
+ return rv
+
+
class LoopContext:
"""A wrapper iterable for dynamic ``for`` loops, with information
about the loop and iteration.
"""
-
+
#: Current iteration of the loop, starting at 0.
index0 = -1
@@ -448,7 +448,7 @@ class LoopContext:
_current: t.Any = missing
_before: t.Any = missing
_last_changed_value: t.Any = missing
-
+
def __init__(
self,
iterable: t.Iterable[V],
@@ -466,68 +466,68 @@ class LoopContext:
"""
self._iterable = iterable
self._iterator = self._to_iterator(iterable)
- self._undefined = undefined
- self._recurse = recurse
+ self._undefined = undefined
+ self._recurse = recurse
#: How many levels deep a recursive loop currently is, starting at 0.
- self.depth0 = depth0
-
+ self.depth0 = depth0
+
@staticmethod
def _to_iterator(iterable: t.Iterable[V]) -> t.Iterator[V]:
return iter(iterable)
-
+
@property
def length(self) -> int:
"""Length of the iterable.
-
+
If the iterable is a generator or otherwise does not have a
size, it is eagerly evaluated to get a size.
"""
if self._length is not None:
return self._length
-
+
try:
self._length = len(self._iterable) # type: ignore
except TypeError:
iterable = list(self._iterator)
self._iterator = self._to_iterator(iterable)
self._length = len(iterable) + self.index + (self._after is not missing)
-
+
return self._length
-
+
def __len__(self) -> int:
- return self.length
-
+ return self.length
+
@property
def depth(self) -> int:
"""How many levels deep a recursive loop currently is, starting at 1."""
return self.depth0 + 1
-
+
@property
def index(self) -> int:
"""Current iteration of the loop, starting at 1."""
return self.index0 + 1
-
+
@property
def revindex0(self) -> int:
"""Number of iterations from the end of the loop, ending at 0.
-
+
Requires calculating :attr:`length`.
"""
return self.length - self.index
-
+
@property
def revindex(self) -> int:
"""Number of iterations from the end of the loop, ending at 1.
-
+
Requires calculating :attr:`length`.
"""
return self.length - self.index0
-
+
@property
def first(self) -> bool:
"""Whether this is the first iteration of the loop."""
return self.index0 == 0
-
+
def _peek_next(self) -> t.Any:
"""Return the next element in the iterable, or :data:`missing`
if the iterable is exhausted. Only peeks one item ahead, caching
@@ -540,16 +540,16 @@ class LoopContext:
self._after = next(self._iterator, missing)
return self._after
- @property
+ @property
def last(self) -> bool:
"""Whether this is the last iteration of the loop.
-
+
Causes the iterable to advance early. See
:func:`itertools.groupby` for issues this can cause.
The :func:`groupby` filter avoids that issue.
"""
return self._peek_next() is missing
-
+
@property
def previtem(self) -> t.Union[t.Any, "Undefined"]:
"""The item in the previous iteration. Undefined during the
@@ -557,20 +557,20 @@ class LoopContext:
"""
if self.first:
return self._undefined("there is no previous item")
-
+
return self._before
-
+
@property
def nextitem(self) -> t.Union[t.Any, "Undefined"]:
"""The item in the next iteration. Undefined during the last
iteration.
-
+
Causes the iterable to advance early. See
:func:`itertools.groupby` for issues this can cause.
The :func:`jinja-filters.groupby` filter avoids that issue.
"""
rv = self._peek_next()
-
+
if rv is missing:
return self._undefined("there is no next item")
@@ -600,20 +600,20 @@ class LoopContext:
return False
def __iter__(self) -> "LoopContext":
- return self
-
+ return self
+
def __next__(self) -> t.Tuple[t.Any, "LoopContext"]:
if self._after is not missing:
rv = self._after
self._after = missing
else:
rv = next(self._iterator)
-
+
self.index0 += 1
self._before = self._current
self._current = rv
return rv, self
-
+
@internalcode
def __call__(self, iterable: t.Iterable[V]) -> str:
"""When iterating over nested data, render the body of the loop
@@ -704,8 +704,8 @@ class AsyncLoopContext(LoopContext):
class Macro:
- """Wraps a macro function."""
-
+ """Wraps a macro function."""
+
def __init__(
self,
environment: "Environment",
@@ -717,84 +717,84 @@ class Macro:
caller: bool,
default_autoescape: t.Optional[bool] = None,
):
- self._environment = environment
- self._func = func
- self._argument_count = len(arguments)
- self.name = name
- self.arguments = arguments
- self.catch_kwargs = catch_kwargs
- self.catch_varargs = catch_varargs
- self.caller = caller
+ self._environment = environment
+ self._func = func
+ self._argument_count = len(arguments)
+ self.name = name
+ self.arguments = arguments
+ self.catch_kwargs = catch_kwargs
+ self.catch_varargs = catch_varargs
+ self.caller = caller
self.explicit_caller = "caller" in arguments
- if default_autoescape is None:
+ if default_autoescape is None:
if callable(environment.autoescape):
default_autoescape = environment.autoescape(None)
else:
default_autoescape = environment.autoescape
- self._default_autoescape = default_autoescape
-
- @internalcode
+ self._default_autoescape = default_autoescape
+
+ @internalcode
@pass_eval_context
def __call__(self, *args: t.Any, **kwargs: t.Any) -> str:
- # This requires a bit of explanation, In the past we used to
- # decide largely based on compile-time information if a macro is
- # safe or unsafe. While there was a volatile mode it was largely
- # unused for deciding on escaping. This turns out to be
+ # This requires a bit of explanation, In the past we used to
+ # decide largely based on compile-time information if a macro is
+ # safe or unsafe. While there was a volatile mode it was largely
+ # unused for deciding on escaping. This turns out to be
# problematic for macros because whether a macro is safe depends not
# on the escape mode when it was defined, but rather when it was used.
- #
- # Because however we export macros from the module system and
- # there are historic callers that do not pass an eval context (and
- # will continue to not pass one), we need to perform an instance
- # check here.
- #
- # This is considered safe because an eval context is not a valid
+ #
+ # Because however we export macros from the module system and
+ # there are historic callers that do not pass an eval context (and
+ # will continue to not pass one), we need to perform an instance
+ # check here.
+ #
+ # This is considered safe because an eval context is not a valid
# argument to callables otherwise anyway. Worst case here is
- # that if no eval context is passed we fall back to the compile
- # time autoescape flag.
- if args and isinstance(args[0], EvalContext):
- autoescape = args[0].autoescape
- args = args[1:]
- else:
- autoescape = self._default_autoescape
-
- # try to consume the positional arguments
+ # that if no eval context is passed we fall back to the compile
+ # time autoescape flag.
+ if args and isinstance(args[0], EvalContext):
+ autoescape = args[0].autoescape
+ args = args[1:]
+ else:
+ autoescape = self._default_autoescape
+
+ # try to consume the positional arguments
arguments = list(args[: self._argument_count])
- off = len(arguments)
-
- # For information why this is necessary refer to the handling
- # of caller in the `macro_body` handler in the compiler.
- found_caller = False
-
- # if the number of arguments consumed is not the number of
- # arguments expected we start filling in keyword arguments
- # and defaults.
- if off != self._argument_count:
+ off = len(arguments)
+
+ # For information why this is necessary refer to the handling
+ # of caller in the `macro_body` handler in the compiler.
+ found_caller = False
+
+ # if the number of arguments consumed is not the number of
+ # arguments expected we start filling in keyword arguments
+ # and defaults.
+ if off != self._argument_count:
for name in self.arguments[len(arguments) :]:
- try:
- value = kwargs.pop(name)
- except KeyError:
- value = missing
+ try:
+ value = kwargs.pop(name)
+ except KeyError:
+ value = missing
if name == "caller":
- found_caller = True
- arguments.append(value)
- else:
- found_caller = self.explicit_caller
-
- # it's important that the order of these arguments does not change
- # if not also changed in the compiler's `function_scoping` method.
- # the order is caller, keyword arguments, positional arguments!
- if self.caller and not found_caller:
+ found_caller = True
+ arguments.append(value)
+ else:
+ found_caller = self.explicit_caller
+
+ # it's important that the order of these arguments does not change
+ # if not also changed in the compiler's `function_scoping` method.
+ # the order is caller, keyword arguments, positional arguments!
+ if self.caller and not found_caller:
caller = kwargs.pop("caller", None)
- if caller is None:
+ if caller is None:
caller = self._environment.undefined("No caller defined", name="caller")
- arguments.append(caller)
-
- if self.catch_kwargs:
- arguments.append(kwargs)
- elif kwargs:
+ arguments.append(caller)
+
+ if self.catch_kwargs:
+ arguments.append(kwargs)
+ elif kwargs:
if "caller" in kwargs:
raise TypeError(
f"macro {self.name!r} was invoked with two values for the special"
@@ -803,16 +803,16 @@ class Macro:
raise TypeError(
f"macro {self.name!r} takes no keyword argument {next(iter(kwargs))!r}"
)
- if self.catch_varargs:
+ if self.catch_varargs:
arguments.append(args[self._argument_count :])
- elif len(args) > self._argument_count:
+ elif len(args) > self._argument_count:
raise TypeError(
f"macro {self.name!r} takes not more than"
f" {len(self.arguments)} argument(s)"
)
-
- return self._invoke(arguments, autoescape)
-
+
+ return self._invoke(arguments, autoescape)
+
async def _async_invoke(self, arguments: t.List[t.Any], autoescape: bool) -> str:
rv = await self._func(*arguments) # type: ignore
@@ -825,33 +825,33 @@ class Macro:
if self._environment.is_async:
return self._async_invoke(arguments, autoescape) # type: ignore
- rv = self._func(*arguments)
+ rv = self._func(*arguments)
- if autoescape:
- rv = Markup(rv)
-
- return rv
+ if autoescape:
+ rv = Markup(rv)
+ return rv
+
def __repr__(self) -> str:
name = "anonymous" if self.name is None else repr(self.name)
return f"<{type(self).__name__} {name}>"
-
-
+
+
class Undefined:
- """The default undefined type. This undefined type can be printed and
+ """The default undefined type. This undefined type can be printed and
iterated over, but every other access will raise an :exc:`UndefinedError`:
-
- >>> foo = Undefined(name='foo')
- >>> str(foo)
- ''
- >>> not foo
- True
- >>> foo + 42
- Traceback (most recent call last):
- ...
- jinja2.exceptions.UndefinedError: 'foo' is undefined
- """
-
+
+ >>> foo = Undefined(name='foo')
+ >>> str(foo)
+ ''
+ >>> not foo
+ True
+ >>> foo + 42
+ Traceback (most recent call last):
+ ...
+ jinja2.exceptions.UndefinedError: 'foo' is undefined
+ """
+
__slots__ = (
"_undefined_hint",
"_undefined_obj",
@@ -866,11 +866,11 @@ class Undefined:
name: t.Optional[str] = None,
exc: t.Type[TemplateRuntimeError] = UndefinedError,
) -> None:
- self._undefined_hint = hint
- self._undefined_obj = obj
- self._undefined_name = name
- self._undefined_exception = exc
-
+ self._undefined_hint = hint
+ self._undefined_obj = obj
+ self._undefined_name = name
+ self._undefined_exception = exc
+
@property
def _undefined_message(self) -> str:
"""Build a message about the undefined value based on how it was
@@ -893,22 +893,22 @@ class Undefined:
f" attribute {self._undefined_name!r}"
)
- @internalcode
+ @internalcode
def _fail_with_undefined_error(
self, *args: t.Any, **kwargs: t.Any
) -> "te.NoReturn":
"""Raise an :exc:`UndefinedError` when operations are performed
on the undefined value.
- """
+ """
raise self._undefined_exception(self._undefined_message)
-
- @internalcode
+
+ @internalcode
def __getattr__(self, name: str) -> t.Any:
if name[:2] == "__":
- raise AttributeError(name)
-
- return self._fail_with_undefined_error()
+ raise AttributeError(name)
+ return self._fail_with_undefined_error()
+
__add__ = __radd__ = __sub__ = __rsub__ = _fail_with_undefined_error
__mul__ = __rmul__ = __div__ = __rdiv__ = _fail_with_undefined_error
__truediv__ = __rtruediv__ = _fail_with_undefined_error
@@ -919,96 +919,96 @@ class Undefined:
__lt__ = __le__ = __gt__ = __ge__ = _fail_with_undefined_error
__int__ = __float__ = __complex__ = _fail_with_undefined_error
__pow__ = __rpow__ = _fail_with_undefined_error
-
+
def __eq__(self, other: t.Any) -> bool:
- return type(self) is type(other)
-
+ return type(self) is type(other)
+
def __ne__(self, other: t.Any) -> bool:
- return not self.__eq__(other)
-
+ return not self.__eq__(other)
+
def __hash__(self) -> int:
- return id(type(self))
-
+ return id(type(self))
+
def __str__(self) -> str:
return ""
-
+
def __len__(self) -> int:
- return 0
-
+ return 0
+
def __iter__(self) -> t.Iterator[t.Any]:
yield from ()
-
+
async def __aiter__(self) -> t.AsyncIterator[t.Any]:
for _ in ():
yield
def __bool__(self) -> bool:
- return False
+ return False
def __repr__(self) -> str:
return "Undefined"
-
-
+
+
def make_logging_undefined(
logger: t.Optional["logging.Logger"] = None, base: t.Type[Undefined] = Undefined
) -> t.Type[Undefined]:
- """Given a logger object this returns a new undefined class that will
- log certain failures. It will log iterations and printing. If no
- logger is given a default logger is created.
-
- Example::
-
- logger = logging.getLogger(__name__)
- LoggingUndefined = make_logging_undefined(
- logger=logger,
- base=Undefined
- )
-
- .. versionadded:: 2.8
-
- :param logger: the logger to use. If not provided, a default logger
- is created.
- :param base: the base class to add logging functionality to. This
- defaults to :class:`Undefined`.
- """
- if logger is None:
- import logging
-
- logger = logging.getLogger(__name__)
- logger.addHandler(logging.StreamHandler(sys.stderr))
-
+ """Given a logger object this returns a new undefined class that will
+ log certain failures. It will log iterations and printing. If no
+ logger is given a default logger is created.
+
+ Example::
+
+ logger = logging.getLogger(__name__)
+ LoggingUndefined = make_logging_undefined(
+ logger=logger,
+ base=Undefined
+ )
+
+ .. versionadded:: 2.8
+
+ :param logger: the logger to use. If not provided, a default logger
+ is created.
+ :param base: the base class to add logging functionality to. This
+ defaults to :class:`Undefined`.
+ """
+ if logger is None:
+ import logging
+
+ logger = logging.getLogger(__name__)
+ logger.addHandler(logging.StreamHandler(sys.stderr))
+
def _log_message(undef: Undefined) -> None:
logger.warning( # type: ignore
"Template variable warning: %s", undef._undefined_message
)
-
+
class LoggingUndefined(base): # type: ignore
__slots__ = ()
def _fail_with_undefined_error( # type: ignore
self, *args: t.Any, **kwargs: t.Any
) -> "te.NoReturn":
- try:
+ try:
super()._fail_with_undefined_error(*args, **kwargs)
- except self._undefined_exception as e:
+ except self._undefined_exception as e:
logger.error("Template variable error: %s", e) # type: ignore
- raise e
-
+ raise e
+
def __str__(self) -> str:
- _log_message(self)
+ _log_message(self)
return super().__str__() # type: ignore
-
+
def __iter__(self) -> t.Iterator[t.Any]:
- _log_message(self)
+ _log_message(self)
return super().__iter__() # type: ignore
-
+
def __bool__(self) -> bool:
_log_message(self)
return super().__bool__() # type: ignore
- return LoggingUndefined
-
-
+ return LoggingUndefined
+
+
class ChainableUndefined(Undefined):
"""An undefined that is chainable, where both ``__getattr__`` and
``__getitem__`` return itself rather than raising an
@@ -1036,22 +1036,22 @@ class ChainableUndefined(Undefined):
__getitem__ = __getattr__ # type: ignore
-class DebugUndefined(Undefined):
- """An undefined that returns the debug info when printed.
-
- >>> foo = DebugUndefined(name='foo')
- >>> str(foo)
- '{{ foo }}'
- >>> not foo
- True
- >>> foo + 42
- Traceback (most recent call last):
- ...
- jinja2.exceptions.UndefinedError: 'foo' is undefined
- """
-
- __slots__ = ()
-
+class DebugUndefined(Undefined):
+ """An undefined that returns the debug info when printed.
+
+ >>> foo = DebugUndefined(name='foo')
+ >>> str(foo)
+ '{{ foo }}'
+ >>> not foo
+ True
+ >>> foo + 42
+ Traceback (most recent call last):
+ ...
+ jinja2.exceptions.UndefinedError: 'foo' is undefined
+ """
+
+ __slots__ = ()
+
def __str__(self) -> str:
if self._undefined_hint:
message = f"undefined value printed: {self._undefined_hint}"
@@ -1063,37 +1063,37 @@ class DebugUndefined(Undefined):
message = (
f"no such element: {object_type_repr(self._undefined_obj)}"
f"[{self._undefined_name!r}]"
- )
-
+ )
+
return f"{{{{ {message} }}}}"
-
-
-class StrictUndefined(Undefined):
- """An undefined that barks on print and iteration as well as boolean
- tests and all kinds of comparisons. In other words: you can do nothing
- with it except checking if it's defined using the `defined` test.
-
- >>> foo = StrictUndefined(name='foo')
- >>> str(foo)
- Traceback (most recent call last):
- ...
- jinja2.exceptions.UndefinedError: 'foo' is undefined
- >>> not foo
- Traceback (most recent call last):
- ...
- jinja2.exceptions.UndefinedError: 'foo' is undefined
- >>> foo + 42
- Traceback (most recent call last):
- ...
- jinja2.exceptions.UndefinedError: 'foo' is undefined
- """
-
- __slots__ = ()
+
+
+class StrictUndefined(Undefined):
+ """An undefined that barks on print and iteration as well as boolean
+ tests and all kinds of comparisons. In other words: you can do nothing
+ with it except checking if it's defined using the `defined` test.
+
+ >>> foo = StrictUndefined(name='foo')
+ >>> str(foo)
+ Traceback (most recent call last):
+ ...
+ jinja2.exceptions.UndefinedError: 'foo' is undefined
+ >>> not foo
+ Traceback (most recent call last):
+ ...
+ jinja2.exceptions.UndefinedError: 'foo' is undefined
+ >>> foo + 42
+ Traceback (most recent call last):
+ ...
+ jinja2.exceptions.UndefinedError: 'foo' is undefined
+ """
+
+ __slots__ = ()
__iter__ = __str__ = __len__ = Undefined._fail_with_undefined_error
__eq__ = __ne__ = __bool__ = __hash__ = Undefined._fail_with_undefined_error
__contains__ = Undefined._fail_with_undefined_error
-
-
+
+
# Remove slots attributes, after the metaclass is applied they are
# unneeded and contain wrong data for subclasses.
del (
diff --git a/contrib/python/Jinja2/py3/jinja2/sandbox.py b/contrib/python/Jinja2/py3/jinja2/sandbox.py
index 4294884776..2c6726636d 100644
--- a/contrib/python/Jinja2/py3/jinja2/sandbox.py
+++ b/contrib/python/Jinja2/py3/jinja2/sandbox.py
@@ -1,42 +1,42 @@
"""A sandbox layer that ensures unsafe operations cannot be performed.
Useful when the template itself comes from an untrusted source.
-"""
+"""
import operator
-import types
+import types
import typing as t
from _string import formatter_field_name_split # type: ignore
from collections import abc
from collections import deque
from string import Formatter
-
-from markupsafe import EscapeFormatter
+
+from markupsafe import EscapeFormatter
from markupsafe import Markup
-
+
from .environment import Environment
from .exceptions import SecurityError
from .runtime import Context
from .runtime import Undefined
-
+
F = t.TypeVar("F", bound=t.Callable[..., t.Any])
-#: maximum number of items a range may produce
-MAX_RANGE = 100000
-
+#: maximum number of items a range may produce
+MAX_RANGE = 100000
+
#: Unsafe function attributes.
UNSAFE_FUNCTION_ATTRIBUTES: t.Set[str] = set()
-
+
#: Unsafe method attributes. Function attributes are unsafe for methods too.
UNSAFE_METHOD_ATTRIBUTES: t.Set[str] = set()
-
+
#: unsafe generator attributes.
UNSAFE_GENERATOR_ATTRIBUTES = {"gi_frame", "gi_code"}
-
-#: unsafe attributes on coroutines
+
+#: unsafe attributes on coroutines
UNSAFE_COROUTINE_ATTRIBUTES = {"cr_frame", "cr_code"}
-
-#: unsafe attributes on async generators
+
+#: unsafe attributes on async generators
UNSAFE_ASYNC_GENERATOR_ATTRIBUTES = {"ag_code", "ag_frame"}
-
+
_mutable_spec: t.Tuple[t.Tuple[t.Type, t.FrozenSet[str]], ...] = (
(
abc.MutableSet,
@@ -77,129 +77,129 @@ _mutable_spec: t.Tuple[t.Tuple[t.Type, t.FrozenSet[str]], ...] = (
]
),
),
-)
-
-
+)
+
+
def inspect_format_method(callable: t.Callable) -> t.Optional[str]:
if not isinstance(
callable, (types.MethodType, types.BuiltinMethodType)
) or callable.__name__ not in ("format", "format_map"):
- return None
+ return None
- obj = callable.__self__
+ obj = callable.__self__
if isinstance(obj, str):
- return obj
-
+ return obj
+
return None
-
+
def safe_range(*args: int) -> range:
- """A range that can't generate ranges with a length of more than
- MAX_RANGE items.
- """
+ """A range that can't generate ranges with a length of more than
+ MAX_RANGE items.
+ """
rng = range(*args)
- if len(rng) > MAX_RANGE:
+ if len(rng) > MAX_RANGE:
raise OverflowError(
"Range too big. The sandbox blocks ranges larger than"
f" MAX_RANGE ({MAX_RANGE})."
)
- return rng
-
-
+ return rng
+
+
def unsafe(f: F) -> F:
- """Marks a function or method as unsafe.
-
+ """Marks a function or method as unsafe.
+
.. code-block: python
-
- @unsafe
- def delete(self):
- pass
- """
+
+ @unsafe
+ def delete(self):
+ pass
+ """
f.unsafe_callable = True # type: ignore
- return f
-
-
+ return f
+
+
def is_internal_attribute(obj: t.Any, attr: str) -> bool:
- """Test if the attribute given is an internal python attribute. For
- example this function returns `True` for the `func_code` attribute of
- python objects. This is useful if the environment method
- :meth:`~SandboxedEnvironment.is_safe_attribute` is overridden.
-
- >>> from jinja2.sandbox import is_internal_attribute
- >>> is_internal_attribute(str, "mro")
- True
- >>> is_internal_attribute(str, "upper")
- False
- """
- if isinstance(obj, types.FunctionType):
- if attr in UNSAFE_FUNCTION_ATTRIBUTES:
- return True
- elif isinstance(obj, types.MethodType):
+ """Test if the attribute given is an internal python attribute. For
+ example this function returns `True` for the `func_code` attribute of
+ python objects. This is useful if the environment method
+ :meth:`~SandboxedEnvironment.is_safe_attribute` is overridden.
+
+ >>> from jinja2.sandbox import is_internal_attribute
+ >>> is_internal_attribute(str, "mro")
+ True
+ >>> is_internal_attribute(str, "upper")
+ False
+ """
+ if isinstance(obj, types.FunctionType):
+ 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:
- return True
- elif isinstance(obj, type):
+ return True
+ elif isinstance(obj, type):
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
+ 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):
- if attr in UNSAFE_COROUTINE_ATTRIBUTES:
- return True
+ if attr in UNSAFE_COROUTINE_ATTRIBUTES:
+ return True
elif hasattr(types, "AsyncGeneratorType") and isinstance(
obj, types.AsyncGeneratorType
):
- if attr in UNSAFE_ASYNC_GENERATOR_ATTRIBUTES:
- return True
+ if attr in UNSAFE_ASYNC_GENERATOR_ATTRIBUTES:
+ return True
return attr.startswith("__")
-
-
+
+
def modifies_known_mutable(obj: t.Any, attr: str) -> bool:
- """This function checks if an attribute on a builtin mutable object
+ """This function checks if an attribute on a builtin mutable object
(list, dict, set or deque) or the corresponding ABCs would modify it
if called.
-
- >>> modifies_known_mutable({}, "clear")
- True
- >>> modifies_known_mutable({}, "keys")
- False
- >>> modifies_known_mutable([], "append")
- True
- >>> modifies_known_mutable([], "index")
- False
-
+
+ >>> modifies_known_mutable({}, "clear")
+ True
+ >>> modifies_known_mutable({}, "keys")
+ False
+ >>> modifies_known_mutable([], "append")
+ True
+ >>> modifies_known_mutable([], "index")
+ False
+
If called with an unsupported object, ``False`` is returned.
-
- >>> modifies_known_mutable("foo", "upper")
- False
- """
- for typespec, unsafe in _mutable_spec:
- if isinstance(obj, typespec):
- return attr in unsafe
- return False
-
-
-class SandboxedEnvironment(Environment):
- """The sandboxed environment. It works like the regular environment but
- tells the compiler to generate sandboxed code. Additionally subclasses of
- this environment may override the methods that tell the runtime what
- attributes or functions are safe to access.
-
- If the template tries to access insecure code a :exc:`SecurityError` is
- 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`
+
+ >>> modifies_known_mutable("foo", "upper")
+ False
+ """
+ for typespec, unsafe in _mutable_spec:
+ if isinstance(obj, typespec):
+ return attr in unsafe
+ return False
+
+
+class SandboxedEnvironment(Environment):
+ """The sandboxed environment. It works like the regular environment but
+ tells the compiler to generate sandboxed code. Additionally subclasses of
+ this environment may override the methods that tell the runtime what
+ attributes or functions are safe to access.
+
+ If the template tries to access insecure code a :exc:`SecurityError` is
+ 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: t.Dict[str, t.Callable[[t.Any, t.Any], t.Any]] = {
"+": operator.add,
"-": operator.sub,
@@ -208,135 +208,135 @@ class SandboxedEnvironment(Environment):
"//": 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 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: t.Dict[str, t.Callable[[t.Any], t.Any]] = {
"+": 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
- #: :meth:`call_binop` method that will perform the operator. The default
- #: operator callback is specified by :attr:`binop_table`.
- #:
- #: The following binary operators are interceptable:
- #: ``//``, ``%``, ``+``, ``*``, ``-``, ``/``, and ``**``
- #:
- #: The default operation form the operator table corresponds to the
- #: builtin function. Intercepted calls are always slower than the native
- #: operator call, so make sure only to intercept the ones you are
- #: interested in.
- #:
- #: .. versionadded:: 2.6
+
+ #: a set of binary operators that should be intercepted. Each operator
+ #: that is added to this set (empty by default) is delegated to the
+ #: :meth:`call_binop` method that will perform the operator. The default
+ #: operator callback is specified by :attr:`binop_table`.
+ #:
+ #: The following binary operators are interceptable:
+ #: ``//``, ``%``, ``+``, ``*``, ``-``, ``/``, and ``**``
+ #:
+ #: The default operation form the operator table corresponds to the
+ #: builtin function. Intercepted calls are always slower than the native
+ #: operator call, so make sure only to intercept the ones you are
+ #: interested in.
+ #:
+ #: .. versionadded:: 2.6
intercepted_binops: t.FrozenSet[str] = frozenset()
-
- #: a set of unary operators that should be intercepted. Each operator
- #: that is added to this set (empty by default) is delegated to the
- #: :meth:`call_unop` method that will perform the operator. The default
- #: operator callback is specified by :attr:`unop_table`.
- #:
- #: The following unary operators are interceptable: ``+``, ``-``
- #:
- #: The default operation form the operator table corresponds to the
- #: builtin function. Intercepted calls are always slower than the native
- #: operator call, so make sure only to intercept the ones you are
- #: interested in.
- #:
- #: .. versionadded:: 2.6
+
+ #: a set of unary operators that should be intercepted. Each operator
+ #: that is added to this set (empty by default) is delegated to the
+ #: :meth:`call_unop` method that will perform the operator. The default
+ #: operator callback is specified by :attr:`unop_table`.
+ #:
+ #: The following unary operators are interceptable: ``+``, ``-``
+ #:
+ #: The default operation form the operator table corresponds to the
+ #: builtin function. Intercepted calls are always slower than the native
+ #: operator call, so make sure only to intercept the ones you are
+ #: interested in.
+ #:
+ #: .. versionadded:: 2.6
intercepted_unops: t.FrozenSet[str] = frozenset()
-
+
def __init__(self, *args: t.Any, **kwargs: t.Any) -> None:
super().__init__(*args, **kwargs)
self.globals["range"] = safe_range
- self.binop_table = self.default_binop_table.copy()
- self.unop_table = self.default_unop_table.copy()
-
+ self.binop_table = self.default_binop_table.copy()
+ self.unop_table = self.default_unop_table.copy()
+
def is_safe_attribute(self, obj: t.Any, attr: str, value: t.Any) -> bool:
- """The sandboxed environment will call this method to check if the
- attribute of an object is safe to access. Per default all attributes
- starting with an underscore are considered private as well as the
- special attributes of internal python objects as returned by the
- :func:`is_internal_attribute` function.
- """
+ """The sandboxed environment will call this method to check if the
+ attribute of an object is safe to access. Per default all attributes
+ starting with an underscore are considered private as well as the
+ 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))
-
+
def is_safe_callable(self, obj: t.Any) -> bool:
"""Check if an object is safely callable. By default callables
are considered safe unless decorated with :func:`unsafe`.
This also recognizes the Django convention of setting
``func.alters_data = True``.
- """
+ """
return not (
getattr(obj, "unsafe_callable", False) or getattr(obj, "alters_data", False)
)
-
+
def call_binop(
self, context: Context, operator: str, left: t.Any, right: t.Any
) -> t.Any:
- """For intercepted binary operator calls (:meth:`intercepted_binops`)
- this function is executed instead of the builtin operator. This can
- be used to fine tune the behavior of certain operators.
-
- .. versionadded:: 2.6
- """
- return self.binop_table[operator](left, right)
-
+ """For intercepted binary operator calls (:meth:`intercepted_binops`)
+ this function is executed instead of the builtin operator. This can
+ be used to fine tune the behavior of certain operators.
+
+ .. versionadded:: 2.6
+ """
+ return self.binop_table[operator](left, right)
+
def call_unop(self, context: Context, operator: str, arg: t.Any) -> t.Any:
- """For intercepted unary operator calls (:meth:`intercepted_unops`)
- this function is executed instead of the builtin operator. This can
- be used to fine tune the behavior of certain operators.
-
- .. versionadded:: 2.6
- """
- return self.unop_table[operator](arg)
-
+ """For intercepted unary operator calls (:meth:`intercepted_unops`)
+ this function is executed instead of the builtin operator. This can
+ be used to fine tune the behavior of certain operators.
+
+ .. versionadded:: 2.6
+ """
+ return self.unop_table[operator](arg)
+
def getitem(
self, obj: t.Any, argument: t.Union[str, t.Any]
) -> t.Union[t.Any, Undefined]:
- """Subscribe an object from sandboxed code."""
- try:
- return obj[argument]
- except (TypeError, LookupError):
+ """Subscribe an object from sandboxed code."""
+ try:
+ return obj[argument]
+ except (TypeError, LookupError):
if isinstance(argument, str):
- try:
- attr = str(argument)
- except Exception:
- pass
- else:
- try:
- value = getattr(obj, attr)
- except AttributeError:
- pass
- else:
- if self.is_safe_attribute(obj, argument, value):
- return value
- return self.unsafe_undefined(obj, argument)
- return self.undefined(obj=obj, name=argument)
-
+ try:
+ attr = str(argument)
+ except Exception:
+ pass
+ else:
+ try:
+ value = getattr(obj, attr)
+ except AttributeError:
+ pass
+ else:
+ if self.is_safe_attribute(obj, argument, value):
+ return value
+ return self.unsafe_undefined(obj, argument)
+ return self.undefined(obj=obj, name=argument)
+
def getattr(self, obj: t.Any, attribute: str) -> t.Union[t.Any, Undefined]:
- """Subscribe an object from sandboxed code and prefer the
- attribute. The attribute passed *must* be a bytestring.
- """
- try:
- value = getattr(obj, attribute)
- except AttributeError:
- try:
- return obj[attribute]
- except (TypeError, LookupError):
- pass
- else:
- if self.is_safe_attribute(obj, attribute, value):
- return value
- return self.unsafe_undefined(obj, attribute)
- return self.undefined(obj=obj, name=attribute)
-
+ """Subscribe an object from sandboxed code and prefer the
+ attribute. The attribute passed *must* be a bytestring.
+ """
+ try:
+ value = getattr(obj, attribute)
+ except AttributeError:
+ try:
+ return obj[attribute]
+ except (TypeError, LookupError):
+ pass
+ else:
+ if self.is_safe_attribute(obj, attribute, value):
+ return value
+ return self.unsafe_undefined(obj, attribute)
+ return self.undefined(obj=obj, name=attribute)
+
def unsafe_undefined(self, obj: t.Any, attribute: str) -> Undefined:
- """Return an undefined object for unsafe attributes."""
+ """Return an undefined object for unsafe attributes."""
return self.undefined(
f"access to attribute {attribute!r} of"
f" {type(obj).__name__!r} object is unsafe.",
@@ -344,7 +344,7 @@ class SandboxedEnvironment(Environment):
obj=obj,
exc=SecurityError,
)
-
+
def format_string(
self,
s: str,
@@ -352,14 +352,14 @@ class SandboxedEnvironment(Environment):
kwargs: t.Dict[str, t.Any],
format_func: t.Optional[t.Callable] = None,
) -> str:
- """If a format call is detected, then this is routed through this
- method so that our safety sandbox can be used for it.
- """
+ """If a format call is detected, then this is routed through this
+ method so that our safety sandbox can be used for it.
+ """
formatter: SandboxedFormatter
- if isinstance(s, Markup):
+ if isinstance(s, Markup):
formatter = SandboxedEscapeFormatter(self, escape=s.escape)
- else:
- formatter = SandboxedFormatter(self)
+ else:
+ formatter = SandboxedFormatter(self)
if format_func is not None and format_func.__name__ == "format_map":
if len(args) != 1 or kwargs:
@@ -371,9 +371,9 @@ class SandboxedEnvironment(Environment):
kwargs = args[0]
args = ()
- rv = formatter.vformat(s, args, kwargs)
- return type(s)(rv)
-
+ rv = formatter.vformat(s, args, kwargs)
+ return type(s)(rv)
+
def call(
__self, # noqa: B902
__context: Context,
@@ -381,48 +381,48 @@ class SandboxedEnvironment(Environment):
*args: t.Any,
**kwargs: t.Any,
) -> t.Any:
- """Call an object from sandboxed code."""
- fmt = inspect_format_method(__obj)
- if fmt is not None:
+ """Call an object from sandboxed code."""
+ fmt = inspect_format_method(__obj)
+ if fmt is not None:
return __self.format_string(fmt, args, kwargs, __obj)
-
- # the double prefixes are to avoid double keyword argument
- # errors when proxying the call.
- if not __self.is_safe_callable(__obj):
+
+ # the double prefixes are to avoid double keyword argument
+ # errors when proxying the call.
+ if not __self.is_safe_callable(__obj):
raise SecurityError(f"{__obj!r} is not safely callable")
- return __context.call(__obj, *args, **kwargs)
-
-
-class ImmutableSandboxedEnvironment(SandboxedEnvironment):
- """Works exactly like the regular `SandboxedEnvironment` but does not
- permit modifications on the builtin mutable objects `list`, `set`, and
- `dict` by using the :func:`modifies_known_mutable` function.
- """
-
+ return __context.call(__obj, *args, **kwargs)
+
+
+class ImmutableSandboxedEnvironment(SandboxedEnvironment):
+ """Works exactly like the regular `SandboxedEnvironment` but does not
+ permit modifications on the builtin mutable objects `list`, `set`, and
+ `dict` by using the :func:`modifies_known_mutable` function.
+ """
+
def is_safe_attribute(self, obj: t.Any, attr: str, value: t.Any) -> bool:
if not super().is_safe_attribute(obj, attr, value):
- return False
-
- return not modifies_known_mutable(obj, attr)
-
+ return False
+ return not modifies_known_mutable(obj, attr)
+
+
class SandboxedFormatter(Formatter):
def __init__(self, env: Environment, **kwargs: t.Any) -> None:
- self._env = env
+ self._env = env
super().__init__(**kwargs) # type: ignore
-
+
def get_field(
self, field_name: str, args: t.Sequence[t.Any], kwargs: t.Mapping[str, t.Any]
) -> t.Tuple[t.Any, str]:
- first, rest = formatter_field_name_split(field_name)
- obj = self.get_value(first, args, kwargs)
- for is_attr, i in rest:
- if is_attr:
- obj = self._env.getattr(obj, i)
- else:
- obj = self._env.getitem(obj, i)
- return obj, first
-
+ first, rest = formatter_field_name_split(field_name)
+ obj = self.get_value(first, args, kwargs)
+ for is_attr, i in rest:
+ if is_attr:
+ obj = self._env.getattr(obj, i)
+ else:
+ obj = self._env.getitem(obj, i)
+ return obj, first
+
class SandboxedEscapeFormatter(SandboxedFormatter, EscapeFormatter):
pass
diff --git a/contrib/python/Jinja2/py3/jinja2/tests.py b/contrib/python/Jinja2/py3/jinja2/tests.py
index a467cf08b5..ec973735a2 100644
--- a/contrib/python/Jinja2/py3/jinja2/tests.py
+++ b/contrib/python/Jinja2/py3/jinja2/tests.py
@@ -1,53 +1,53 @@
"""Built-in template tests used with the ``is`` operator."""
-import operator
+import operator
import typing as t
from collections import abc
from numbers import Number
-
+
from .runtime import Undefined
from .utils import pass_environment
if t.TYPE_CHECKING:
from .environment import Environment
-
-
+
+
def test_odd(value: int) -> bool:
- """Return true if the variable is odd."""
- return value % 2 == 1
-
-
+ """Return true if the variable is odd."""
+ return value % 2 == 1
+
+
def test_even(value: int) -> bool:
- """Return true if the variable is even."""
- return value % 2 == 0
-
-
+ """Return true if the variable is even."""
+ return value % 2 == 0
+
+
def test_divisibleby(value: int, num: int) -> bool:
- """Check if a variable is divisible by a number."""
- return value % num == 0
-
-
+ """Check if a variable is divisible by a number."""
+ return value % num == 0
+
+
def test_defined(value: t.Any) -> bool:
- """Return true if the variable is defined:
-
- .. sourcecode:: jinja
-
- {% if variable is defined %}
- value of variable: {{ variable }}
- {% else %}
- variable is not defined
- {% endif %}
-
- See the :func:`default` filter for a simple way to set undefined
- variables.
- """
- return not isinstance(value, Undefined)
-
-
+ """Return true if the variable is defined:
+
+ .. sourcecode:: jinja
+
+ {% if variable is defined %}
+ value of variable: {{ variable }}
+ {% else %}
+ variable is not defined
+ {% endif %}
+
+ See the :func:`default` filter for a simple way to set undefined
+ variables.
+ """
+ return not isinstance(value, Undefined)
+
+
def test_undefined(value: t.Any) -> bool:
- """Like :func:`defined` but the other way round."""
- return isinstance(value, Undefined)
-
-
+ """Like :func:`defined` but the other way round."""
+ return isinstance(value, Undefined)
+
+
@pass_environment
def test_filter(env: "Environment", value: str) -> bool:
"""Check if a filter exists by name. Useful if a filter may be
@@ -89,10 +89,10 @@ def test_test(env: "Environment", value: str) -> bool:
def test_none(value: t.Any) -> bool:
- """Return true if the variable is none."""
- return value is None
-
-
+ """Return true if the variable is none."""
+ return value is None
+
+
def test_boolean(value: t.Any) -> bool:
"""Return true if the object is a boolean value.
@@ -136,83 +136,83 @@ def test_float(value: t.Any) -> bool:
def test_lower(value: str) -> bool:
- """Return true if the variable is lowercased."""
+ """Return true if the variable is lowercased."""
return str(value).islower()
-
-
+
+
def test_upper(value: str) -> bool:
- """Return true if the variable is uppercased."""
+ """Return true if the variable is uppercased."""
return str(value).isupper()
-
-
+
+
def test_string(value: t.Any) -> bool:
- """Return true if the object is a string."""
+ """Return true if the object is a string."""
return isinstance(value, str)
-
-
+
+
def test_mapping(value: t.Any) -> bool:
- """Return true if the object is a mapping (dict etc.).
-
- .. versionadded:: 2.6
- """
+ """Return true if the object is a mapping (dict etc.).
+
+ .. versionadded:: 2.6
+ """
return isinstance(value, abc.Mapping)
-
-
+
+
def test_number(value: t.Any) -> bool:
- """Return true if the variable is a number."""
+ """Return true if the variable is a number."""
return isinstance(value, Number)
-
-
+
+
def test_sequence(value: t.Any) -> bool:
- """Return true if the variable is a sequence. Sequences are variables
- that are iterable.
- """
- try:
- len(value)
- value.__getitem__
+ """Return true if the variable is a sequence. Sequences are variables
+ that are iterable.
+ """
+ try:
+ len(value)
+ value.__getitem__
except Exception:
- return False
-
- return True
-
+ return False
+ return True
+
+
def test_sameas(value: t.Any, other: t.Any) -> bool:
- """Check if an object points to the same memory address than another
- object:
-
- .. sourcecode:: jinja
-
- {% if foo.attribute is sameas false %}
- the foo attribute really is the `False` singleton
- {% endif %}
- """
- return value is other
-
-
+ """Check if an object points to the same memory address than another
+ object:
+
+ .. sourcecode:: jinja
+
+ {% if foo.attribute is sameas false %}
+ the foo attribute really is the `False` singleton
+ {% endif %}
+ """
+ return value is other
+
+
def test_iterable(value: t.Any) -> bool:
- """Check if it's possible to iterate over an object."""
- try:
- iter(value)
- except TypeError:
- return False
-
- return True
-
-
+ """Check if it's possible to iterate over an object."""
+ try:
+ iter(value)
+ except TypeError:
+ return False
+
+ return True
+
+
def test_escaped(value: t.Any) -> bool:
- """Check if the value is escaped."""
+ """Check if the value is escaped."""
return hasattr(value, "__html__")
-
-
+
+
def test_in(value: t.Any, seq: t.Container) -> bool:
- """Check if value is in seq.
-
- .. versionadded:: 2.10
- """
- return value in seq
-
-
-TESTS = {
+ """Check if value is in seq.
+
+ .. versionadded:: 2.10
+ """
+ return value in seq
+
+
+TESTS = {
"odd": test_odd,
"even": test_even,
"divisibleby": test_divisibleby,
@@ -252,4 +252,4 @@ TESTS = {
"lessthan": operator.lt,
"<=": operator.le,
"le": operator.le,
-}
+}
diff --git a/contrib/python/Jinja2/py3/jinja2/utils.py b/contrib/python/Jinja2/py3/jinja2/utils.py
index 567185f41f..261b118583 100644
--- a/contrib/python/Jinja2/py3/jinja2/utils.py
+++ b/contrib/python/Jinja2/py3/jinja2/utils.py
@@ -1,54 +1,54 @@
import enum
import json
import os
-import re
+import re
import typing as t
import warnings
from collections import abc
-from collections import deque
+from collections import deque
from random import choice
from random import randrange
-from threading import Lock
+from threading import Lock
from types import CodeType
from urllib.parse import quote_from_bytes
-
+
import markupsafe
-
+
if t.TYPE_CHECKING:
import typing_extensions as te
F = t.TypeVar("F", bound=t.Callable[..., t.Any])
-# special singleton representing missing values for the runtime
+# special singleton representing missing values for the runtime
missing: t.Any = type("MissingType", (), {"__repr__": lambda x: "missing"})()
-
+
internal_code: t.MutableSet[CodeType] = set()
-
+
concat = "".join
-
-
+
+
def pass_context(f: F) -> F:
"""Pass the :class:`~jinja2.runtime.Context` as the first argument
to the decorated function when called while rendering a template.
-
+
Can be used on functions, filters, and tests.
-
+
If only ``Context.eval_context`` is needed, use
:func:`pass_eval_context`. If only ``Context.environment`` is
needed, use :func:`pass_environment`.
.. versionadded:: 3.0.0
Replaces ``contextfunction`` and ``contextfilter``.
- """
+ """
f.jinja_pass_arg = _PassArg.context # type: ignore
- return f
-
-
+ return f
+
+
def pass_eval_context(f: F) -> F:
"""Pass the :class:`~jinja2.nodes.EvalContext` as the first argument
to the decorated function when called while rendering a template.
See :ref:`eval-context`.
-
+
Can be used on functions, filters, and tests.
If only ``EvalContext.environment`` is needed, use
@@ -56,11 +56,11 @@ def pass_eval_context(f: F) -> F:
.. versionadded:: 3.0.0
Replaces ``evalcontextfunction`` and ``evalcontextfilter``.
- """
+ """
f.jinja_pass_arg = _PassArg.eval_context # type: ignore
- return f
-
-
+ return f
+
+
def pass_environment(f: F) -> F:
"""Pass the :class:`~jinja2.Environment` as the first argument to
the decorated function when called while rendering a template.
@@ -69,11 +69,11 @@ def pass_environment(f: F) -> F:
.. versionadded:: 3.0.0
Replaces ``environmentfunction`` and ``environmentfilter``.
- """
+ """
f.jinja_pass_arg = _PassArg.environment # type: ignore
- return f
-
-
+ return f
+
+
class _PassArg(enum.Enum):
context = enum.auto()
eval_context = enum.auto()
@@ -153,98 +153,98 @@ def environmentfunction(f: F) -> F:
def internalcode(f: F) -> F:
- """Marks the function as internally used"""
- internal_code.add(f.__code__)
- return f
-
-
+ """Marks the function as internally used"""
+ internal_code.add(f.__code__)
+ return f
+
+
def is_undefined(obj: t.Any) -> bool:
- """Check if the object passed is undefined. This does nothing more than
- performing an instance check against :class:`Undefined` but looks nicer.
- This can be used for custom filters or tests that want to react to
- undefined variables. For example a custom default filter can look like
- this::
-
- def default(var, default=''):
- if is_undefined(var):
- return default
- return var
- """
+ """Check if the object passed is undefined. This does nothing more than
+ performing an instance check against :class:`Undefined` but looks nicer.
+ This can be used for custom filters or tests that want to react to
+ undefined variables. For example a custom default filter can look like
+ this::
+
+ def default(var, default=''):
+ if is_undefined(var):
+ return default
+ return var
+ """
from .runtime import Undefined
- return isinstance(obj, Undefined)
-
-
+ return isinstance(obj, Undefined)
+
+
def consume(iterable: t.Iterable[t.Any]) -> None:
- """Consumes an iterable without doing anything with it."""
+ """Consumes an iterable without doing anything with it."""
for _ in iterable:
- pass
-
-
+ pass
+
+
def clear_caches() -> None:
"""Jinja keeps internal caches for environments and lexers. These are
used so that Jinja doesn't have to recreate environments and lexers all
- the time. Normally you don't have to care about that but if you are
- measuring memory consumption you may want to clean the caches.
- """
+ the time. Normally you don't have to care about that but if you are
+ measuring memory consumption you may want to clean the caches.
+ """
from .environment import get_spontaneous_environment
from .lexer import _lexer_cache
get_spontaneous_environment.cache_clear()
- _lexer_cache.clear()
-
-
+ _lexer_cache.clear()
+
+
def import_string(import_name: str, silent: bool = False) -> t.Any:
- """Imports an object based on a string. This is useful if you want to
- use import paths as endpoints or something similar. An import path can
- be specified either in dotted notation (``xml.sax.saxutils.escape``)
- or with a colon as object delimiter (``xml.sax.saxutils:escape``).
-
- If the `silent` is True the return value will be `None` if the import
- fails.
-
- :return: imported object
- """
- try:
+ """Imports an object based on a string. This is useful if you want to
+ use import paths as endpoints or something similar. An import path can
+ be specified either in dotted notation (``xml.sax.saxutils.escape``)
+ or with a colon as object delimiter (``xml.sax.saxutils:escape``).
+
+ If the `silent` is True the return value will be `None` if the import
+ fails.
+
+ :return: imported object
+ """
+ try:
if ":" in import_name:
module, obj = import_name.split(":", 1)
elif "." in import_name:
module, _, obj = import_name.rpartition(".")
- else:
- return __import__(import_name)
- return getattr(__import__(module, None, None, [obj]), obj)
- except (ImportError, AttributeError):
- if not silent:
- raise
-
-
+ else:
+ return __import__(import_name)
+ return getattr(__import__(module, None, None, [obj]), obj)
+ except (ImportError, AttributeError):
+ if not silent:
+ raise
+
+
def open_if_exists(filename: str, mode: str = "rb") -> t.Optional[t.IO]:
- """Returns a file descriptor for the filename if that file exists,
+ """Returns a file descriptor for the filename if that file exists,
otherwise ``None``.
- """
+ """
if not os.path.isfile(filename):
return None
-
+
return open(filename, mode)
-
+
def object_type_repr(obj: t.Any) -> str:
- """Returns the name of the object's type. For some recognized
- singletons the name of the object is returned instead. (For
- example for `None` and `Ellipsis`).
- """
- if obj is None:
+ """Returns the name of the object's type. For some recognized
+ singletons the name of the object is returned instead. (For
+ example for `None` and `Ellipsis`).
+ """
+ if obj is None:
return "None"
- elif obj is Ellipsis:
+ elif obj is Ellipsis:
return "Ellipsis"
cls = type(obj)
if cls.__module__ == "builtins":
return f"{cls.__name__} object"
-
+
return f"{cls.__module__}.{cls.__name__} object"
-
+
def pformat(obj: t.Any) -> str:
"""Format an object using :func:`pprint.pformat`."""
@@ -252,7 +252,7 @@ def pformat(obj: t.Any) -> str:
return pformat(obj)
-
+
_http_re = re.compile(
r"""
^
@@ -282,8 +282,8 @@ _http_re = re.compile(
re.IGNORECASE | re.VERBOSE,
)
_email_re = re.compile(r"^\S+@\w[\w.-]*\.\w+$")
-
-
+
+
def urlize(
text: str,
trim_url_limit: t.Optional[int] = None,
@@ -292,11 +292,11 @@ def urlize(
extra_schemes: t.Optional[t.Iterable[str]] = None,
) -> str:
"""Convert URLs in text into clickable links.
-
+
This may not recognize links in some situations. Usually, a more
comprehensive formatter, such as a Markdown library, is a better
choice.
-
+
Works on ``http://``, ``https://``, ``www.``, ``mailto:``, and email
addresses. Links with trailing punctuation (periods, commas, closing
parentheses) and leading punctuation (opening parentheses) are
@@ -321,9 +321,9 @@ def urlize(
The parsing rules were updated. Recognize email addresses with
or without the ``mailto:`` scheme. Validate IP addresses. Ignore
parentheses and brackets in more cases.
- """
+ """
if trim_url_limit is not None:
-
+
def trim_url(x: str) -> str:
if len(x) > trim_url_limit: # type: ignore
return f"{x[:trim_url_limit]}..."
@@ -339,11 +339,11 @@ def urlize(
rel_attr = f' rel="{markupsafe.escape(rel)}"' if rel else ""
target_attr = f' target="{markupsafe.escape(target)}"' if target else ""
- for i, word in enumerate(words):
+ for i, word in enumerate(words):
head, middle, tail = "", word, ""
match = re.match(r"^([(<]|&lt;)+", middle)
- if match:
+ if match:
head = match.group()
middle = middle[match.end() :]
@@ -401,51 +401,51 @@ def urlize(
middle = f'<a href="{middle}"{rel_attr}{target_attr}>{middle}</a>'
words[i] = f"{head}{middle}{tail}"
-
+
return "".join(words)
-
+
def generate_lorem_ipsum(
n: int = 5, html: bool = True, min: int = 20, max: int = 100
) -> str:
- """Generate some lorem ipsum for the template."""
+ """Generate some lorem ipsum for the template."""
from .constants import LOREM_IPSUM_WORDS
- words = LOREM_IPSUM_WORDS.split()
- result = []
-
- for _ in range(n):
- next_capitalized = True
- last_comma = last_fullstop = 0
- word = None
- last = None
- p = []
-
- # each paragraph contains out of 20 to 100 words.
- for idx, _ in enumerate(range(randrange(min, max))):
- while True:
- word = choice(words)
- if word != last:
- last = word
- break
- if next_capitalized:
- word = word.capitalize()
- next_capitalized = False
- # add commas
- if idx - randrange(3, 8) > last_comma:
- last_comma = idx
- last_fullstop += 2
+ words = LOREM_IPSUM_WORDS.split()
+ result = []
+
+ for _ in range(n):
+ next_capitalized = True
+ last_comma = last_fullstop = 0
+ word = None
+ last = None
+ p = []
+
+ # each paragraph contains out of 20 to 100 words.
+ for idx, _ in enumerate(range(randrange(min, max))):
+ while True:
+ word = choice(words)
+ if word != last:
+ last = word
+ break
+ if next_capitalized:
+ word = word.capitalize()
+ next_capitalized = False
+ # add commas
+ if idx - randrange(3, 8) > last_comma:
+ last_comma = idx
+ last_fullstop += 2
word += ","
- # add end of sentences
- if idx - randrange(10, 20) > last_fullstop:
- last_comma = last_fullstop = idx
+ # add end of sentences
+ if idx - randrange(10, 20) > last_fullstop:
+ last_comma = last_fullstop = idx
word += "."
- next_capitalized = True
- p.append(word)
-
- # ensure that the paragraph ends with a dot.
+ next_capitalized = True
+ p.append(word)
+
+ # ensure that the paragraph ends with a dot.
p_str = " ".join(p)
-
+
if p_str.endswith(","):
p_str = p_str[:-1] + "."
elif not p_str.endswith("."):
@@ -453,36 +453,36 @@ def generate_lorem_ipsum(
result.append(p_str)
- if not html:
+ if not html:
return "\n\n".join(result)
return markupsafe.Markup(
"\n".join(f"<p>{markupsafe.escape(x)}</p>" for x in result)
)
-
-
+
+
def url_quote(obj: t.Any, charset: str = "utf-8", for_qs: bool = False) -> str:
"""Quote a string for use in a URL using the given charset.
-
+
:param obj: String or bytes to quote. Other types are converted to
string then encoded to bytes using the given charset.
:param charset: Encode text to bytes using this charset.
:param for_qs: Quote "/" and use "+" for spaces.
- """
+ """
if not isinstance(obj, bytes):
if not isinstance(obj, str):
obj = str(obj)
- obj = obj.encode(charset)
+ obj = obj.encode(charset)
safe = b"" if for_qs else b"/"
rv = quote_from_bytes(obj, safe)
- if for_qs:
+ if for_qs:
rv = rv.replace("%20", "+")
- return rv
-
-
+ return rv
+
+
def unicode_urlencode(obj: t.Any, charset: str = "utf-8", for_qs: bool = False) -> str:
import warnings
@@ -497,221 +497,221 @@ def unicode_urlencode(obj: t.Any, charset: str = "utf-8", for_qs: bool = False)
@abc.MutableMapping.register
class LRUCache:
- """A simple LRU Cache implementation."""
-
- # this is fast for small capacities (something below 1000) but doesn't
- # scale. But as long as it's only used as storage for templates this
- # won't do any harm.
-
+ """A simple LRU Cache implementation."""
+
+ # this is fast for small capacities (something below 1000) but doesn't
+ # scale. But as long as it's only used as storage for templates this
+ # won't do any harm.
+
def __init__(self, capacity: int) -> None:
- self.capacity = capacity
+ self.capacity = capacity
self._mapping: t.Dict[t.Any, t.Any] = {}
self._queue: "te.Deque[t.Any]" = deque()
- self._postinit()
-
+ self._postinit()
+
def _postinit(self) -> None:
- # alias all queue methods for faster lookup
- self._popleft = self._queue.popleft
- self._pop = self._queue.pop
- self._remove = self._queue.remove
- self._wlock = Lock()
- self._append = self._queue.append
-
+ # alias all queue methods for faster lookup
+ self._popleft = self._queue.popleft
+ self._pop = self._queue.pop
+ self._remove = self._queue.remove
+ self._wlock = Lock()
+ self._append = self._queue.append
+
def __getstate__(self) -> t.Mapping[str, t.Any]:
- return {
+ return {
"capacity": self.capacity,
"_mapping": self._mapping,
"_queue": self._queue,
- }
-
+ }
+
def __setstate__(self, d: t.Mapping[str, t.Any]) -> None:
- self.__dict__.update(d)
- self._postinit()
-
+ self.__dict__.update(d)
+ self._postinit()
+
def __getnewargs__(self) -> t.Tuple:
- return (self.capacity,)
-
+ return (self.capacity,)
+
def copy(self) -> "LRUCache":
- """Return a shallow copy of the instance."""
- rv = self.__class__(self.capacity)
- rv._mapping.update(self._mapping)
+ """Return a shallow copy of the instance."""
+ rv = self.__class__(self.capacity)
+ rv._mapping.update(self._mapping)
rv._queue.extend(self._queue)
- return rv
-
+ return rv
+
def get(self, key: t.Any, default: t.Any = None) -> t.Any:
- """Return an item from the cache dict or `default`"""
- try:
- return self[key]
- except KeyError:
- return default
-
+ """Return an item from the cache dict or `default`"""
+ try:
+ return self[key]
+ except KeyError:
+ return default
+
def setdefault(self, key: t.Any, default: t.Any = None) -> t.Any:
- """Set `default` if the key is not in the cache otherwise
- leave unchanged. Return the value of this key.
- """
- try:
+ """Set `default` if the key is not in the cache otherwise
+ leave unchanged. Return the value of this key.
+ """
+ try:
return self[key]
except KeyError:
self[key] = default
return default
-
+
def clear(self) -> None:
- """Clear the cache."""
+ """Clear the cache."""
with self._wlock:
- self._mapping.clear()
- self._queue.clear()
-
+ self._mapping.clear()
+ self._queue.clear()
+
def __contains__(self, key: t.Any) -> bool:
- """Check if a key exists in this cache."""
- return key in self._mapping
-
+ """Check if a key exists in this cache."""
+ return key in self._mapping
+
def __len__(self) -> int:
- """Return the current size of the cache."""
- return len(self._mapping)
-
+ """Return the current size of the cache."""
+ return len(self._mapping)
+
def __repr__(self) -> str:
return f"<{type(self).__name__} {self._mapping!r}>"
-
+
def __getitem__(self, key: t.Any) -> t.Any:
- """Get an item from the cache. Moves the item up so that it has the
- highest priority then.
-
- Raise a `KeyError` if it does not exist.
- """
+ """Get an item from the cache. Moves the item up so that it has the
+ highest priority then.
+
+ Raise a `KeyError` if it does not exist.
+ """
with self._wlock:
- rv = self._mapping[key]
+ rv = self._mapping[key]
- if self._queue[-1] != key:
- try:
- self._remove(key)
- except ValueError:
- # if something removed the key from the container
- # when we read, ignore the ValueError that we would
- # get otherwise.
- pass
+ if self._queue[-1] != key:
+ try:
+ self._remove(key)
+ except ValueError:
+ # if something removed the key from the container
+ # when we read, ignore the ValueError that we would
+ # get otherwise.
+ pass
- self._append(key)
-
- return rv
+ self._append(key)
+ return rv
+
def __setitem__(self, key: t.Any, value: t.Any) -> None:
- """Sets the value for an item. Moves the item up so that it
- has the highest priority then.
- """
+ """Sets the value for an item. Moves the item up so that it
+ has the highest priority then.
+ """
with self._wlock:
- if key in self._mapping:
- self._remove(key)
- elif len(self._mapping) == self.capacity:
- del self._mapping[self._popleft()]
-
- self._append(key)
- self._mapping[key] = value
-
+ if key in self._mapping:
+ self._remove(key)
+ elif len(self._mapping) == self.capacity:
+ del self._mapping[self._popleft()]
+
+ self._append(key)
+ self._mapping[key] = value
+
def __delitem__(self, key: t.Any) -> None:
- """Remove an item from the cache dict.
- Raise a `KeyError` if it does not exist.
- """
+ """Remove an item from the cache dict.
+ Raise a `KeyError` if it does not exist.
+ """
with self._wlock:
- del self._mapping[key]
-
- try:
- self._remove(key)
- except ValueError:
- pass
+ del self._mapping[key]
+ try:
+ self._remove(key)
+ except ValueError:
+ pass
+
def items(self) -> t.Iterable[t.Tuple[t.Any, t.Any]]:
- """Return a list of items."""
- result = [(key, self._mapping[key]) for key in list(self._queue)]
- result.reverse()
- return result
-
+ """Return a list of items."""
+ result = [(key, self._mapping[key]) for key in list(self._queue)]
+ result.reverse()
+ return result
+
def values(self) -> t.Iterable[t.Any]:
- """Return a list of all values."""
- return [x[1] for x in self.items()]
-
+ """Return a list of all values."""
+ return [x[1] for x in self.items()]
+
def keys(self) -> t.Iterable[t.Any]:
- """Return a list of all keys ordered by most recent usage."""
- return list(self)
-
+ """Return a list of all keys ordered by most recent usage."""
+ return list(self)
+
def __iter__(self) -> t.Iterator[t.Any]:
- return reversed(tuple(self._queue))
-
+ return reversed(tuple(self._queue))
+
def __reversed__(self) -> t.Iterator[t.Any]:
"""Iterate over the keys in the cache dict, oldest items
- coming first.
- """
- return iter(tuple(self._queue))
-
- __copy__ = copy
-
-
+ coming first.
+ """
+ return iter(tuple(self._queue))
+
+ __copy__ = copy
+
+
def select_autoescape(
enabled_extensions: t.Collection[str] = ("html", "htm", "xml"),
disabled_extensions: t.Collection[str] = (),
default_for_string: bool = True,
default: bool = False,
) -> t.Callable[[t.Optional[str]], bool]:
- """Intelligently sets the initial value of autoescaping based on the
- filename of the template. This is the recommended way to configure
- autoescaping if you do not want to write a custom function yourself.
-
- If you want to enable it for all templates created from strings or
- for all templates with `.html` and `.xml` extensions::
-
- from jinja2 import Environment, select_autoescape
- env = Environment(autoescape=select_autoescape(
- enabled_extensions=('html', 'xml'),
- default_for_string=True,
- ))
-
- Example configuration to turn it on at all times except if the template
- ends with `.txt`::
-
- from jinja2 import Environment, select_autoescape
- env = Environment(autoescape=select_autoescape(
- disabled_extensions=('txt',),
- default_for_string=True,
- default=True,
- ))
-
- The `enabled_extensions` is an iterable of all the extensions that
- autoescaping should be enabled for. Likewise `disabled_extensions` is
- a list of all templates it should be disabled for. If a template is
- loaded from a string then the default from `default_for_string` is used.
- If nothing matches then the initial value of autoescaping is set to the
- value of `default`.
-
- For security reasons this function operates case insensitive.
-
- .. versionadded:: 2.9
- """
+ """Intelligently sets the initial value of autoescaping based on the
+ filename of the template. This is the recommended way to configure
+ autoescaping if you do not want to write a custom function yourself.
+
+ If you want to enable it for all templates created from strings or
+ for all templates with `.html` and `.xml` extensions::
+
+ from jinja2 import Environment, select_autoescape
+ env = Environment(autoescape=select_autoescape(
+ enabled_extensions=('html', 'xml'),
+ default_for_string=True,
+ ))
+
+ Example configuration to turn it on at all times except if the template
+ ends with `.txt`::
+
+ from jinja2 import Environment, select_autoescape
+ env = Environment(autoescape=select_autoescape(
+ disabled_extensions=('txt',),
+ default_for_string=True,
+ default=True,
+ ))
+
+ The `enabled_extensions` is an iterable of all the extensions that
+ autoescaping should be enabled for. Likewise `disabled_extensions` is
+ a list of all templates it should be disabled for. If a template is
+ loaded from a string then the default from `default_for_string` is used.
+ If nothing matches then the initial value of autoescaping is set to the
+ value of `default`.
+
+ For security reasons this function operates case insensitive.
+
+ .. versionadded:: 2.9
+ """
enabled_patterns = tuple(f".{x.lstrip('.').lower()}" for x in enabled_extensions)
disabled_patterns = tuple(f".{x.lstrip('.').lower()}" for x in disabled_extensions)
def autoescape(template_name: t.Optional[str]) -> bool:
- if template_name is None:
- return default_for_string
- template_name = template_name.lower()
- if template_name.endswith(enabled_patterns):
- return True
- if template_name.endswith(disabled_patterns):
- return False
- return default
-
- return autoescape
-
-
+ if template_name is None:
+ return default_for_string
+ template_name = template_name.lower()
+ if template_name.endswith(enabled_patterns):
+ return True
+ if template_name.endswith(disabled_patterns):
+ return False
+ return default
+
+ return autoescape
+
+
def htmlsafe_json_dumps(
obj: t.Any, dumps: t.Optional[t.Callable[..., str]] = None, **kwargs: t.Any
) -> markupsafe.Markup:
"""Serialize an object to a string of JSON with :func:`json.dumps`,
then replace HTML-unsafe characters with Unicode escapes and mark
the result safe with :class:`~markupsafe.Markup`.
-
+
This is available in templates as the ``|tojson`` filter.
-
+
The following characters are escaped: ``<``, ``>``, ``&``, ``'``.
-
+
The returned string is safe to render in HTML documents and
``<script>`` tags. The exception is in HTML attributes that are
double quoted; either use single quotes or the ``|forceescape``
@@ -728,7 +728,7 @@ def htmlsafe_json_dumps(
The ``dumper`` parameter is renamed to ``dumps``.
.. versionadded:: 2.9
- """
+ """
if dumps is None:
dumps = json.dumps
@@ -739,12 +739,12 @@ def htmlsafe_json_dumps(
.replace("&", "\\u0026")
.replace("'", "\\u0027")
)
-
-
+
+
class Cycler:
"""Cycle through values by yield them one at a time, then restarting
once the end is reached. Available as ``cycler`` in templates.
-
+
Similar to ``loop.cycle``, but can be used outside loops or across
multiple loops. For example, render a list of folders and files in a
list, alternating giving them "odd" and "even" classes.
@@ -768,71 +768,71 @@ class Cycler:
"""
def __init__(self, *items: t.Any) -> None:
- if not items:
+ if not items:
raise RuntimeError("at least one item has to be provided")
- self.items = items
+ self.items = items
self.pos = 0
-
+
def reset(self) -> None:
"""Resets the current item to the first item."""
- self.pos = 0
-
- @property
+ self.pos = 0
+
+ @property
def current(self) -> t.Any:
"""Return the current item. Equivalent to the item that will be
returned next time :meth:`next` is called.
"""
- return self.items[self.pos]
-
+ return self.items[self.pos]
+
def next(self) -> t.Any:
"""Return the current item, then advance :attr:`current` to the
next item.
"""
- rv = self.current
- self.pos = (self.pos + 1) % len(self.items)
- return rv
-
- __next__ = next
-
-
+ rv = self.current
+ self.pos = (self.pos + 1) % len(self.items)
+ return rv
+
+ __next__ = next
+
+
class Joiner:
- """A joining helper for templates."""
-
+ """A joining helper for templates."""
+
def __init__(self, sep: str = ", ") -> None:
- self.sep = sep
- self.used = False
-
+ self.sep = sep
+ self.used = False
+
def __call__(self) -> str:
- if not self.used:
- self.used = True
+ if not self.used:
+ self.used = True
return ""
- return self.sep
-
-
+ return self.sep
+
+
class Namespace:
- """A namespace object that can hold arbitrary attributes. It may be
+ """A namespace object that can hold arbitrary attributes. It may be
initialized from a dictionary or with keyword arguments."""
-
+
def __init__(*args: t.Any, **kwargs: t.Any) -> None: # noqa: B902
- self, args = args[0], args[1:]
- self.__attrs = dict(*args, **kwargs)
-
+ self, args = args[0], args[1:]
+ self.__attrs = dict(*args, **kwargs)
+
def __getattribute__(self, name: str) -> t.Any:
# __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]
- except KeyError:
+ return object.__getattribute__(self, name)
+ try:
+ return self.__attrs[name]
+ except KeyError:
raise AttributeError(name) from None
-
+
def __setitem__(self, name: str, value: t.Any) -> None:
- self.__attrs[name] = value
-
+ self.__attrs[name] = value
+
def __repr__(self) -> str:
return f"<Namespace {self.__attrs!r}>"
-
-
+
+
class Markup(markupsafe.Markup):
def __new__(cls, base="", encoding=None, errors="strict"): # type: ignore
warnings.warn(
@@ -842,8 +842,8 @@ class Markup(markupsafe.Markup):
stacklevel=2,
)
return super().__new__(cls, base, encoding, errors)
-
-
+
+
def escape(s: t.Any) -> str:
warnings.warn(
"'jinja2.escape' is deprecated and will be removed in Jinja"
diff --git a/contrib/python/Jinja2/py3/jinja2/visitor.py b/contrib/python/Jinja2/py3/jinja2/visitor.py
index b150e578a8..3dd61cedd5 100644
--- a/contrib/python/Jinja2/py3/jinja2/visitor.py
+++ b/contrib/python/Jinja2/py3/jinja2/visitor.py
@@ -1,92 +1,92 @@
"""API for traversing the AST nodes. Implemented by the compiler and
meta introspection.
-"""
+"""
import typing as t
from .nodes import Node
-
+
if t.TYPE_CHECKING:
import typing_extensions as te
-
+
class VisitCallable(te.Protocol):
def __call__(self, node: Node, *args: t.Any, **kwargs: t.Any) -> t.Any:
...
class NodeVisitor:
- """Walks the abstract syntax tree and call visitor functions for every
- node found. The visitor functions may return values which will be
- forwarded by the `visit` method.
-
- Per default the visitor functions for the nodes are ``'visit_'`` +
- class name of the node. So a `TryFinally` node visit function would
- be `visit_TryFinally`. This behavior can be changed by overriding
- the `get_visitor` function. If no visitor function exists for a node
- (return value `None`) the `generic_visit` visitor is used instead.
- """
-
+ """Walks the abstract syntax tree and call visitor functions for every
+ node found. The visitor functions may return values which will be
+ forwarded by the `visit` method.
+
+ Per default the visitor functions for the nodes are ``'visit_'`` +
+ class name of the node. So a `TryFinally` node visit function would
+ be `visit_TryFinally`. This behavior can be changed by overriding
+ the `get_visitor` function. If no visitor function exists for a node
+ (return value `None`) the `generic_visit` visitor is used instead.
+ """
+
def get_visitor(self, node: Node) -> "t.Optional[VisitCallable]":
- """Return the visitor function for this node or `None` if no visitor
- exists for this node. In that case the generic visit function is
- used instead.
- """
+ """Return the visitor function for this node or `None` if no visitor
+ exists for this node. In that case the generic visit function is
+ used instead.
+ """
return getattr(self, f"visit_{type(node).__name__}", None) # type: ignore
-
+
def visit(self, node: Node, *args: t.Any, **kwargs: t.Any) -> t.Any:
- """Visit a node."""
- f = self.get_visitor(node)
-
- if f is not None:
- return f(node, *args, **kwargs)
+ """Visit a node."""
+ f = self.get_visitor(node)
- return self.generic_visit(node, *args, **kwargs)
+ if f is not None:
+ return f(node, *args, **kwargs)
+ return self.generic_visit(node, *args, **kwargs)
+
def generic_visit(self, node: Node, *args: t.Any, **kwargs: t.Any) -> t.Any:
- """Called if no explicit visitor function exists for a node."""
- for node in node.iter_child_nodes():
- self.visit(node, *args, **kwargs)
-
-
-class NodeTransformer(NodeVisitor):
- """Walks the abstract syntax tree and allows modifications of nodes.
-
- The `NodeTransformer` will walk the AST and use the return value of the
- visitor functions to replace or remove the old node. If the return
- value of the visitor function is `None` the node will be removed
- from the previous location otherwise it's replaced with the return
- value. The return value may be the original node in which case no
- replacement takes place.
- """
-
+ """Called if no explicit visitor function exists for a node."""
+ for node in node.iter_child_nodes():
+ self.visit(node, *args, **kwargs)
+
+
+class NodeTransformer(NodeVisitor):
+ """Walks the abstract syntax tree and allows modifications of nodes.
+
+ The `NodeTransformer` will walk the AST and use the return value of the
+ visitor functions to replace or remove the old node. If the return
+ value of the visitor function is `None` the node will be removed
+ from the previous location otherwise it's replaced with the return
+ value. The return value may be the original node in which case no
+ replacement takes place.
+ """
+
def generic_visit(self, node: Node, *args: t.Any, **kwargs: t.Any) -> Node:
- for field, old_value in node.iter_fields():
- if isinstance(old_value, list):
- new_values = []
- for value in old_value:
- if isinstance(value, Node):
- value = self.visit(value, *args, **kwargs)
- if value is None:
- continue
- elif not isinstance(value, Node):
- new_values.extend(value)
- continue
- new_values.append(value)
- old_value[:] = new_values
- elif isinstance(old_value, Node):
- new_node = self.visit(old_value, *args, **kwargs)
- if new_node is None:
- delattr(node, field)
- else:
- setattr(node, field, new_node)
- return node
-
+ for field, old_value in node.iter_fields():
+ if isinstance(old_value, list):
+ new_values = []
+ for value in old_value:
+ if isinstance(value, Node):
+ value = self.visit(value, *args, **kwargs)
+ if value is None:
+ continue
+ elif not isinstance(value, Node):
+ new_values.extend(value)
+ continue
+ new_values.append(value)
+ old_value[:] = new_values
+ elif isinstance(old_value, Node):
+ new_node = self.visit(old_value, *args, **kwargs)
+ if new_node is None:
+ delattr(node, field)
+ else:
+ setattr(node, field, new_node)
+ return node
+
def visit_list(self, node: Node, *args: t.Any, **kwargs: t.Any) -> t.List[Node]:
- """As transformers may return lists in some places this method
- can be used to enforce a list as return value.
- """
- rv = self.visit(node, *args, **kwargs)
+ """As transformers may return lists in some places this method
+ can be used to enforce a list as return value.
+ """
+ rv = self.visit(node, *args, **kwargs)
- if not isinstance(rv, list):
+ if not isinstance(rv, list):
return [rv]
- return rv
+ return rv
diff --git a/contrib/python/Jinja2/py3/tests/conftest.py b/contrib/python/Jinja2/py3/tests/conftest.py
index 218c3c77cf..72df42a6a6 100644
--- a/contrib/python/Jinja2/py3/tests/conftest.py
+++ b/contrib/python/Jinja2/py3/tests/conftest.py
@@ -1,50 +1,50 @@
from pathlib import Path
-
-import pytest
-
-from jinja2 import loaders
+
+import pytest
+
+from jinja2 import loaders
from jinja2.environment import Environment
-
-
-@pytest.fixture
-def env():
+
+
+@pytest.fixture
+def env():
"""returns a new environment."""
- return Environment()
-
-
-@pytest.fixture
-def dict_loader():
+ return Environment()
+
+
+@pytest.fixture
+def dict_loader():
"""returns DictLoader"""
return loaders.DictLoader({"justdict.html": "FOO"})
-
-
-@pytest.fixture
-def package_loader():
+
+
+@pytest.fixture
+def package_loader():
"""returns PackageLoader initialized from templates"""
return loaders.PackageLoader("res", "templates")
-
-
-@pytest.fixture
-def filesystem_loader():
+
+
+@pytest.fixture
+def filesystem_loader():
"""returns FileSystemLoader initialized to res/templates directory"""
import yatest.common
here = Path(yatest.common.test_source_path())
return loaders.FileSystemLoader(here / "res" / "templates")
-
-
-@pytest.fixture
-def function_loader():
+
+
+@pytest.fixture
+def function_loader():
"""returns a FunctionLoader"""
return loaders.FunctionLoader({"justfunction.html": "FOO"}.get)
-
-
-@pytest.fixture
-def choice_loader(dict_loader, package_loader):
+
+
+@pytest.fixture
+def choice_loader(dict_loader, package_loader):
"""returns a ChoiceLoader"""
- return loaders.ChoiceLoader([dict_loader, package_loader])
-
-
-@pytest.fixture
-def prefix_loader(filesystem_loader, dict_loader):
+ return loaders.ChoiceLoader([dict_loader, package_loader])
+
+
+@pytest.fixture
+def prefix_loader(filesystem_loader, dict_loader):
"""returns a PrefixLoader"""
return loaders.PrefixLoader({"a": filesystem_loader, "b": dict_loader})
diff --git a/contrib/python/Jinja2/py3/tests/res/templates/broken.html b/contrib/python/Jinja2/py3/tests/res/templates/broken.html
index 77669fae57..b38d7bb927 100644
--- a/contrib/python/Jinja2/py3/tests/res/templates/broken.html
+++ b/contrib/python/Jinja2/py3/tests/res/templates/broken.html
@@ -1,3 +1,3 @@
-Before
-{{ fail() }}
-After
+Before
+{{ fail() }}
+After
diff --git a/contrib/python/Jinja2/py3/tests/res/templates/foo/test.html b/contrib/python/Jinja2/py3/tests/res/templates/foo/test.html
index b7d6715e2d..bbd2d23cd1 100644
--- a/contrib/python/Jinja2/py3/tests/res/templates/foo/test.html
+++ b/contrib/python/Jinja2/py3/tests/res/templates/foo/test.html
@@ -1 +1 @@
-FOO
+FOO
diff --git a/contrib/python/Jinja2/py3/tests/res/templates/syntaxerror.html b/contrib/python/Jinja2/py3/tests/res/templates/syntaxerror.html
index f21b817939..dc8c8af224 100644
--- a/contrib/python/Jinja2/py3/tests/res/templates/syntaxerror.html
+++ b/contrib/python/Jinja2/py3/tests/res/templates/syntaxerror.html
@@ -1,4 +1,4 @@
-Foo
-{% for item in broken %}
- ...
-{% endif %}
+Foo
+{% for item in broken %}
+ ...
+{% endif %}
diff --git a/contrib/python/Jinja2/py3/tests/res/templates/test.html b/contrib/python/Jinja2/py3/tests/res/templates/test.html
index ba578e48b1..640acfc455 100644
--- a/contrib/python/Jinja2/py3/tests/res/templates/test.html
+++ b/contrib/python/Jinja2/py3/tests/res/templates/test.html
@@ -1 +1 @@
-BAR
+BAR
diff --git a/contrib/python/Jinja2/py3/tests/test_api.py b/contrib/python/Jinja2/py3/tests/test_api.py
index 4db3b4a96a..e36f54a5ed 100644
--- a/contrib/python/Jinja2/py3/tests/test_api.py
+++ b/contrib/python/Jinja2/py3/tests/test_api.py
@@ -1,8 +1,8 @@
import shutil
-import tempfile
+import tempfile
from pathlib import Path
-
-import pytest
+
+import pytest
from jinja2 import ChainableUndefined
from jinja2 import DebugUndefined
@@ -16,31 +16,31 @@ from jinja2 import Template
from jinja2 import TemplatesNotFound
from jinja2 import Undefined
from jinja2 import UndefinedError
-from jinja2.compiler import CodeGenerator
-from jinja2.runtime import Context
-from jinja2.utils import Cycler
+from jinja2.compiler import CodeGenerator
+from jinja2.runtime import Context
+from jinja2.utils import Cycler
from jinja2.utils import pass_context
from jinja2.utils import pass_environment
from jinja2.utils import pass_eval_context
-
-
+
+
class TestExtendedAPI:
- def test_item_and_attribute(self, env):
- from jinja2.sandbox import SandboxedEnvironment
-
- for env in Environment(), SandboxedEnvironment():
+ def test_item_and_attribute(self, env):
+ from jinja2.sandbox import SandboxedEnvironment
+
+ for env in Environment(), SandboxedEnvironment():
tmpl = env.from_string("{{ foo.items()|list }}")
assert tmpl.render(foo={"items": 42}) == "[('items', 42)]"
- tmpl = env.from_string('{{ foo|attr("items")()|list }}')
+ tmpl = env.from_string('{{ foo|attr("items")()|list }}')
assert tmpl.render(foo={"items": 42}) == "[('items', 42)]"
- tmpl = env.from_string('{{ foo["items"] }}')
+ tmpl = env.from_string('{{ foo["items"] }}')
assert tmpl.render(foo={"items": 42}) == "42"
-
+
def test_finalize(self):
e = Environment(finalize=lambda v: "" if v is None else v)
t = e.from_string("{% for item in seq %}|{{ item }}{% endfor %}")
assert t.render(seq=(None, 1, "foo")) == "||1|foo"
-
+
def test_finalize_constant_expression(self):
e = Environment(finalize=lambda v: "" if v is None else v)
t = e.from_string("<{{ none }}>")
@@ -81,34 +81,34 @@ class TestExtendedAPI:
t = e.from_string("{{ value }}")
assert t.render(value="hello") == "{{ 'hello' }}"
- def test_cycler(self, env):
- items = 1, 2, 3
- c = Cycler(*items)
- for item in items + items:
- assert c.current == item
- assert next(c) == item
- next(c)
- assert c.current == 2
- c.reset()
- assert c.current == 1
-
- def test_expressions(self, env):
- expr = env.compile_expression("foo")
- assert expr() is None
- assert expr(foo=42) == 42
- expr2 = env.compile_expression("foo", undefined_to_none=False)
- assert is_undefined(expr2())
-
- expr = env.compile_expression("42 + foo")
- assert expr(foo=42) == 84
-
- def test_template_passthrough(self, env):
+ def test_cycler(self, env):
+ items = 1, 2, 3
+ c = Cycler(*items)
+ for item in items + items:
+ assert c.current == item
+ assert next(c) == item
+ next(c)
+ assert c.current == 2
+ c.reset()
+ assert c.current == 1
+
+ def test_expressions(self, env):
+ expr = env.compile_expression("foo")
+ assert expr() is None
+ assert expr(foo=42) == 42
+ expr2 = env.compile_expression("foo", undefined_to_none=False)
+ assert is_undefined(expr2())
+
+ expr = env.compile_expression("42 + foo")
+ assert expr(foo=42) == 84
+
+ def test_template_passthrough(self, env):
t = Template("Content")
- assert env.get_template(t) is t
- assert env.select_template([t]) is t
- assert env.get_or_select_template([t]) is t
- assert env.get_or_select_template(t) is t
-
+ assert env.get_template(t) is t
+ assert env.select_template([t]) is t
+ assert env.get_or_select_template([t]) is t
+ assert env.get_or_select_template(t) is t
+
def test_get_template_undefined(self, env):
"""Passing Undefined to get/select_template raises an
UndefinedError or shows the undefined message in the list.
@@ -132,12 +132,12 @@ class TestExtendedAPI:
assert "'no_name_1' is undefined" in exc_message
assert "no_name_2" in exc_message
- def test_autoescape_autoselect(self, env):
- def select_autoescape(name):
+ def test_autoescape_autoselect(self, env):
+ def select_autoescape(name):
if name is None or "." not in name:
- return False
+ return False
return name.endswith(".html")
-
+
env = Environment(
autoescape=select_autoescape,
loader=DictLoader({"test.txt": "{{ foo }}", "test.html": "{{ foo }}"}),
@@ -148,7 +148,7 @@ class TestExtendedAPI:
assert t.render(foo="<foo>") == "&lt;foo&gt;"
t = env.from_string("{{ foo }}")
assert t.render(foo="<foo>") == "<foo>"
-
+
def test_sandbox_max_range(self, env):
from jinja2.sandbox import SandboxedEnvironment, MAX_RANGE
@@ -160,60 +160,60 @@ class TestExtendedAPI:
class TestMeta:
- def test_find_undeclared_variables(self, env):
+ def test_find_undeclared_variables(self, env):
ast = env.parse("{% set foo = 42 %}{{ bar + foo }}")
- x = meta.find_undeclared_variables(ast)
+ x = meta.find_undeclared_variables(ast)
assert x == {"bar"}
-
+
ast = env.parse(
"{% set foo = 42 %}{{ bar + foo }}"
"{% macro meh(x) %}{{ x }}{% endmacro %}"
"{% for item in seq %}{{ muh(item) + meh(seq) }}"
"{% endfor %}"
)
- x = meta.find_undeclared_variables(ast)
+ x = meta.find_undeclared_variables(ast)
assert x == {"bar", "seq", "muh"}
-
+
ast = env.parse("{% for x in range(5) %}{{ x }}{% endfor %}{{ foo }}")
x = meta.find_undeclared_variables(ast)
assert x == {"foo"}
- def test_find_refererenced_templates(self, env):
- ast = env.parse('{% extends "layout.html" %}{% include helper %}')
- i = meta.find_referenced_templates(ast)
+ def test_find_refererenced_templates(self, env):
+ ast = env.parse('{% extends "layout.html" %}{% include helper %}')
+ i = meta.find_referenced_templates(ast)
assert next(i) == "layout.html"
- assert next(i) is None
- assert list(i) == []
-
+ assert next(i) is None
+ assert list(i) == []
+
ast = env.parse(
'{% extends "layout.html" %}'
'{% from "test.html" import a, b as c %}'
'{% import "meh.html" as meh %}'
'{% include "muh.html" %}'
)
- i = meta.find_referenced_templates(ast)
+ i = meta.find_referenced_templates(ast)
assert list(i) == ["layout.html", "test.html", "meh.html", "muh.html"]
-
- def test_find_included_templates(self, env):
- ast = env.parse('{% include ["foo.html", "bar.html"] %}')
- i = meta.find_referenced_templates(ast)
+
+ def test_find_included_templates(self, env):
+ ast = env.parse('{% include ["foo.html", "bar.html"] %}')
+ i = meta.find_referenced_templates(ast)
assert list(i) == ["foo.html", "bar.html"]
-
- ast = env.parse('{% include ("foo.html", "bar.html") %}')
- i = meta.find_referenced_templates(ast)
+
+ ast = env.parse('{% include ("foo.html", "bar.html") %}')
+ i = meta.find_referenced_templates(ast)
assert list(i) == ["foo.html", "bar.html"]
-
- ast = env.parse('{% include ["foo.html", "bar.html", foo] %}')
- i = meta.find_referenced_templates(ast)
+
+ ast = env.parse('{% include ["foo.html", "bar.html", foo] %}')
+ i = meta.find_referenced_templates(ast)
assert list(i) == ["foo.html", "bar.html", None]
-
- ast = env.parse('{% include ("foo.html", "bar.html", foo) %}')
- i = meta.find_referenced_templates(ast)
+
+ ast = env.parse('{% include ("foo.html", "bar.html", foo) %}')
+ i = meta.find_referenced_templates(ast)
assert list(i) == ["foo.html", "bar.html", None]
-
-
+
+
class TestStreaming:
- def test_basic_streaming(self, env):
+ def test_basic_streaming(self, env):
t = env.from_string(
"<ul>{% for item in seq %}<li>{{ loop.index }} - {{ item }}</li>"
"{%- endfor %}</ul>"
@@ -221,51 +221,51 @@ class TestStreaming:
stream = t.stream(seq=list(range(3)))
assert next(stream) == "<ul>"
assert "".join(stream) == "<li>1 - 0</li><li>2 - 1</li><li>3 - 2</li></ul>"
-
- def test_buffered_streaming(self, env):
+
+ def test_buffered_streaming(self, env):
tmpl = env.from_string(
"<ul>{% for item in seq %}<li>{{ loop.index }} - {{ item }}</li>"
"{%- endfor %}</ul>"
)
stream = tmpl.stream(seq=list(range(3)))
- stream.enable_buffering(size=3)
+ stream.enable_buffering(size=3)
assert next(stream) == "<ul><li>1"
assert next(stream) == " - 0</li>"
-
- def test_streaming_behavior(self, env):
- tmpl = env.from_string("")
- stream = tmpl.stream()
- assert not stream.buffered
- stream.enable_buffering(20)
- assert stream.buffered
- stream.disable_buffering()
- assert not stream.buffered
-
- def test_dump_stream(self, env):
+
+ def test_streaming_behavior(self, env):
+ tmpl = env.from_string("")
+ stream = tmpl.stream()
+ assert not stream.buffered
+ stream.enable_buffering(20)
+ assert stream.buffered
+ stream.disable_buffering()
+ assert not stream.buffered
+
+ def test_dump_stream(self, env):
tmp = Path(tempfile.mkdtemp())
- try:
+ try:
tmpl = env.from_string("\u2713")
- stream = tmpl.stream()
+ stream = tmpl.stream()
stream.dump(str(tmp / "dump.txt"), "utf-8")
assert (tmp / "dump.txt").read_bytes() == b"\xe2\x9c\x93"
- finally:
- shutil.rmtree(tmp)
-
-
+ finally:
+ shutil.rmtree(tmp)
+
+
class TestUndefined:
- def test_stopiteration_is_undefined(self):
- def test():
- raise StopIteration()
+ def test_stopiteration_is_undefined(self):
+ def test():
+ raise StopIteration()
t = Template("A{{ test() }}B")
assert t.render(test=test) == "AB"
t = Template("A{{ test().missingattribute }}B")
- pytest.raises(UndefinedError, t.render, test=test)
-
- def test_undefined_and_special_attributes(self):
+ pytest.raises(UndefinedError, t.render, test=test)
+
+ def test_undefined_and_special_attributes(self):
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
@@ -281,34 +281,34 @@ class TestUndefined:
with pytest.raises(UndefinedError):
getattr(u, "recursion", None)
- def test_logging_undefined(self):
- _messages = []
-
+ def test_logging_undefined(self):
+ _messages = []
+
class DebugLogger:
- def warning(self, msg, *args):
+ def warning(self, msg, *args):
_messages.append("W:" + msg % args)
-
- def error(self, msg, *args):
+
+ def error(self, msg, *args):
_messages.append("E:" + msg % args)
-
- logging_undefined = make_logging_undefined(DebugLogger())
- env = Environment(undefined=logging_undefined)
+
+ logging_undefined = make_logging_undefined(DebugLogger())
+ env = Environment(undefined=logging_undefined)
assert env.from_string("{{ missing }}").render() == ""
pytest.raises(UndefinedError, env.from_string("{{ missing.attribute }}").render)
assert env.from_string("{{ missing|list }}").render() == "[]"
assert env.from_string("{{ missing is not defined }}").render() == "True"
assert env.from_string("{{ foo.missing }}").render(foo=42) == ""
assert env.from_string("{{ not missing }}").render() == "True"
- assert _messages == [
+ assert _messages == [
"W:Template variable warning: 'missing' is undefined",
- "E:Template variable error: 'missing' is undefined",
+ "E:Template variable error: 'missing' is undefined",
"W:Template variable warning: 'missing' is undefined",
"W:Template variable warning: 'int object' has no attribute 'missing'",
"W:Template variable warning: 'missing' is undefined",
- ]
-
- def test_default_undefined(self):
- env = Environment(undefined=Undefined)
+ ]
+
+ def test_default_undefined(self):
+ env = Environment(undefined=Undefined)
assert env.from_string("{{ missing }}").render() == ""
pytest.raises(UndefinedError, env.from_string("{{ missing.attribute }}").render)
assert env.from_string("{{ missing|list }}").render() == "[]"
@@ -324,7 +324,7 @@ class TestUndefined:
assert hash(und1) == hash(und2) == hash(Undefined())
with pytest.raises(AttributeError):
getattr(Undefined, "__slots__") # noqa: B009
-
+
def test_chainable_undefined(self):
env = Environment(undefined=ChainableUndefined)
# The following tests are copied from test_default_undefined
@@ -351,8 +351,8 @@ class TestUndefined:
== "baz"
)
- def test_debug_undefined(self):
- env = Environment(undefined=DebugUndefined)
+ def test_debug_undefined(self):
+ env = Environment(undefined=DebugUndefined)
assert env.from_string("{{ missing }}").render() == "{{ missing }}"
pytest.raises(UndefinedError, env.from_string("{{ missing.attribute }}").render)
assert env.from_string("{{ missing|list }}").render() == "[]"
@@ -369,9 +369,9 @@ class TestUndefined:
)
with pytest.raises(AttributeError):
getattr(DebugUndefined, "__slots__") # noqa: B009
-
- def test_strict_undefined(self):
- env = Environment(undefined=StrictUndefined)
+
+ def test_strict_undefined(self):
+ env = Environment(undefined=StrictUndefined)
pytest.raises(UndefinedError, env.from_string("{{ missing }}").render)
pytest.raises(UndefinedError, env.from_string("{{ missing.attribute }}").render)
pytest.raises(UndefinedError, env.from_string("{{ missing|list }}").render)
@@ -388,47 +388,47 @@ class TestUndefined:
with pytest.raises(AttributeError):
getattr(StrictUndefined, "__slots__") # noqa: B009
assert env.from_string('{{ "foo" if false }}').render() == ""
-
- def test_indexing_gives_undefined(self):
- t = Template("{{ var[42].foo }}")
- pytest.raises(UndefinedError, t.render, var=0)
-
- def test_none_gives_proper_error(self):
+
+ def test_indexing_gives_undefined(self):
+ t = Template("{{ var[42].foo }}")
+ pytest.raises(UndefinedError, t.render, var=0)
+
+ def test_none_gives_proper_error(self):
with pytest.raises(UndefinedError, match="'None' has no attribute 'split'"):
Environment().getattr(None, "split")()
-
- def test_object_repr(self):
+
+ def test_object_repr(self):
with pytest.raises(
UndefinedError, match="'int object' has no attribute 'upper'"
):
Undefined(obj=42, name="upper")()
-
-
+
+
class TestLowLevel:
- def test_custom_code_generator(self):
- class CustomCodeGenerator(CodeGenerator):
- def visit_Const(self, node, frame=None):
- # This method is pure nonsense, but works fine for testing...
+ def test_custom_code_generator(self):
+ class CustomCodeGenerator(CodeGenerator):
+ def visit_Const(self, node, frame=None):
+ # This method is pure nonsense, but works fine for testing...
if node.value == "foo":
self.write(repr("bar"))
- else:
+ else:
super().visit_Const(node, frame)
-
- class CustomEnvironment(Environment):
- code_generator_class = CustomCodeGenerator
-
- env = CustomEnvironment()
- tmpl = env.from_string('{% set foo = "foo" %}{{ foo }}')
+
+ class CustomEnvironment(Environment):
+ code_generator_class = CustomCodeGenerator
+
+ env = CustomEnvironment()
+ tmpl = env.from_string('{% set foo = "foo" %}{{ foo }}')
assert tmpl.render() == "bar"
-
- def test_custom_context(self):
- class CustomContext(Context):
- def resolve_or_missing(self, key):
+
+ def test_custom_context(self):
+ class CustomContext(Context):
+ def resolve_or_missing(self, key):
return "resolve-" + key
-
- class CustomEnvironment(Environment):
- context_class = CustomContext
-
- env = CustomEnvironment()
+
+ class CustomEnvironment(Environment):
+ context_class = CustomContext
+
+ env = CustomEnvironment()
tmpl = env.from_string("{{ foo }}")
assert tmpl.render() == "resolve-foo"
diff --git a/contrib/python/Jinja2/py3/tests/test_async.py b/contrib/python/Jinja2/py3/tests/test_async.py
index 375a7bac33..4f45e6df14 100644
--- a/contrib/python/Jinja2/py3/tests/test_async.py
+++ b/contrib/python/Jinja2/py3/tests/test_async.py
@@ -1,8 +1,8 @@
-import asyncio
+import asyncio
import sys
-
+
import pytest
-
+
from jinja2 import ChainableUndefined
from jinja2 import DictLoader
from jinja2 import Environment
@@ -12,14 +12,14 @@ from jinja2.exceptions import TemplateNotFound
from jinja2.exceptions import TemplatesNotFound
from jinja2.exceptions import UndefinedError
from jinja2.nativetypes import NativeEnvironment
-
+
if sys.version_info < (3, 7):
-
+
def run(coro):
loop = asyncio.get_event_loop()
return loop.run_until_complete(coro)
-
+
else:
@@ -27,106 +27,106 @@ else:
return asyncio.run(coro)
-def test_basic_async():
+def test_basic_async():
t = Template(
"{% for item in [1, 2, 3] %}[{{ item }}]{% endfor %}", enable_async=True
)
- async def func():
- return await t.render_async()
-
- rv = run(func())
+ async def func():
+ return await t.render_async()
+
+ rv = run(func())
assert rv == "[1][2][3]"
-
-
-def test_await_on_calls():
+
+
+def test_await_on_calls():
t = Template("{{ async_func() + normal_func() }}", enable_async=True)
-
- async def async_func():
- return 42
-
- def normal_func():
- return 23
-
- async def func():
+
+ async def async_func():
+ return 42
+
+ def normal_func():
+ return 23
+
+ async def func():
return await t.render_async(async_func=async_func, normal_func=normal_func)
-
- rv = run(func())
+
+ rv = run(func())
assert rv == "65"
-
-
-def test_await_on_calls_normal_render():
+
+
+def test_await_on_calls_normal_render():
t = Template("{{ async_func() + normal_func() }}", enable_async=True)
-
- async def async_func():
- return 42
-
- def normal_func():
- return 23
-
+
+ async def async_func():
+ return 42
+
+ def normal_func():
+ return 23
+
rv = t.render(async_func=async_func, normal_func=normal_func)
-
+
assert rv == "65"
-
-
-def test_await_and_macros():
+
+
+def test_await_and_macros():
t = Template(
"{% macro foo(x) %}[{{ x }}][{{ async_func() }}]{% endmacro %}{{ foo(42) }}",
enable_async=True,
)
-
- async def async_func():
- return 42
-
- async def func():
- return await t.render_async(async_func=async_func)
-
- rv = run(func())
+
+ async def async_func():
+ return 42
+
+ async def func():
+ return await t.render_async(async_func=async_func)
+
+ rv = run(func())
assert rv == "[42][42]"
-
-
-def test_async_blocks():
+
+
+def test_async_blocks():
t = Template(
"{% block foo %}<Test>{% endblock %}{{ self.foo() }}",
enable_async=True,
autoescape=True,
)
- async def func():
- return await t.render_async()
-
- rv = run(func())
+ async def func():
+ return await t.render_async()
+
+ rv = run(func())
assert rv == "<Test><Test>"
-
-
-def test_async_generate():
+
+
+def test_async_generate():
t = Template("{% for x in [1, 2, 3] %}{{ x }}{% endfor %}", enable_async=True)
- rv = list(t.generate())
+ rv = list(t.generate())
assert rv == ["1", "2", "3"]
-
-
-def test_async_iteration_in_templates():
+
+
+def test_async_iteration_in_templates():
t = Template("{% for x in rng %}{{ x }}{% endfor %}", enable_async=True)
- async def async_iterator():
- for item in [1, 2, 3]:
- yield item
+ async def async_iterator():
+ for item in [1, 2, 3]:
+ yield item
- rv = list(t.generate(rng=async_iterator()))
+ rv = list(t.generate(rng=async_iterator()))
assert rv == ["1", "2", "3"]
-
-
-def test_async_iteration_in_templates_extended():
+
+
+def test_async_iteration_in_templates_extended():
t = Template(
"{% for x in rng %}{{ loop.index0 }}/{{ x }}{% endfor %}", enable_async=True
)
stream = t.generate(rng=auto_aiter(range(1, 4)))
assert next(stream) == "0"
assert "".join(stream) == "/11/22/3"
-
-
-@pytest.fixture
-def test_env_async():
+
+
+@pytest.fixture
+def test_env_async():
env = Environment(
loader=DictLoader(
dict(
@@ -138,63 +138,63 @@ def test_env_async():
enable_async=True,
)
env.globals["bar"] = 23
- return env
-
-
+ return env
+
+
class TestAsyncImports:
- def test_context_imports(self, test_env_async):
- t = test_env_async.from_string('{% import "module" as m %}{{ m.test() }}')
+ def test_context_imports(self, test_env_async):
+ t = test_env_async.from_string('{% import "module" as m %}{{ m.test() }}')
assert t.render(foo=42) == "[|23]"
- t = test_env_async.from_string(
- '{% import "module" as m without context %}{{ m.test() }}'
- )
+ t = test_env_async.from_string(
+ '{% import "module" as m without context %}{{ m.test() }}'
+ )
assert t.render(foo=42) == "[|23]"
- t = test_env_async.from_string(
- '{% import "module" as m with context %}{{ m.test() }}'
- )
+ t = test_env_async.from_string(
+ '{% import "module" as m with context %}{{ m.test() }}'
+ )
assert t.render(foo=42) == "[42|23]"
- t = test_env_async.from_string('{% from "module" import test %}{{ test() }}')
+ t = test_env_async.from_string('{% from "module" import test %}{{ test() }}')
assert t.render(foo=42) == "[|23]"
- t = test_env_async.from_string(
- '{% from "module" import test without context %}{{ test() }}'
- )
+ t = test_env_async.from_string(
+ '{% from "module" import test without context %}{{ test() }}'
+ )
assert t.render(foo=42) == "[|23]"
- t = test_env_async.from_string(
- '{% from "module" import test with context %}{{ test() }}'
- )
+ t = test_env_async.from_string(
+ '{% from "module" import test with context %}{{ test() }}'
+ )
assert t.render(foo=42) == "[42|23]"
-
- def test_trailing_comma(self, test_env_async):
- test_env_async.from_string('{% from "foo" import bar, baz with context %}')
- test_env_async.from_string('{% from "foo" import bar, baz, with context %}')
- test_env_async.from_string('{% from "foo" import bar, with context %}')
- test_env_async.from_string('{% from "foo" import bar, with, context %}')
- test_env_async.from_string('{% from "foo" import bar, with with context %}')
-
- def test_exports(self, test_env_async):
+
+ def test_trailing_comma(self, test_env_async):
+ test_env_async.from_string('{% from "foo" import bar, baz with context %}')
+ test_env_async.from_string('{% from "foo" import bar, baz, with context %}')
+ test_env_async.from_string('{% from "foo" import bar, with context %}')
+ test_env_async.from_string('{% from "foo" import bar, with, context %}')
+ test_env_async.from_string('{% from "foo" import bar, with with context %}')
+
+ def test_exports(self, test_env_async):
m = run(
test_env_async.from_string(
"""
- {% macro toplevel() %}...{% endmacro %}
- {% macro __private() %}...{% endmacro %}
- {% set variable = 42 %}
- {% for item in [1] %}
- {% macro notthere() %}{% endmacro %}
- {% endfor %}
+ {% macro toplevel() %}...{% endmacro %}
+ {% macro __private() %}...{% endmacro %}
+ {% set variable = 42 %}
+ {% for item in [1] %}
+ {% macro notthere() %}{% endmacro %}
+ {% endfor %}
"""
)._get_default_module_async()
)
assert run(m.toplevel()) == "..."
assert not hasattr(m, "__missing")
- assert m.variable == 42
+ assert m.variable == 42
assert not hasattr(m, "notthere")
-
+
def test_import_with_globals(self, test_env_async):
t = test_env_async.from_string(
'{% import "module" as m %}{{ m.test() }}', globals={"foo": 42}
)
assert t.render() == "[42|23]"
-
+
t = test_env_async.from_string('{% import "module" as m %}{{ m.test() }}')
assert t.render() == "[|23]"
@@ -214,40 +214,40 @@ class TestAsyncImports:
class TestAsyncIncludes:
- def test_context_include(self, test_env_async):
- t = test_env_async.from_string('{% include "header" %}')
+ def test_context_include(self, test_env_async):
+ t = test_env_async.from_string('{% include "header" %}')
assert t.render(foo=42) == "[42|23]"
- t = test_env_async.from_string('{% include "header" with context %}')
+ t = test_env_async.from_string('{% include "header" with context %}')
assert t.render(foo=42) == "[42|23]"
- t = test_env_async.from_string('{% include "header" without context %}')
+ t = test_env_async.from_string('{% include "header" without context %}')
assert t.render(foo=42) == "[|23]"
-
- def test_choice_includes(self, test_env_async):
- t = test_env_async.from_string('{% include ["missing", "header"] %}')
+
+ def test_choice_includes(self, test_env_async):
+ t = test_env_async.from_string('{% include ["missing", "header"] %}')
assert t.render(foo=42) == "[42|23]"
-
- t = test_env_async.from_string(
- '{% include ["missing", "missing2"] ignore missing %}'
- )
+
+ t = test_env_async.from_string(
+ '{% include ["missing", "missing2"] ignore missing %}'
+ )
assert t.render(foo=42) == ""
-
- t = test_env_async.from_string('{% include ["missing", "missing2"] %}')
- pytest.raises(TemplateNotFound, t.render)
+
+ t = test_env_async.from_string('{% include ["missing", "missing2"] %}')
+ pytest.raises(TemplateNotFound, t.render)
with pytest.raises(TemplatesNotFound) as e:
- t.render()
-
+ t.render()
+
assert e.value.templates == ["missing", "missing2"]
assert e.value.name == "missing2"
- def test_includes(t, **ctx):
+ def test_includes(t, **ctx):
ctx["foo"] = 42
assert t.render(ctx) == "[42|23]"
-
- t = test_env_async.from_string('{% include ["missing", "header"] %}')
- test_includes(t)
+
+ t = test_env_async.from_string('{% include ["missing", "header"] %}')
+ test_includes(t)
t = test_env_async.from_string("{% include x %}")
test_includes(t, x=["missing", "header"])
- t = test_env_async.from_string('{% include [x, "header"] %}')
+ t = test_env_async.from_string('{% include [x, "header"] %}')
test_includes(t, x="missing")
t = test_env_async.from_string("{% include x %}")
test_includes(t, x="header")
@@ -255,17 +255,17 @@ class TestAsyncIncludes:
test_includes(t, x="header")
t = test_env_async.from_string("{% include [x] %}")
test_includes(t, x="header")
-
- def test_include_ignoring_missing(self, test_env_async):
- t = test_env_async.from_string('{% include "missing" %}')
- pytest.raises(TemplateNotFound, t.render)
+
+ def test_include_ignoring_missing(self, test_env_async):
+ t = test_env_async.from_string('{% include "missing" %}')
+ pytest.raises(TemplateNotFound, t.render)
for extra in "", "with context", "without context":
t = test_env_async.from_string(
'{% include "missing" ignore missing ' + extra + " %}"
)
assert t.render() == ""
-
- def test_context_include_with_overrides(self, test_env_async):
+
+ def test_context_include_with_overrides(self, test_env_async):
env = Environment(
loader=DictLoader(
dict(
@@ -274,23 +274,23 @@ class TestAsyncIncludes:
)
)
)
- assert env.get_template("main").render() == "123"
-
- def test_unoptimized_scopes(self, test_env_async):
+ assert env.get_template("main").render() == "123"
+
+ def test_unoptimized_scopes(self, test_env_async):
t = test_env_async.from_string(
"""
- {% macro outer(o) %}
- {% macro inner() %}
- {% include "o_printer" %}
- {% endmacro %}
- {{ inner() }}
- {% endmacro %}
- {{ outer("FOO") }}
+ {% macro outer(o) %}
+ {% macro inner() %}
+ {% include "o_printer" %}
+ {% endmacro %}
+ {{ inner() }}
+ {% endmacro %}
+ {{ outer("FOO") }}
"""
)
assert t.render().strip() == "(FOO)"
-
- def test_unoptimized_scopes_autoescape(self):
+
+ def test_unoptimized_scopes_autoescape(self):
env = Environment(
loader=DictLoader({"o_printer": "({{ o }})"}),
autoescape=True,
@@ -298,35 +298,35 @@ class TestAsyncIncludes:
)
t = env.from_string(
"""
- {% macro outer(o) %}
- {% macro inner() %}
- {% include "o_printer" %}
- {% endmacro %}
- {{ inner() }}
- {% endmacro %}
- {{ outer("FOO") }}
+ {% macro outer(o) %}
+ {% macro inner() %}
+ {% include "o_printer" %}
+ {% endmacro %}
+ {{ inner() }}
+ {% endmacro %}
+ {{ outer("FOO") }}
"""
)
assert t.render().strip() == "(FOO)"
-
-
+
+
class TestAsyncForLoop:
- def test_simple(self, test_env_async):
+ def test_simple(self, test_env_async):
tmpl = test_env_async.from_string("{% for item in seq %}{{ item }}{% endfor %}")
assert tmpl.render(seq=list(range(10))) == "0123456789"
-
- def test_else(self, test_env_async):
- tmpl = test_env_async.from_string(
+
+ def test_else(self, test_env_async):
+ tmpl = test_env_async.from_string(
"{% for item in seq %}XXX{% else %}...{% endfor %}"
)
assert tmpl.render() == "..."
-
- def test_empty_blocks(self, test_env_async):
+
+ def test_empty_blocks(self, test_env_async):
tmpl = test_env_async.from_string(
"<{% for item in seq %}{% else %}{% endfor %}>"
)
assert tmpl.render() == "<>"
-
+
@pytest.mark.parametrize(
"transform", [lambda x: x, iter, reversed, lambda x: (i for i in x), auto_aiter]
)
@@ -338,58 +338,58 @@ class TestAsyncForLoop:
)
out = t.render(seq=transform([42, 24]))
assert out == "1|0|2|1|True|False|2\n2|1|1|0|False|True|2\n"
-
- def test_cycling(self, test_env_async):
+
+ def test_cycling(self, test_env_async):
tmpl = test_env_async.from_string(
"""{% for item in seq %}{{
- loop.cycle('<1>', '<2>') }}{% endfor %}{%
+ loop.cycle('<1>', '<2>') }}{% endfor %}{%
for item in seq %}{{ loop.cycle(*through) }}{% endfor %}"""
)
output = tmpl.render(seq=list(range(4)), through=("<1>", "<2>"))
assert output == "<1><2>" * 4
-
- def test_lookaround(self, test_env_async):
+
+ def test_lookaround(self, test_env_async):
tmpl = test_env_async.from_string(
"""{% for item in seq -%}
- {{ loop.previtem|default('x') }}-{{ item }}-{{
- loop.nextitem|default('x') }}|
+ {{ loop.previtem|default('x') }}-{{ item }}-{{
+ loop.nextitem|default('x') }}|
{%- endfor %}"""
)
- output = tmpl.render(seq=list(range(4)))
+ output = tmpl.render(seq=list(range(4)))
assert output == "x-0-1|0-1-2|1-2-3|2-3-x|"
-
- def test_changed(self, test_env_async):
+
+ def test_changed(self, test_env_async):
tmpl = test_env_async.from_string(
"""{% for item in seq -%}
- {{ loop.changed(item) }},
+ {{ loop.changed(item) }},
{%- endfor %}"""
)
- output = tmpl.render(seq=[None, None, 1, 2, 2, 3, 4, 4, 4])
+ output = tmpl.render(seq=[None, None, 1, 2, 2, 3, 4, 4, 4])
assert output == "True,False,True,True,False,True,True,False,False,"
-
- def test_scope(self, test_env_async):
+
+ def test_scope(self, test_env_async):
tmpl = test_env_async.from_string("{% for item in seq %}{% endfor %}{{ item }}")
- output = tmpl.render(seq=list(range(10)))
- assert not output
-
- def test_varlen(self, test_env_async):
- def inner():
+ output = tmpl.render(seq=list(range(10)))
+ assert not output
+
+ def test_varlen(self, test_env_async):
+ def inner():
yield from range(5)
tmpl = test_env_async.from_string(
"{% for item in iter %}{{ item }}{% endfor %}"
)
- output = tmpl.render(iter=inner())
+ output = tmpl.render(iter=inner())
assert output == "01234"
-
- def test_noniter(self, test_env_async):
+
+ def test_noniter(self, test_env_async):
tmpl = test_env_async.from_string("{% for item in none %}...{% endfor %}")
- pytest.raises(TypeError, tmpl.render)
-
- def test_recursive(self, test_env_async):
+ pytest.raises(TypeError, tmpl.render)
+
+ def test_recursive(self, test_env_async):
tmpl = test_env_async.from_string(
"""{% for item in seq recursive -%}
- [{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
+ [{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
{%- endfor %}"""
)
assert (
@@ -402,13 +402,13 @@ class TestAsyncForLoop:
)
== "[1<[1][2]>][2<[1][2]>][3<[a]>]"
)
-
- def test_recursive_lookaround(self, test_env_async):
+
+ def test_recursive_lookaround(self, test_env_async):
tmpl = test_env_async.from_string(
"""{% for item in seq recursive -%}
- [{{ loop.previtem.a if loop.previtem is defined else 'x' }}.{{
- item.a }}.{{ loop.nextitem.a if loop.nextitem is defined else 'x'
- }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
+ [{{ loop.previtem.a if loop.previtem is defined else 'x' }}.{{
+ item.a }}.{{ loop.nextitem.a if loop.nextitem is defined else 'x'
+ }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
{%- endfor %}"""
)
assert (
@@ -421,8 +421,8 @@ class TestAsyncForLoop:
)
== "[x.1.2<[x.1.2][1.2.x]>][1.2.3<[x.1.2][1.2.x]>][2.3.x<[x.a.x]>]"
)
-
- def test_recursive_depth0(self, test_env_async):
+
+ def test_recursive_depth0(self, test_env_async):
tmpl = test_env_async.from_string(
"{% for item in seq recursive %}[{{ loop.depth0 }}:{{ item.a }}"
"{% if item.b %}<{{ loop(item.b) }}>{% endif %}]{% endfor %}"
@@ -437,8 +437,8 @@ class TestAsyncForLoop:
)
== "[0:1<[1:1][1:2]>][0:2<[1:1][1:2]>][0:3<[1:a]>]"
)
-
- def test_recursive_depth(self, test_env_async):
+
+ def test_recursive_depth(self, test_env_async):
tmpl = test_env_async.from_string(
"{% for item in seq recursive %}[{{ loop.depth }}:{{ item.a }}"
"{% if item.b %}<{{ loop(item.b) }}>{% endif %}]{% endfor %}"
@@ -453,58 +453,58 @@ class TestAsyncForLoop:
)
== "[1:1<[2:1][2:2]>][1:2<[2:1][2:2]>][1:3<[2:a]>]"
)
-
- def test_looploop(self, test_env_async):
+
+ def test_looploop(self, test_env_async):
tmpl = test_env_async.from_string(
"""{% for row in table %}
- {%- set rowloop = loop -%}
- {% for cell in row -%}
- [{{ rowloop.index }}|{{ loop.index }}]
- {%- endfor %}
+ {%- set rowloop = loop -%}
+ {% for cell in row -%}
+ [{{ rowloop.index }}|{{ loop.index }}]
+ {%- endfor %}
{%- endfor %}"""
)
assert tmpl.render(table=["ab", "cd"]) == "[1|1][1|2][2|1][2|2]"
-
- def test_reversed_bug(self, test_env_async):
+
+ def test_reversed_bug(self, test_env_async):
tmpl = test_env_async.from_string(
"{% for i in items %}{{ i }}"
"{% if not loop.last %}"
",{% endif %}{% endfor %}"
)
assert tmpl.render(items=reversed([3, 2, 1])) == "1,2,3"
-
- def test_loop_errors(self, test_env_async):
+
+ def test_loop_errors(self, test_env_async):
tmpl = test_env_async.from_string(
"""{% for item in [1] if loop.index
== 0 %}...{% endfor %}"""
)
- pytest.raises(UndefinedError, tmpl.render)
+ pytest.raises(UndefinedError, tmpl.render)
tmpl = test_env_async.from_string(
"""{% for item in [] %}...{% else
%}{{ loop }}{% endfor %}"""
)
assert tmpl.render() == ""
-
- def test_loop_filter(self, test_env_async):
+
+ def test_loop_filter(self, test_env_async):
tmpl = test_env_async.from_string(
"{% for item in range(10) if item is even %}[{{ item }}]{% endfor %}"
)
assert tmpl.render() == "[0][2][4][6][8]"
tmpl = test_env_async.from_string(
"""
- {%- for item in range(10) if item is even %}[{{
+ {%- for item in range(10) if item is even %}[{{
loop.index }}:{{ item }}]{% endfor %}"""
)
assert tmpl.render() == "[1:0][2:2][3:4][4:6][5:8]"
-
- def test_scoped_special_var(self, test_env_async):
- t = test_env_async.from_string(
+
+ def test_scoped_special_var(self, test_env_async):
+ t = test_env_async.from_string(
"{% for s in seq %}[{{ loop.first }}{% for c in s %}"
"|{{ loop.first }}{% endfor %}]{% endfor %}"
)
assert t.render(seq=("ab", "cd")) == "[True|True|False][False|True|False]"
-
- def test_scoped_loop_var(self, test_env_async):
+
+ def test_scoped_loop_var(self, test_env_async):
t = test_env_async.from_string(
"{% for x in seq %}{{ loop.first }}"
"{% for y in seq %}{% endfor %}{% endfor %}"
@@ -515,97 +515,97 @@ class TestAsyncForLoop:
"{{ loop.first }}{% endfor %}{% endfor %}"
)
assert t.render(seq="ab") == "TrueFalseTrueFalse"
-
- def test_recursive_empty_loop_iter(self, test_env_async):
+
+ def test_recursive_empty_loop_iter(self, test_env_async):
t = test_env_async.from_string(
"""
- {%- for item in foo recursive -%}{%- endfor -%}
+ {%- for item in foo recursive -%}{%- endfor -%}
"""
)
assert t.render(dict(foo=[])) == ""
-
- def test_call_in_loop(self, test_env_async):
+
+ def test_call_in_loop(self, test_env_async):
t = test_env_async.from_string(
"""
- {%- macro do_something() -%}
- [{{ caller() }}]
- {%- endmacro %}
-
- {%- for i in [1, 2, 3] %}
- {%- call do_something() -%}
- {{ i }}
- {%- endcall %}
- {%- endfor -%}
+ {%- macro do_something() -%}
+ [{{ caller() }}]
+ {%- endmacro %}
+
+ {%- for i in [1, 2, 3] %}
+ {%- call do_something() -%}
+ {{ i }}
+ {%- endcall %}
+ {%- endfor -%}
"""
)
assert t.render() == "[1][2][3]"
-
- def test_scoping_bug(self, test_env_async):
+
+ def test_scoping_bug(self, test_env_async):
t = test_env_async.from_string(
"""
- {%- for item in foo %}...{{ item }}...{% endfor %}
- {%- macro item(a) %}...{{ a }}...{% endmacro %}
- {{- item(2) -}}
+ {%- for item in foo %}...{{ item }}...{% endfor %}
+ {%- macro item(a) %}...{{ a }}...{% endmacro %}
+ {{- item(2) -}}
"""
)
assert t.render(foo=(1,)) == "...1......2..."
-
- def test_unpacking(self, test_env_async):
+
+ def test_unpacking(self, test_env_async):
tmpl = test_env_async.from_string(
"{% for a, b, c in [[1, 2, 3]] %}{{ a }}|{{ b }}|{{ c }}{% endfor %}"
)
assert tmpl.render() == "1|2|3"
-
- def test_recursive_loop_filter(self, test_env_async):
+
+ def test_recursive_loop_filter(self, test_env_async):
t = test_env_async.from_string(
"""
- <?xml version="1.0" encoding="UTF-8"?>
- <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
- {%- for page in [site.root] if page.url != this recursive %}
- <url><loc>{{ page.url }}</loc></url>
- {{- loop(page.children) }}
- {%- endfor %}
- </urlset>
+ <?xml version="1.0" encoding="UTF-8"?>
+ <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
+ {%- for page in [site.root] if page.url != this recursive %}
+ <url><loc>{{ page.url }}</loc></url>
+ {{- loop(page.children) }}
+ {%- endfor %}
+ </urlset>
"""
)
sm = t.render(
this="/foo",
site={"root": {"url": "/", "children": [{"url": "/foo"}, {"url": "/bar"}]}},
)
- lines = [x.strip() for x in sm.splitlines() if x.strip()]
- assert lines == [
- '<?xml version="1.0" encoding="UTF-8"?>',
- '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
+ lines = [x.strip() for x in sm.splitlines() if x.strip()]
+ assert lines == [
+ '<?xml version="1.0" encoding="UTF-8"?>',
+ '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
"<url><loc>/</loc></url>",
"<url><loc>/bar</loc></url>",
"</urlset>",
- ]
-
- def test_nonrecursive_loop_filter(self, test_env_async):
+ ]
+
+ def test_nonrecursive_loop_filter(self, test_env_async):
t = test_env_async.from_string(
"""
- <?xml version="1.0" encoding="UTF-8"?>
- <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
- {%- for page in items if page.url != this %}
- <url><loc>{{ page.url }}</loc></url>
- {%- endfor %}
- </urlset>
+ <?xml version="1.0" encoding="UTF-8"?>
+ <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
+ {%- for page in items if page.url != this %}
+ <url><loc>{{ page.url }}</loc></url>
+ {%- endfor %}
+ </urlset>
"""
)
sm = t.render(
this="/foo", items=[{"url": "/"}, {"url": "/foo"}, {"url": "/bar"}]
)
- lines = [x.strip() for x in sm.splitlines() if x.strip()]
- assert lines == [
- '<?xml version="1.0" encoding="UTF-8"?>',
- '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
+ lines = [x.strip() for x in sm.splitlines() if x.strip()]
+ assert lines == [
+ '<?xml version="1.0" encoding="UTF-8"?>',
+ '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
"<url><loc>/</loc></url>",
"<url><loc>/bar</loc></url>",
"</urlset>",
- ]
-
- def test_bare_async(self, test_env_async):
- t = test_env_async.from_string('{% extends "header" %}')
+ ]
+
+ def test_bare_async(self, test_env_async):
+ t = test_env_async.from_string('{% extends "header" %}')
assert t.render(foo=42) == "[42|23]"
def test_awaitable_property_slicing(self, test_env_async):
diff --git a/contrib/python/Jinja2/py3/tests/test_bytecode_cache.py b/contrib/python/Jinja2/py3/tests/test_bytecode_cache.py
index 5b9eb0ff69..a88feafe1f 100644
--- a/contrib/python/Jinja2/py3/tests/test_bytecode_cache.py
+++ b/contrib/python/Jinja2/py3/tests/test_bytecode_cache.py
@@ -1,77 +1,77 @@
-import pytest
-
-from jinja2 import Environment
+import pytest
+
+from jinja2 import Environment
from jinja2.bccache import Bucket
from jinja2.bccache import FileSystemBytecodeCache
from jinja2.bccache import MemcachedBytecodeCache
-from jinja2.exceptions import TemplateNotFound
-
-
-@pytest.fixture
+from jinja2.exceptions import TemplateNotFound
+
+
+@pytest.fixture
def env(package_loader, tmp_path):
bytecode_cache = FileSystemBytecodeCache(str(tmp_path))
return Environment(loader=package_loader, bytecode_cache=bytecode_cache)
-
-
+
+
class TestByteCodeCache:
- def test_simple(self, env):
+ def test_simple(self, env):
tmpl = env.get_template("test.html")
assert tmpl.render().strip() == "BAR"
pytest.raises(TemplateNotFound, env.get_template, "missing.html")
-
-
+
+
class MockMemcached:
- class Error(Exception):
- pass
-
- key = None
- value = None
- timeout = None
-
- def get(self, key):
- return self.value
-
- def set(self, key, value, timeout=None):
- self.key = key
- self.value = value
- self.timeout = timeout
-
- def get_side_effect(self, key):
- raise self.Error()
-
- def set_side_effect(self, *args):
- raise self.Error()
-
-
+ class Error(Exception):
+ pass
+
+ key = None
+ value = None
+ timeout = None
+
+ def get(self, key):
+ return self.value
+
+ def set(self, key, value, timeout=None):
+ self.key = key
+ self.value = value
+ self.timeout = timeout
+
+ def get_side_effect(self, key):
+ raise self.Error()
+
+ def set_side_effect(self, *args):
+ raise self.Error()
+
+
class TestMemcachedBytecodeCache:
- def test_dump_load(self):
- memcached = MockMemcached()
- m = MemcachedBytecodeCache(memcached)
-
+ def test_dump_load(self):
+ memcached = MockMemcached()
+ m = MemcachedBytecodeCache(memcached)
+
b = Bucket(None, "key", "")
b.code = "code"
- m.dump_bytecode(b)
+ m.dump_bytecode(b)
assert memcached.key == "jinja2/bytecode/key"
-
+
b = Bucket(None, "key", "")
- m.load_bytecode(b)
+ m.load_bytecode(b)
assert b.code == "code"
-
- def test_exception(self):
- memcached = MockMemcached()
- memcached.get = memcached.get_side_effect
- memcached.set = memcached.set_side_effect
- m = MemcachedBytecodeCache(memcached)
+
+ def test_exception(self):
+ memcached = MockMemcached()
+ memcached.get = memcached.get_side_effect
+ memcached.set = memcached.set_side_effect
+ m = MemcachedBytecodeCache(memcached)
b = Bucket(None, "key", "")
b.code = "code"
-
- m.dump_bytecode(b)
- m.load_bytecode(b)
-
- m.ignore_memcache_errors = False
-
- with pytest.raises(MockMemcached.Error):
- m.dump_bytecode(b)
-
- with pytest.raises(MockMemcached.Error):
- m.load_bytecode(b)
+
+ m.dump_bytecode(b)
+ m.load_bytecode(b)
+
+ m.ignore_memcache_errors = False
+
+ with pytest.raises(MockMemcached.Error):
+ m.dump_bytecode(b)
+
+ with pytest.raises(MockMemcached.Error):
+ m.load_bytecode(b)
diff --git a/contrib/python/Jinja2/py3/tests/test_core_tags.py b/contrib/python/Jinja2/py3/tests/test_core_tags.py
index 4bb95e0240..aa492cf1b0 100644
--- a/contrib/python/Jinja2/py3/tests/test_core_tags.py
+++ b/contrib/python/Jinja2/py3/tests/test_core_tags.py
@@ -1,41 +1,41 @@
import pytest
-
+
from jinja2 import DictLoader
from jinja2 import Environment
from jinja2 import TemplateRuntimeError
from jinja2 import TemplateSyntaxError
from jinja2 import UndefinedError
-
-
-@pytest.fixture
-def env_trim():
- return Environment(trim_blocks=True)
-
-
+
+
+@pytest.fixture
+def env_trim():
+ return Environment(trim_blocks=True)
+
+
class TestForLoop:
- def test_simple(self, env):
+ def test_simple(self, env):
tmpl = env.from_string("{% for item in seq %}{{ item }}{% endfor %}")
assert tmpl.render(seq=list(range(10))) == "0123456789"
-
- def test_else(self, env):
+
+ def test_else(self, env):
tmpl = env.from_string("{% for item in seq %}XXX{% else %}...{% endfor %}")
assert tmpl.render() == "..."
-
- def test_else_scoping_item(self, env):
+
+ def test_else_scoping_item(self, env):
tmpl = env.from_string("{% for item in [] %}{% else %}{{ item }}{% endfor %}")
assert tmpl.render(item=42) == "42"
-
- def test_empty_blocks(self, env):
+
+ def test_empty_blocks(self, env):
tmpl = env.from_string("<{% for item in seq %}{% else %}{% endfor %}>")
assert tmpl.render() == "<>"
-
- def test_context_vars(self, env):
- slist = [42, 24]
- for seq in [slist, iter(slist), reversed(slist), (_ for _ in slist)]:
+
+ def test_context_vars(self, env):
+ slist = [42, 24]
+ for seq in [slist, iter(slist), reversed(slist), (_ for _ in slist)]:
tmpl = env.from_string(
"""{% for item in seq -%}
- {{ loop.index }}|{{ loop.index0 }}|{{ loop.revindex }}|{{
- loop.revindex0 }}|{{ loop.first }}|{{ loop.last }}|{{
+ {{ loop.index }}|{{ loop.index0 }}|{{ loop.revindex }}|{{
+ loop.revindex0 }}|{{ loop.first }}|{{ loop.last }}|{{
loop.length }}###{% endfor %}"""
)
one, two, _ = tmpl.render(seq=seq).split("###")
@@ -57,61 +57,61 @@ class TestForLoop:
two_last,
two_length,
) = two.split("|")
-
- assert int(one_index) == 1 and int(two_index) == 2
- assert int(one_index0) == 0 and int(two_index0) == 1
- assert int(one_revindex) == 2 and int(two_revindex) == 1
- assert int(one_revindex0) == 1 and int(two_revindex0) == 0
+
+ assert int(one_index) == 1 and int(two_index) == 2
+ assert int(one_index0) == 0 and int(two_index0) == 1
+ assert int(one_revindex) == 2 and int(two_revindex) == 1
+ assert int(one_revindex0) == 1 and int(two_revindex0) == 0
assert one_first == "True" and two_first == "False"
assert one_last == "False" and two_last == "True"
assert one_length == two_length == "2"
-
- def test_cycling(self, env):
+
+ def test_cycling(self, env):
tmpl = env.from_string(
"""{% for item in seq %}{{
- loop.cycle('<1>', '<2>') }}{% endfor %}{%
+ loop.cycle('<1>', '<2>') }}{% endfor %}{%
for item in seq %}{{ loop.cycle(*through) }}{% endfor %}"""
)
output = tmpl.render(seq=list(range(4)), through=("<1>", "<2>"))
assert output == "<1><2>" * 4
-
- def test_lookaround(self, env):
+
+ def test_lookaround(self, env):
tmpl = env.from_string(
"""{% for item in seq -%}
- {{ loop.previtem|default('x') }}-{{ item }}-{{
- loop.nextitem|default('x') }}|
+ {{ loop.previtem|default('x') }}-{{ item }}-{{
+ loop.nextitem|default('x') }}|
{%- endfor %}"""
)
- output = tmpl.render(seq=list(range(4)))
+ output = tmpl.render(seq=list(range(4)))
assert output == "x-0-1|0-1-2|1-2-3|2-3-x|"
-
- def test_changed(self, env):
+
+ def test_changed(self, env):
tmpl = env.from_string(
"""{% for item in seq -%}
- {{ loop.changed(item) }},
+ {{ loop.changed(item) }},
{%- endfor %}"""
)
- output = tmpl.render(seq=[None, None, 1, 2, 2, 3, 4, 4, 4])
+ output = tmpl.render(seq=[None, None, 1, 2, 2, 3, 4, 4, 4])
assert output == "True,False,True,True,False,True,True,False,False,"
-
- def test_scope(self, env):
+
+ def test_scope(self, env):
tmpl = env.from_string("{% for item in seq %}{% endfor %}{{ item }}")
- output = tmpl.render(seq=list(range(10)))
- assert not output
-
- def test_varlen(self, env):
+ output = tmpl.render(seq=list(range(10)))
+ assert not output
+
+ def test_varlen(self, env):
tmpl = env.from_string("{% for item in iter %}{{ item }}{% endfor %}")
output = tmpl.render(iter=range(5))
assert output == "01234"
-
- def test_noniter(self, env):
+
+ def test_noniter(self, env):
tmpl = env.from_string("{% for item in none %}...{% endfor %}")
- pytest.raises(TypeError, tmpl.render)
-
- def test_recursive(self, env):
+ pytest.raises(TypeError, tmpl.render)
+
+ def test_recursive(self, env):
tmpl = env.from_string(
"""{% for item in seq recursive -%}
- [{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
+ [{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
{%- endfor %}"""
)
assert (
@@ -124,13 +124,13 @@ class TestForLoop:
)
== "[1<[1][2]>][2<[1][2]>][3<[a]>]"
)
-
- def test_recursive_lookaround(self, env):
+
+ def test_recursive_lookaround(self, env):
tmpl = env.from_string(
"""{% for item in seq recursive -%}
- [{{ loop.previtem.a if loop.previtem is defined else 'x' }}.{{
- item.a }}.{{ loop.nextitem.a if loop.nextitem is defined else 'x'
- }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
+ [{{ loop.previtem.a if loop.previtem is defined else 'x' }}.{{
+ item.a }}.{{ loop.nextitem.a if loop.nextitem is defined else 'x'
+ }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
{%- endfor %}"""
)
assert (
@@ -143,8 +143,8 @@ class TestForLoop:
)
== "[x.1.2<[x.1.2][1.2.x]>][1.2.3<[x.1.2][1.2.x]>][2.3.x<[x.a.x]>]"
)
-
- def test_recursive_depth0(self, env):
+
+ def test_recursive_depth0(self, env):
tmpl = env.from_string(
"""{% for item in seq recursive -%}
[{{ loop.depth0 }}:{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
@@ -160,8 +160,8 @@ class TestForLoop:
)
== "[0:1<[1:1][1:2]>][0:2<[1:1][1:2]>][0:3<[1:a]>]"
)
-
- def test_recursive_depth(self, env):
+
+ def test_recursive_depth(self, env):
tmpl = env.from_string(
"""{% for item in seq recursive -%}
[{{ loop.depth }}:{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
@@ -177,63 +177,63 @@ class TestForLoop:
)
== "[1:1<[2:1][2:2]>][1:2<[2:1][2:2]>][1:3<[2:a]>]"
)
-
- def test_looploop(self, env):
+
+ def test_looploop(self, env):
tmpl = env.from_string(
"""{% for row in table %}
- {%- set rowloop = loop -%}
- {% for cell in row -%}
- [{{ rowloop.index }}|{{ loop.index }}]
- {%- endfor %}
+ {%- set rowloop = loop -%}
+ {% for cell in row -%}
+ [{{ rowloop.index }}|{{ loop.index }}]
+ {%- endfor %}
{%- endfor %}"""
)
assert tmpl.render(table=["ab", "cd"]) == "[1|1][1|2][2|1][2|2]"
-
- def test_reversed_bug(self, env):
+
+ def test_reversed_bug(self, env):
tmpl = env.from_string(
"{% for i in items %}{{ i }}"
"{% if not loop.last %}"
",{% endif %}{% endfor %}"
)
assert tmpl.render(items=reversed([3, 2, 1])) == "1,2,3"
-
- def test_loop_errors(self, env):
+
+ def test_loop_errors(self, env):
tmpl = env.from_string(
"""{% for item in [1] if loop.index
== 0 %}...{% endfor %}"""
)
- pytest.raises(UndefinedError, tmpl.render)
+ pytest.raises(UndefinedError, tmpl.render)
tmpl = env.from_string(
"""{% for item in [] %}...{% else
%}{{ loop }}{% endfor %}"""
)
assert tmpl.render() == ""
-
- def test_loop_filter(self, env):
+
+ def test_loop_filter(self, env):
tmpl = env.from_string(
"{% for item in range(10) if item is even %}[{{ item }}]{% endfor %}"
)
assert tmpl.render() == "[0][2][4][6][8]"
tmpl = env.from_string(
"""
- {%- for item in range(10) if item is even %}[{{
+ {%- for item in range(10) if item is even %}[{{
loop.index }}:{{ item }}]{% endfor %}"""
)
assert tmpl.render() == "[1:0][2:2][3:4][4:6][5:8]"
-
- def test_loop_unassignable(self, env):
+
+ def test_loop_unassignable(self, env):
pytest.raises(
TemplateSyntaxError, env.from_string, "{% for loop in seq %}...{% endfor %}"
)
-
- def test_scoped_special_var(self, env):
- t = env.from_string(
+
+ def test_scoped_special_var(self, env):
+ t = env.from_string(
"{% for s in seq %}[{{ loop.first }}{% for c in s %}"
"|{{ loop.first }}{% endfor %}]{% endfor %}"
)
assert t.render(seq=("ab", "cd")) == "[True|True|False][False|True|False]"
-
- def test_scoped_loop_var(self, env):
+
+ def test_scoped_loop_var(self, env):
t = env.from_string(
"{% for x in seq %}{{ loop.first }}"
"{% for y in seq %}{% endfor %}{% endfor %}"
@@ -244,276 +244,276 @@ class TestForLoop:
"{{ loop.first }}{% endfor %}{% endfor %}"
)
assert t.render(seq="ab") == "TrueFalseTrueFalse"
-
- def test_recursive_empty_loop_iter(self, env):
+
+ def test_recursive_empty_loop_iter(self, env):
t = env.from_string(
"""
- {%- for item in foo recursive -%}{%- endfor -%}
+ {%- for item in foo recursive -%}{%- endfor -%}
"""
)
assert t.render(dict(foo=[])) == ""
-
- def test_call_in_loop(self, env):
+
+ def test_call_in_loop(self, env):
t = env.from_string(
"""
- {%- macro do_something() -%}
- [{{ caller() }}]
- {%- endmacro %}
-
- {%- for i in [1, 2, 3] %}
- {%- call do_something() -%}
- {{ i }}
- {%- endcall %}
- {%- endfor -%}
+ {%- macro do_something() -%}
+ [{{ caller() }}]
+ {%- endmacro %}
+
+ {%- for i in [1, 2, 3] %}
+ {%- call do_something() -%}
+ {{ i }}
+ {%- endcall %}
+ {%- endfor -%}
"""
)
assert t.render() == "[1][2][3]"
-
- def test_scoping_bug(self, env):
+
+ def test_scoping_bug(self, env):
t = env.from_string(
"""
- {%- for item in foo %}...{{ item }}...{% endfor %}
- {%- macro item(a) %}...{{ a }}...{% endmacro %}
- {{- item(2) -}}
+ {%- for item in foo %}...{{ item }}...{% endfor %}
+ {%- macro item(a) %}...{{ a }}...{% endmacro %}
+ {{- item(2) -}}
"""
)
assert t.render(foo=(1,)) == "...1......2..."
-
- def test_unpacking(self, env):
+
+ def test_unpacking(self, env):
tmpl = env.from_string(
"{% for a, b, c in [[1, 2, 3]] %}{{ a }}|{{ b }}|{{ c }}{% endfor %}"
)
assert tmpl.render() == "1|2|3"
-
- def test_intended_scoping_with_set(self, env):
+
+ def test_intended_scoping_with_set(self, env):
tmpl = env.from_string(
"{% for item in seq %}{{ x }}{% set x = item %}{{ x }}{% endfor %}"
)
assert tmpl.render(x=0, seq=[1, 2, 3]) == "010203"
-
+
tmpl = env.from_string(
"{% set x = 9 %}{% for item in seq %}{{ x }}"
"{% set x = item %}{{ x }}{% endfor %}"
)
assert tmpl.render(x=0, seq=[1, 2, 3]) == "919293"
-
-
+
+
class TestIfCondition:
- def test_simple(self, env):
+ def test_simple(self, env):
tmpl = env.from_string("""{% if true %}...{% endif %}""")
assert tmpl.render() == "..."
-
- def test_elif(self, env):
+
+ def test_elif(self, env):
tmpl = env.from_string(
"""{% if false %}XXX{% elif true
%}...{% else %}XXX{% endif %}"""
)
assert tmpl.render() == "..."
-
- def test_elif_deep(self, env):
+
+ def test_elif_deep(self, env):
elifs = "\n".join(f"{{% elif a == {i} %}}{i}" for i in range(1, 1000))
tmpl = env.from_string(f"{{% if a == 0 %}}0{elifs}{{% else %}}x{{% endif %}}")
- for x in (0, 10, 999):
- assert tmpl.render(a=x).strip() == str(x)
+ for x in (0, 10, 999):
+ assert tmpl.render(a=x).strip() == str(x)
assert tmpl.render(a=1000).strip() == "x"
-
- def test_else(self, env):
+
+ def test_else(self, env):
tmpl = env.from_string("{% if false %}XXX{% else %}...{% endif %}")
assert tmpl.render() == "..."
-
- def test_empty(self, env):
+
+ def test_empty(self, env):
tmpl = env.from_string("[{% if true %}{% else %}{% endif %}]")
assert tmpl.render() == "[]"
-
- def test_complete(self, env):
+
+ def test_complete(self, env):
tmpl = env.from_string(
"{% if a %}A{% elif b %}B{% elif c == d %}C{% else %}D{% endif %}"
)
assert tmpl.render(a=0, b=False, c=42, d=42.0) == "C"
-
- def test_no_scope(self, env):
+
+ def test_no_scope(self, env):
tmpl = env.from_string("{% if a %}{% set foo = 1 %}{% endif %}{{ foo }}")
assert tmpl.render(a=True) == "1"
tmpl = env.from_string("{% if true %}{% set foo = 1 %}{% endif %}{{ foo }}")
assert tmpl.render() == "1"
-
-
+
+
class TestMacros:
- def test_simple(self, env_trim):
+ def test_simple(self, env_trim):
tmpl = env_trim.from_string(
"""\
-{% macro say_hello(name) %}Hello {{ name }}!{% endmacro %}
+{% macro say_hello(name) %}Hello {{ name }}!{% endmacro %}
{{ say_hello('Peter') }}"""
)
assert tmpl.render() == "Hello Peter!"
-
- def test_scoping(self, env_trim):
+
+ def test_scoping(self, env_trim):
tmpl = env_trim.from_string(
"""\
-{% macro level1(data1) %}
-{% macro level2(data2) %}{{ data1 }}|{{ data2 }}{% endmacro %}
-{{ level2('bar') }}{% endmacro %}
+{% macro level1(data1) %}
+{% macro level2(data2) %}{{ data1 }}|{{ data2 }}{% endmacro %}
+{{ level2('bar') }}{% endmacro %}
{{ level1('foo') }}"""
)
assert tmpl.render() == "foo|bar"
-
- def test_arguments(self, env_trim):
+
+ def test_arguments(self, env_trim):
tmpl = env_trim.from_string(
"""\
-{% macro m(a, b, c='c', d='d') %}{{ a }}|{{ b }}|{{ c }}|{{ d }}{% endmacro %}
+{% macro m(a, b, c='c', d='d') %}{{ a }}|{{ b }}|{{ c }}|{{ d }}{% endmacro %}
{{ m() }}|{{ m('a') }}|{{ m('a', 'b') }}|{{ m(1, 2, 3) }}"""
)
assert tmpl.render() == "||c|d|a||c|d|a|b|c|d|1|2|3|d"
-
- def test_arguments_defaults_nonsense(self, env_trim):
+
+ def test_arguments_defaults_nonsense(self, env_trim):
pytest.raises(
TemplateSyntaxError,
env_trim.from_string,
"""\
{% macro m(a, b=1, c) %}a={{ a }}, b={{ b }}, c={{ c }}{% endmacro %}""",
)
-
- def test_caller_defaults_nonsense(self, env_trim):
+
+ def test_caller_defaults_nonsense(self, env_trim):
pytest.raises(
TemplateSyntaxError,
env_trim.from_string,
"""\
-{% macro a() %}{{ caller() }}{% endmacro %}
+{% macro a() %}{{ caller() }}{% endmacro %}
{% call(x, y=1, z) a() %}{% endcall %}""",
)
-
- def test_varargs(self, env_trim):
+
+ def test_varargs(self, env_trim):
tmpl = env_trim.from_string(
"""\
-{% macro test() %}{{ varargs|join('|') }}{% endmacro %}\
+{% macro test() %}{{ varargs|join('|') }}{% endmacro %}\
{{ test(1, 2, 3) }}"""
)
assert tmpl.render() == "1|2|3"
-
- def test_simple_call(self, env_trim):
+
+ def test_simple_call(self, env_trim):
tmpl = env_trim.from_string(
"""\
-{% macro test() %}[[{{ caller() }}]]{% endmacro %}\
+{% macro test() %}[[{{ caller() }}]]{% endmacro %}\
{% call test() %}data{% endcall %}"""
)
assert tmpl.render() == "[[data]]"
-
- def test_complex_call(self, env_trim):
+
+ def test_complex_call(self, env_trim):
tmpl = env_trim.from_string(
"""\
-{% macro test() %}[[{{ caller('data') }}]]{% endmacro %}\
+{% macro test() %}[[{{ caller('data') }}]]{% endmacro %}\
{% call(data) test() %}{{ data }}{% endcall %}"""
)
assert tmpl.render() == "[[data]]"
-
- def test_caller_undefined(self, env_trim):
+
+ def test_caller_undefined(self, env_trim):
tmpl = env_trim.from_string(
"""\
-{% set caller = 42 %}\
-{% macro test() %}{{ caller is not defined }}{% endmacro %}\
+{% set caller = 42 %}\
+{% macro test() %}{{ caller is not defined }}{% endmacro %}\
{{ test() }}"""
)
assert tmpl.render() == "True"
-
- def test_include(self, env_trim):
- env_trim = Environment(
+
+ def test_include(self, env_trim):
+ env_trim = Environment(
loader=DictLoader(
{"include": "{% macro test(foo) %}[{{ foo }}]{% endmacro %}"}
)
- )
+ )
tmpl = env_trim.from_string('{% from "include" import test %}{{ test("foo") }}')
assert tmpl.render() == "[foo]"
-
- def test_macro_api(self, env_trim):
- tmpl = env_trim.from_string(
+
+ def test_macro_api(self, env_trim):
+ tmpl = env_trim.from_string(
"{% macro foo(a, b) %}{% endmacro %}"
"{% macro bar() %}{{ varargs }}{{ kwargs }}{% endmacro %}"
"{% macro baz() %}{{ caller() }}{% endmacro %}"
)
assert tmpl.module.foo.arguments == ("a", "b")
assert tmpl.module.foo.name == "foo"
- assert not tmpl.module.foo.caller
- assert not tmpl.module.foo.catch_kwargs
- assert not tmpl.module.foo.catch_varargs
- assert tmpl.module.bar.arguments == ()
- assert not tmpl.module.bar.caller
- assert tmpl.module.bar.catch_kwargs
- assert tmpl.module.bar.catch_varargs
- assert tmpl.module.baz.caller
-
- def test_callself(self, env_trim):
+ assert not tmpl.module.foo.caller
+ assert not tmpl.module.foo.catch_kwargs
+ assert not tmpl.module.foo.catch_varargs
+ assert tmpl.module.bar.arguments == ()
+ assert not tmpl.module.bar.caller
+ assert tmpl.module.bar.catch_kwargs
+ assert tmpl.module.bar.catch_varargs
+ assert tmpl.module.baz.caller
+
+ def test_callself(self, env_trim):
tmpl = env_trim.from_string(
"{% macro foo(x) %}{{ x }}{% if x > 1 %}|"
"{{ foo(x - 1) }}{% endif %}{% endmacro %}"
"{{ foo(5) }}"
)
assert tmpl.render() == "5|4|3|2|1"
-
- def test_macro_defaults_self_ref(self, env):
+
+ def test_macro_defaults_self_ref(self, env):
tmpl = env.from_string(
"""
- {%- set x = 42 %}
- {%- macro m(a, b=x, x=23) %}{{ a }}|{{ b }}|{{ x }}{% endmacro -%}
+ {%- set x = 42 %}
+ {%- macro m(a, b=x, x=23) %}{{ a }}|{{ b }}|{{ x }}{% endmacro -%}
"""
)
assert tmpl.module.m(1) == "1||23"
assert tmpl.module.m(1, 2) == "1|2|23"
assert tmpl.module.m(1, 2, 3) == "1|2|3"
assert tmpl.module.m(1, x=7) == "1|7|7"
-
-
+
+
class TestSet:
- def test_normal(self, env_trim):
+ def test_normal(self, env_trim):
tmpl = env_trim.from_string("{% set foo = 1 %}{{ foo }}")
assert tmpl.render() == "1"
- assert tmpl.module.foo == 1
-
- def test_block(self, env_trim):
+ assert tmpl.module.foo == 1
+
+ def test_block(self, env_trim):
tmpl = env_trim.from_string("{% set foo %}42{% endset %}{{ foo }}")
assert tmpl.render() == "42"
assert tmpl.module.foo == "42"
-
- def test_block_escaping(self):
- env = Environment(autoescape=True)
+
+ def test_block_escaping(self):
+ env = Environment(autoescape=True)
tmpl = env.from_string(
"{% set foo %}<em>{{ test }}</em>{% endset %}foo: {{ foo }}"
)
assert tmpl.render(test="<unsafe>") == "foo: <em>&lt;unsafe&gt;</em>"
-
- def test_set_invalid(self, env_trim):
+
+ def test_set_invalid(self, env_trim):
pytest.raises(
TemplateSyntaxError, env_trim.from_string, "{% set foo['bar'] = 1 %}"
)
tmpl = env_trim.from_string("{% set foo.bar = 1 %}")
- exc_info = pytest.raises(TemplateRuntimeError, tmpl.render, foo={})
+ exc_info = pytest.raises(TemplateRuntimeError, tmpl.render, foo={})
assert "non-namespace object" in exc_info.value.message
-
- def test_namespace_redefined(self, env_trim):
+
+ def test_namespace_redefined(self, env_trim):
tmpl = env_trim.from_string("{% set ns = namespace() %}{% set ns.bar = 'hi' %}")
exc_info = pytest.raises(TemplateRuntimeError, tmpl.render, namespace=dict)
assert "non-namespace object" in exc_info.value.message
-
- def test_namespace(self, env_trim):
+
+ def test_namespace(self, env_trim):
tmpl = env_trim.from_string(
"{% set ns = namespace() %}{% set ns.bar = '42' %}{{ ns.bar }}"
)
assert tmpl.render() == "42"
-
- def test_namespace_block(self, env_trim):
+
+ def test_namespace_block(self, env_trim):
tmpl = env_trim.from_string(
"{% set ns = namespace() %}{% set ns.bar %}42{% endset %}{{ ns.bar }}"
)
assert tmpl.render() == "42"
-
- def test_init_namespace(self, env_trim):
+
+ def test_init_namespace(self, env_trim):
tmpl = env_trim.from_string(
"{% set ns = namespace(d, self=37) %}"
"{% set ns.b = 42 %}"
"{{ ns.a }}|{{ ns.self }}|{{ ns.b }}"
)
assert tmpl.render(d={"a": 13}) == "13|37|42"
-
- def test_namespace_loop(self, env_trim):
+
+ def test_namespace_loop(self, env_trim):
tmpl = env_trim.from_string(
"{% set ns = namespace(found=false) %}"
"{% for x in range(4) %}"
@@ -525,8 +525,8 @@ class TestSet:
)
assert tmpl.render(v=3) == "True"
assert tmpl.render(v=4) == "False"
-
- def test_namespace_macro(self, env_trim):
+
+ def test_namespace_macro(self, env_trim):
tmpl = env_trim.from_string(
"{% set ns = namespace() %}"
"{% set ns.a = 13 %}"
@@ -537,59 +537,59 @@ class TestSet:
"{{ ns.a }}|{{ ns.b }}"
)
assert tmpl.render() == "13|37"
-
- def test_block_escaping_filtered(self):
- env = Environment(autoescape=True)
+
+ def test_block_escaping_filtered(self):
+ env = Environment(autoescape=True)
tmpl = env.from_string(
"{% set foo | trim %}<em>{{ test }}</em> {% endset %}foo: {{ foo }}"
)
assert tmpl.render(test="<unsafe>") == "foo: <em>&lt;unsafe&gt;</em>"
-
- def test_block_filtered(self, env_trim):
- tmpl = env_trim.from_string(
+
+ def test_block_filtered(self, env_trim):
+ tmpl = env_trim.from_string(
"{% set foo | trim | length | string %} 42 {% endset %}{{ foo }}"
)
assert tmpl.render() == "2"
assert tmpl.module.foo == "2"
-
- def test_block_filtered_set(self, env_trim):
- def _myfilter(val, arg):
+
+ def test_block_filtered_set(self, env_trim):
+ def _myfilter(val, arg):
assert arg == " xxx "
- return val
+ return val
env_trim.filters["myfilter"] = _myfilter
- tmpl = env_trim.from_string(
- '{% set a = " xxx " %}'
+ tmpl = env_trim.from_string(
+ '{% set a = " xxx " %}'
"{% set foo | myfilter(a) | trim | length | string %}"
- ' {% set b = " yy " %} 42 {{ a }}{{ b }} '
+ ' {% set b = " yy " %} 42 {{ a }}{{ b }} '
"{% endset %}"
"{{ foo }}"
)
assert tmpl.render() == "11"
assert tmpl.module.foo == "11"
-
-
+
+
class TestWith:
- def test_with(self, env):
+ def test_with(self, env):
tmpl = env.from_string(
"""\
- {% with a=42, b=23 -%}
- {{ a }} = {{ b }}
- {% endwith -%}
- {{ a }} = {{ b }}\
+ {% with a=42, b=23 -%}
+ {{ a }} = {{ b }}
+ {% endwith -%}
+ {{ a }} = {{ b }}\
"""
)
assert [x.strip() for x in tmpl.render(a=1, b=2).splitlines()] == [
"42 = 23",
"1 = 2",
]
-
- def test_with_argument_scoping(self, env):
+
+ def test_with_argument_scoping(self, env):
tmpl = env.from_string(
"""\
- {%- with a=1, b=2, c=b, d=e, e=5 -%}
- {{ a }}|{{ b }}|{{ c }}|{{ d }}|{{ e }}
- {%- endwith -%}
+ {%- with a=1, b=2, c=b, d=e, e=5 -%}
+ {{ a }}|{{ b }}|{{ c }}|{{ d }}|{{ e }}
+ {%- endwith -%}
"""
)
assert tmpl.render(b=3, e=4) == "1|2|3|4|5"
diff --git a/contrib/python/Jinja2/py3/tests/test_debug.py b/contrib/python/Jinja2/py3/tests/test_debug.py
index 1cb931cfc1..bcb99afe91 100644
--- a/contrib/python/Jinja2/py3/tests/test_debug.py
+++ b/contrib/python/Jinja2/py3/tests/test_debug.py
@@ -1,79 +1,79 @@
import pickle
import re
from traceback import format_exception
-
-import pytest
-
+
+import pytest
+
from jinja2 import ChoiceLoader
from jinja2 import DictLoader
from jinja2 import Environment
from jinja2 import TemplateSyntaxError
-
-
-@pytest.fixture
-def fs_env(filesystem_loader):
+
+
+@pytest.fixture
+def fs_env(filesystem_loader):
"""returns a new environment."""
- return Environment(loader=filesystem_loader)
-
-
+ return Environment(loader=filesystem_loader)
+
+
class TestDebug:
- def assert_traceback_matches(self, callback, expected_tb):
+ def assert_traceback_matches(self, callback, expected_tb):
with pytest.raises(Exception) as exc_info:
- callback()
-
+ callback()
+
tb = format_exception(exc_info.type, exc_info.value, exc_info.tb)
m = re.search(expected_tb.strip(), "".join(tb))
assert (
m is not None
), "Traceback did not match:\n\n{''.join(tb)}\nexpected:\n{expected_tb}"
- def test_runtime_error(self, fs_env):
- def test():
- tmpl.render(fail=lambda: 1 / 0)
+ def test_runtime_error(self, fs_env):
+ def test():
+ tmpl.render(fail=lambda: 1 / 0)
tmpl = fs_env.get_template("broken.html")
self.assert_traceback_matches(
test,
r"""
- File ".*?broken.html", line 2, in (top-level template code|<module>)
+ File ".*?broken.html", line 2, in (top-level template code|<module>)
\{\{ fail\(\) \}\}(
\^{12})?
- File ".*debug?.pyc?", line \d+, in <lambda>
+ File ".*debug?.pyc?", line \d+, in <lambda>
tmpl\.render\(fail=lambda: 1 / 0\)(
~~\^~~)?
-ZeroDivisionError: (int(eger)? )?division (or modulo )?by zero
+ZeroDivisionError: (int(eger)? )?division (or modulo )?by zero
""",
)
-
- def test_syntax_error(self, fs_env):
+
+ def test_syntax_error(self, fs_env):
# The trailing .*? is for PyPy 2 and 3, which don't seem to
# clear the exception's original traceback, leaving the syntax
# error in the middle of other compiler frames.
self.assert_traceback_matches(
lambda: fs_env.get_template("syntaxerror.html"),
"""(?sm)
- File ".*?syntaxerror.html", line 4, in (template|<module>)
+ File ".*?syntaxerror.html", line 4, in (template|<module>)
\\{% endif %\\}.*?
(jinja2\\.exceptions\\.)?TemplateSyntaxError: Encountered unknown tag 'endif'. Jinja \
was looking for the following tags: 'endfor' or 'else'. The innermost block that needs \
to be closed is 'for'.
""",
)
-
- def test_regular_syntax_error(self, fs_env):
- def test():
+
+ def test_regular_syntax_error(self, fs_env):
+ def test():
raise TemplateSyntaxError("wtf", 42)
self.assert_traceback_matches(
test,
r"""
- File ".*debug.pyc?", line \d+, in test
+ File ".*debug.pyc?", line \d+, in test
raise TemplateSyntaxError\("wtf", 42\)(
\^{36})?
-(jinja2\.exceptions\.)?TemplateSyntaxError: wtf
+(jinja2\.exceptions\.)?TemplateSyntaxError: wtf
line 42""",
)
-
+
def test_pickleable_syntax_error(self, fs_env):
original = TemplateSyntaxError("bad template", 42, "test", "test.txt")
unpickled = pickle.loads(pickle.dumps(original))
@@ -96,9 +96,9 @@ to be closed is 'for'.
assert exc_info.value.source is not None
- def test_local_extraction(self):
+ def test_local_extraction(self):
from jinja2.debug import get_template_locals
- from jinja2.runtime import missing
+ from jinja2.runtime import missing
locals = get_template_locals(
{
diff --git a/contrib/python/Jinja2/py3/tests/test_ext.py b/contrib/python/Jinja2/py3/tests/test_ext.py
index b54e905ffd..455379a9ae 100644
--- a/contrib/python/Jinja2/py3/tests/test_ext.py
+++ b/contrib/python/Jinja2/py3/tests/test_ext.py
@@ -1,23 +1,23 @@
import re
from io import BytesIO
-
-import pytest
-
+
+import pytest
+
from jinja2 import DictLoader
from jinja2 import Environment
from jinja2 import nodes
from jinja2 import pass_context
-from jinja2.exceptions import TemplateAssertionError
-from jinja2.ext import Extension
+from jinja2.exceptions import TemplateAssertionError
+from jinja2.ext import Extension
from jinja2.lexer import count_newlines
from jinja2.lexer import Token
-
-importable_object = 23
-
+
+importable_object = 23
+
_gettext_re = re.compile(r"_\((.*?)\)", re.DOTALL)
-
-
-i18n_templates = {
+
+
+i18n_templates = {
"default.html": '<title>{{ page_title|default(_("missing")) }}</title>'
"{% block body %}{% endblock %}",
"child.html": '{% extends "default.html" %}{% block body %}'
@@ -27,9 +27,9 @@ i18n_templates = {
"plural2.html": "{% trans user_count=get_user_count() %}{{ user_count }}s"
"{% pluralize %}{{ user_count }}p{% endtrans %}",
"stringformat.html": '{{ _("User: %(num)s")|format(num=user_count) }}',
-}
-
-newstyle_i18n_templates = {
+}
+
+newstyle_i18n_templates = {
"default.html": '<title>{{ page_title|default(_("missing")) }}</title>'
"{% block body %}{% endblock %}",
"child.html": '{% extends "default.html" %}{% block body %}'
@@ -49,10 +49,10 @@ newstyle_i18n_templates = {
"novars.html": "{% trans %}%(hello)s{% endtrans %}",
"vars.html": "{% trans %}{{ foo }}%(foo)s{% endtrans %}",
"explicitvars.html": '{% trans foo="42" %}%(foo)s{% endtrans %}',
-}
-
-
-languages = {
+}
+
+
+languages = {
"de": {
"missing": "fehlend",
"watch out": "pass auf",
@@ -63,10 +63,10 @@ languages = {
"Apple": {None: "Apfel", "fruit": "Apple"},
"%(num)s apple": {None: "%(num)s Apfel", "fruit": "%(num)s Apple"},
"%(num)s apples": {None: "%(num)s Äpfel", "fruit": "%(num)s Apples"},
- }
-}
-
-
+ }
+}
+
+
def _get_with_context(value, ctx=None):
if isinstance(value, dict):
return value.get(ctx, value)
@@ -75,23 +75,23 @@ def _get_with_context(value, ctx=None):
@pass_context
-def gettext(context, string):
+def gettext(context, string):
language = context.get("LANGUAGE", "en")
value = languages.get(language, {}).get(string, string)
return _get_with_context(value)
-
-
+
+
@pass_context
-def ngettext(context, s, p, n):
+def ngettext(context, s, p, n):
language = context.get("LANGUAGE", "en")
- if n != 1:
+ if n != 1:
value = languages.get(language, {}).get(p, p)
return _get_with_context(value)
-
+
value = languages.get(language, {}).get(s, s)
return _get_with_context(value)
-
+
@pass_context
def pgettext(context, c, s):
@@ -112,9 +112,9 @@ def npgettext(context, c, s, p, n):
return _get_with_context(value, c)
-i18n_env = Environment(
+i18n_env = Environment(
loader=DictLoader(i18n_templates), extensions=["jinja2.ext.i18n"]
-)
+)
i18n_env.globals.update(
{
"_": gettext,
@@ -136,21 +136,21 @@ i18n_env_trimmed.globals.update(
"npgettext": npgettext,
}
)
-
-newstyle_i18n_env = Environment(
+
+newstyle_i18n_env = Environment(
loader=DictLoader(newstyle_i18n_templates), extensions=["jinja2.ext.i18n"]
-)
+)
newstyle_i18n_env.install_gettext_callables( # type: ignore
gettext, ngettext, newstyle=True, pgettext=pgettext, npgettext=npgettext
)
-
-
-class ExampleExtension(Extension):
+
+
+class ExampleExtension(Extension):
tags = {"test"}
- ext_attr = 42
+ ext_attr = 42
context_reference_node_cls = nodes.ContextReference
-
- def parse(self, parser):
+
+ def parse(self, parser):
return nodes.Output(
[
self.call_method(
@@ -164,97 +164,97 @@ class ExampleExtension(Extension):
)
]
).set_lineno(next(parser.stream).lineno)
-
- def _dump(self, sandboxed, ext_attr, imported_object, context):
+
+ def _dump(self, sandboxed, ext_attr, imported_object, context):
return (
f"{sandboxed}|{ext_attr}|{imported_object}|{context.blocks}"
f"|{context.get('test_var')}"
- )
-
-
+ )
+
+
class DerivedExampleExtension(ExampleExtension):
context_reference_node_cls = nodes.DerivedContextReference # type: ignore
-class PreprocessorExtension(Extension):
- def preprocess(self, source, name, filename=None):
+class PreprocessorExtension(Extension):
+ def preprocess(self, source, name, filename=None):
return source.replace("[[TEST]]", "({{ foo }})")
-
-
-class StreamFilterExtension(Extension):
- def filter_stream(self, stream):
- for token in stream:
+
+
+class StreamFilterExtension(Extension):
+ def filter_stream(self, stream):
+ for token in stream:
if token.type == "data":
yield from self.interpolate(token)
- else:
- yield token
-
- def interpolate(self, token):
- pos = 0
- end = len(token.value)
- lineno = token.lineno
+ else:
+ yield token
+
+ def interpolate(self, token):
+ pos = 0
+ end = len(token.value)
+ lineno = token.lineno
while True:
- match = _gettext_re.search(token.value, pos)
- if match is None:
- break
+ match = _gettext_re.search(token.value, pos)
+ if match is None:
+ break
value = token.value[pos : match.start()]
- if value:
+ if value:
yield Token(lineno, "data", value)
- lineno += count_newlines(token.value)
+ lineno += count_newlines(token.value)
yield Token(lineno, "variable_begin", None)
yield Token(lineno, "name", "gettext")
yield Token(lineno, "lparen", None)
yield Token(lineno, "string", match.group(1))
yield Token(lineno, "rparen", None)
yield Token(lineno, "variable_end", None)
- pos = match.end()
- if pos < end:
+ pos = match.end()
+ if pos < end:
yield Token(lineno, "data", token.value[pos:])
-
-
+
+
class TestExtensions:
- def test_extend_late(self):
- env = Environment()
+ def test_extend_late(self):
+ env = Environment()
t = env.from_string('{% autoescape true %}{{ "<test>" }}{% endautoescape %}')
assert t.render() == "&lt;test&gt;"
-
- def test_loop_controls(self):
+
+ def test_loop_controls(self):
env = Environment(extensions=["jinja2.ext.loopcontrols"])
-
+
tmpl = env.from_string(
"""
- {%- for item in [1, 2, 3, 4] %}
- {%- if item % 2 == 0 %}{% continue %}{% endif -%}
- {{ item }}
+ {%- for item in [1, 2, 3, 4] %}
+ {%- if item % 2 == 0 %}{% continue %}{% endif -%}
+ {{ item }}
{%- endfor %}"""
)
assert tmpl.render() == "13"
-
+
tmpl = env.from_string(
"""
- {%- for item in [1, 2, 3, 4] %}
- {%- if item > 2 %}{% break %}{% endif -%}
- {{ item }}
+ {%- for item in [1, 2, 3, 4] %}
+ {%- if item > 2 %}{% break %}{% endif -%}
+ {{ item }}
{%- endfor %}"""
)
assert tmpl.render() == "12"
-
- def test_do(self):
+
+ def test_do(self):
env = Environment(extensions=["jinja2.ext.do"])
tmpl = env.from_string(
"""
- {%- set items = [] %}
- {%- for char in "foo" %}
- {%- do items.append(loop.index0 ~ char) %}
+ {%- set items = [] %}
+ {%- for char in "foo" %}
+ {%- do items.append(loop.index0 ~ char) %}
{%- endfor %}{{ items|join(', ') }}"""
)
assert tmpl.render() == "0f, 1o, 2o"
-
- def test_extension_nodes(self):
- env = Environment(extensions=[ExampleExtension])
+
+ def test_extension_nodes(self):
+ env = Environment(extensions=[ExampleExtension])
tmpl = env.from_string("{% test %}")
assert tmpl.render() == "False|42|23|{}|None"
-
+
def test_contextreference_node_passes_context(self):
env = Environment(extensions=[ExampleExtension])
tmpl = env.from_string('{% set test_var="test_content" %}{% test %}')
@@ -267,72 +267,72 @@ class TestExtensions:
)
assert tmpl.render() == "False|42|23|{}|test_content"
- def test_identifier(self):
+ def test_identifier(self):
assert ExampleExtension.identifier == __name__ + ".ExampleExtension"
-
- def test_rebinding(self):
- original = Environment(extensions=[ExampleExtension])
- overlay = original.overlay()
- for env in original, overlay:
+
+ def test_rebinding(self):
+ original = Environment(extensions=[ExampleExtension])
+ overlay = original.overlay()
+ for env in original, overlay:
for ext in env.extensions.values():
- assert ext.environment is env
-
- def test_preprocessor_extension(self):
- env = Environment(extensions=[PreprocessorExtension])
+ assert ext.environment is env
+
+ def test_preprocessor_extension(self):
+ env = Environment(extensions=[PreprocessorExtension])
tmpl = env.from_string("{[[TEST]]}")
assert tmpl.render(foo=42) == "{(42)}"
-
- def test_streamfilter_extension(self):
- env = Environment(extensions=[StreamFilterExtension])
+
+ def test_streamfilter_extension(self):
+ env = Environment(extensions=[StreamFilterExtension])
env.globals["gettext"] = lambda x: x.upper()
tmpl = env.from_string("Foo _(bar) Baz")
- out = tmpl.render()
+ out = tmpl.render()
assert out == "Foo BAR Baz"
-
- def test_extension_ordering(self):
- class T1(Extension):
- priority = 1
-
- class T2(Extension):
- priority = 2
-
- env = Environment(extensions=[T1, T2])
- ext = list(env.iter_extensions())
- assert ext[0].__class__ is T1
- assert ext[1].__class__ is T2
-
+
+ def test_extension_ordering(self):
+ class T1(Extension):
+ priority = 1
+
+ class T2(Extension):
+ priority = 2
+
+ env = Environment(extensions=[T1, T2])
+ ext = list(env.iter_extensions())
+ assert ext[0].__class__ is T1
+ assert ext[1].__class__ is T2
+
def test_debug(self):
env = Environment(extensions=["jinja2.ext.debug"])
t = env.from_string("Hello\n{% debug %}\nGoodbye")
out = t.render()
-
+
for value in ("context", "cycler", "filters", "abs", "tests", "!="):
assert f"'{value}'" in out
class TestInternationalization:
- def test_trans(self):
+ def test_trans(self):
tmpl = i18n_env.get_template("child.html")
assert tmpl.render(LANGUAGE="de") == "<title>fehlend</title>pass auf"
-
- def test_trans_plural(self):
+
+ def test_trans_plural(self):
tmpl = i18n_env.get_template("plural.html")
assert tmpl.render(LANGUAGE="de", user_count=1) == "Ein Benutzer online"
assert tmpl.render(LANGUAGE="de", user_count=2) == "2 Benutzer online"
-
- def test_trans_plural_with_functions(self):
+
+ def test_trans_plural_with_functions(self):
tmpl = i18n_env.get_template("plural2.html")
+
+ def get_user_count():
+ get_user_count.called += 1
+ return 1
- def get_user_count():
- get_user_count.called += 1
- return 1
-
- get_user_count.called = 0
+ get_user_count.called = 0
assert tmpl.render(LANGUAGE="de", get_user_count=get_user_count) == "1s"
- assert get_user_count.called == 1
-
- def test_complex_plural(self):
- tmpl = i18n_env.from_string(
+ assert get_user_count.called == 1
+
+ def test_complex_plural(self):
+ tmpl = i18n_env.from_string(
"{% trans foo=42, count=2 %}{{ count }} item{% "
"pluralize count %}{{ count }} items{% endtrans %}"
)
@@ -342,46 +342,46 @@ class TestInternationalization:
i18n_env.from_string,
"{% trans foo %}...{% pluralize bar %}...{% endtrans %}",
)
-
- def test_trans_stringformatting(self):
+
+ def test_trans_stringformatting(self):
tmpl = i18n_env.get_template("stringformat.html")
assert tmpl.render(LANGUAGE="de", user_count=5) == "Benutzer: 5"
-
- def test_trimmed(self):
- tmpl = i18n_env.from_string(
+
+ def test_trimmed(self):
+ tmpl = i18n_env.from_string(
"{%- trans trimmed %} hello\n world {% endtrans -%}"
)
assert tmpl.render() == "hello world"
-
- def test_trimmed_policy(self):
+
+ def test_trimmed_policy(self):
s = "{%- trans %} hello\n world {% endtrans -%}"
- tmpl = i18n_env.from_string(s)
- trimmed_tmpl = i18n_env_trimmed.from_string(s)
+ tmpl = i18n_env.from_string(s)
+ trimmed_tmpl = i18n_env_trimmed.from_string(s)
assert tmpl.render() == " hello\n world "
assert trimmed_tmpl.render() == "hello world"
-
- def test_trimmed_policy_override(self):
- tmpl = i18n_env_trimmed.from_string(
+
+ def test_trimmed_policy_override(self):
+ tmpl = i18n_env_trimmed.from_string(
"{%- trans notrimmed %} hello\n world {% endtrans -%}"
)
assert tmpl.render() == " hello\n world "
-
- def test_trimmed_vars(self):
- tmpl = i18n_env.from_string(
+
+ def test_trimmed_vars(self):
+ tmpl = i18n_env.from_string(
'{%- trans trimmed x="world" %} hello\n {{ x }} {% endtrans -%}'
)
assert tmpl.render() == "hello world"
-
- def test_trimmed_varname_trimmed(self):
- # unlikely variable name, but when used as a variable
- # it should not enable trimming
- tmpl = i18n_env.from_string(
+
+ def test_trimmed_varname_trimmed(self):
+ # unlikely variable name, but when used as a variable
+ # it should not enable trimming
+ tmpl = i18n_env.from_string(
"{%- trans trimmed = 'world' %} hello\n {{ trimmed }} {% endtrans -%}"
)
assert tmpl.render() == " hello\n world "
-
- def test_extract(self):
- from jinja2.ext import babel_extract
+
+ def test_extract(self):
+ from jinja2.ext import babel_extract
source = BytesIO(
b"""
@@ -394,10 +394,10 @@ class TestInternationalization:
(2, "gettext", "Hello World", []),
(3, "gettext", "Hello World", []),
(4, "ngettext", ("%(users)s user", "%(users)s users", None), []),
- ]
-
- def test_extract_trimmed(self):
- from jinja2.ext import babel_extract
+ ]
+
+ def test_extract_trimmed(self):
+ from jinja2.ext import babel_extract
source = BytesIO(
b"""
@@ -411,10 +411,10 @@ class TestInternationalization:
(2, "gettext", " Hello \n World", []),
(4, "gettext", "Hello World", []),
(6, "ngettext", ("%(users)s user", "%(users)s users", None), []),
- ]
-
- def test_extract_trimmed_option(self):
- from jinja2.ext import babel_extract
+ ]
+
+ def test_extract_trimmed_option(self):
+ from jinja2.ext import babel_extract
source = BytesIO(
b"""
@@ -429,10 +429,10 @@ class TestInternationalization:
(2, "gettext", " Hello \n World", []),
(4, "gettext", "Hello World", []),
(6, "ngettext", ("%(users)s user", "%(users)s users", None), []),
- ]
-
- def test_comment_extract(self):
- from jinja2.ext import babel_extract
+ ]
+
+ def test_comment_extract(self):
+ from jinja2.ext import babel_extract
source = BytesIO(
b"""
@@ -449,11 +449,11 @@ class TestInternationalization:
(3, "gettext", "Hello World", ["first"]),
(4, "gettext", "Hello World", ["second"]),
(6, "ngettext", ("%(users)s user", "%(users)s users", None), ["third"]),
- ]
-
+ ]
+
def test_extract_context(self):
from jinja2.ext import babel_extract
-
+
source = BytesIO(
b"""
{{ pgettext("babel", "Hello World") }}
@@ -467,50 +467,50 @@ class TestInternationalization:
class TestScope:
- def test_basic_scope_behavior(self):
- # This is what the old with statement compiled down to
- class ScopeExt(Extension):
+ def test_basic_scope_behavior(self):
+ # This is what the old with statement compiled down to
+ class ScopeExt(Extension):
tags = {"scope"}
-
- def parse(self, parser):
- node = nodes.Scope(lineno=next(parser.stream).lineno)
- assignments = []
+
+ def parse(self, parser):
+ node = nodes.Scope(lineno=next(parser.stream).lineno)
+ assignments = []
while parser.stream.current.type != "block_end":
- lineno = parser.stream.current.lineno
- if assignments:
+ lineno = parser.stream.current.lineno
+ if assignments:
parser.stream.expect("comma")
- target = parser.parse_assign_target()
+ target = parser.parse_assign_target()
parser.stream.expect("assign")
- expr = parser.parse_expression()
- assignments.append(nodes.Assign(target, expr, lineno=lineno))
+ expr = parser.parse_expression()
+ assignments.append(nodes.Assign(target, expr, lineno=lineno))
node.body = assignments + list(
parser.parse_statements(("name:endscope",), drop_needle=True)
)
- return node
-
- env = Environment(extensions=[ScopeExt])
+ return node
+
+ env = Environment(extensions=[ScopeExt])
tmpl = env.from_string(
"""\
- {%- scope a=1, b=2, c=b, d=e, e=5 -%}
- {{ a }}|{{ b }}|{{ c }}|{{ d }}|{{ e }}
- {%- endscope -%}
+ {%- scope a=1, b=2, c=b, d=e, e=5 -%}
+ {{ a }}|{{ b }}|{{ c }}|{{ d }}|{{ e }}
+ {%- endscope -%}
"""
)
assert tmpl.render(b=3, e=4) == "1|2|2|4|5"
-
-
+
+
class TestNewstyleInternationalization:
- def test_trans(self):
+ def test_trans(self):
tmpl = newstyle_i18n_env.get_template("child.html")
assert tmpl.render(LANGUAGE="de") == "<title>fehlend</title>pass auf"
-
- def test_trans_plural(self):
+
+ def test_trans_plural(self):
tmpl = newstyle_i18n_env.get_template("plural.html")
assert tmpl.render(LANGUAGE="de", user_count=1) == "Ein Benutzer online"
assert tmpl.render(LANGUAGE="de", user_count=2) == "2 Benutzer online"
-
- def test_complex_plural(self):
- tmpl = newstyle_i18n_env.from_string(
+
+ def test_complex_plural(self):
+ tmpl = newstyle_i18n_env.from_string(
"{% trans foo=42, count=2 %}{{ count }} item{% "
"pluralize count %}{{ count }} items{% endtrans %}"
)
@@ -520,19 +520,19 @@ class TestNewstyleInternationalization:
i18n_env.from_string,
"{% trans foo %}...{% pluralize bar %}...{% endtrans %}",
)
-
- def test_trans_stringformatting(self):
+
+ def test_trans_stringformatting(self):
tmpl = newstyle_i18n_env.get_template("stringformat.html")
assert tmpl.render(LANGUAGE="de", user_count=5) == "Benutzer: 5"
-
- def test_newstyle_plural(self):
+
+ def test_newstyle_plural(self):
tmpl = newstyle_i18n_env.get_template("ngettext.html")
assert tmpl.render(LANGUAGE="de", apples=1) == "1 Apfel"
assert tmpl.render(LANGUAGE="de", apples=5) == "5 Äpfel"
-
- def test_autoescape_support(self):
+
+ def test_autoescape_support(self):
env = Environment(extensions=["jinja2.ext.i18n"])
- env.install_gettext_callables(
+ env.install_gettext_callables(
lambda x: "<strong>Wert: %(name)s</strong>",
lambda s, p, n: s,
newstyle=True,
@@ -543,56 +543,56 @@ class TestNewstyleInternationalization:
)
assert t.render(ae=True) == "<strong>Wert: &lt;test&gt;</strong>"
assert t.render(ae=False) == "<strong>Wert: <test></strong>"
-
- def test_autoescape_macros(self):
+
+ def test_autoescape_macros(self):
env = Environment(autoescape=False)
- template = (
+ template = (
"{% macro m() %}<html>{% endmacro %}"
"{% autoescape true %}{{ m() }}{% endautoescape %}"
- )
+ )
assert env.from_string(template).render() == "<html>"
-
- def test_num_used_twice(self):
+
+ def test_num_used_twice(self):
tmpl = newstyle_i18n_env.get_template("ngettext_long.html")
assert tmpl.render(apples=5, LANGUAGE="de") == "5 Äpfel"
-
- def test_num_called_num(self):
+
+ def test_num_called_num(self):
source = newstyle_i18n_env.compile(
"""
- {% trans num=3 %}{{ num }} apple{% pluralize
- %}{{ num }} apples{% endtrans %}
+ {% trans num=3 %}{{ num }} apple{% pluralize
+ %}{{ num }} apples{% endtrans %}
""",
raw=True,
)
- # quite hacky, but the only way to properly test that. The idea is
- # that the generated code does not pass num twice (although that
- # would work) for better performance. This only works on the
- # newstyle gettext of course
+ # quite hacky, but the only way to properly test that. The idea is
+ # that the generated code does not pass num twice (although that
+ # would work) for better performance. This only works on the
+ # newstyle gettext of course
assert (
re.search(r"u?'%\(num\)s apple', u?'%\(num\)s apples', 3", source)
is not None
)
-
- def test_trans_vars(self):
+
+ def test_trans_vars(self):
t1 = newstyle_i18n_env.get_template("transvars1.html")
t2 = newstyle_i18n_env.get_template("transvars2.html")
t3 = newstyle_i18n_env.get_template("transvars3.html")
assert t1.render(num=1, LANGUAGE="de") == "Benutzer: 1"
assert t2.render(count=23, LANGUAGE="de") == "Benutzer: 23"
assert t3.render(num=42, LANGUAGE="de") == "Benutzer: 42"
-
- def test_novars_vars_escaping(self):
+
+ def test_novars_vars_escaping(self):
t = newstyle_i18n_env.get_template("novars.html")
assert t.render() == "%(hello)s"
t = newstyle_i18n_env.get_template("vars.html")
assert t.render(foo="42") == "42%(foo)s"
t = newstyle_i18n_env.get_template("explicitvars.html")
assert t.render() == "%(foo)s"
-
+
def test_context(self):
tmpl = newstyle_i18n_env.get_template("pgettext.html")
assert tmpl.render(LANGUAGE="de") == "Apple"
-
+
def test_context_newstyle_plural(self):
tmpl = newstyle_i18n_env.get_template("npgettext.html")
assert tmpl.render(LANGUAGE="de", apples=1) == "1 Apple"
@@ -600,15 +600,15 @@ class TestNewstyleInternationalization:
class TestAutoEscape:
- def test_scoped_setting(self):
+ def test_scoped_setting(self):
env = Environment(autoescape=True)
tmpl = env.from_string(
"""
- {{ "<HelloWorld>" }}
- {% autoescape false %}
- {{ "<HelloWorld>" }}
- {% endautoescape %}
- {{ "<HelloWorld>" }}
+ {{ "<HelloWorld>" }}
+ {% autoescape false %}
+ {{ "<HelloWorld>" }}
+ {% endautoescape %}
+ {{ "<HelloWorld>" }}
"""
)
assert tmpl.render().split() == [
@@ -616,15 +616,15 @@ class TestAutoEscape:
"<HelloWorld>",
"&lt;HelloWorld&gt;",
]
-
+
env = Environment(autoescape=False)
tmpl = env.from_string(
"""
- {{ "<HelloWorld>" }}
- {% autoescape true %}
- {{ "<HelloWorld>" }}
- {% endautoescape %}
- {{ "<HelloWorld>" }}
+ {{ "<HelloWorld>" }}
+ {% autoescape true %}
+ {{ "<HelloWorld>" }}
+ {% endautoescape %}
+ {{ "<HelloWorld>" }}
"""
)
assert tmpl.render().split() == [
@@ -632,83 +632,83 @@ class TestAutoEscape:
"&lt;HelloWorld&gt;",
"<HelloWorld>",
]
-
- def test_nonvolatile(self):
+
+ def test_nonvolatile(self):
env = Environment(autoescape=True)
- tmpl = env.from_string('{{ {"foo": "<test>"}|xmlattr|escape }}')
- assert tmpl.render() == ' foo="&lt;test&gt;"'
+ tmpl = env.from_string('{{ {"foo": "<test>"}|xmlattr|escape }}')
+ assert tmpl.render() == ' foo="&lt;test&gt;"'
tmpl = env.from_string(
'{% autoescape false %}{{ {"foo": "<test>"}'
"|xmlattr|escape }}{% endautoescape %}"
)
assert tmpl.render() == " foo=&#34;&amp;lt;test&amp;gt;&#34;"
-
- def test_volatile(self):
+
+ def test_volatile(self):
env = Environment(autoescape=True)
tmpl = env.from_string(
'{% autoescape foo %}{{ {"foo": "<test>"}'
"|xmlattr|escape }}{% endautoescape %}"
)
assert tmpl.render(foo=False) == " foo=&#34;&amp;lt;test&amp;gt;&#34;"
- assert tmpl.render(foo=True) == ' foo="&lt;test&gt;"'
-
- def test_scoping(self):
+ assert tmpl.render(foo=True) == ' foo="&lt;test&gt;"'
+
+ def test_scoping(self):
env = Environment()
- tmpl = env.from_string(
- '{% autoescape true %}{% set x = "<x>" %}{{ x }}'
+ tmpl = env.from_string(
+ '{% autoescape true %}{% set x = "<x>" %}{{ x }}'
'{% endautoescape %}{{ x }}{{ "<y>" }}'
)
assert tmpl.render(x=1) == "&lt;x&gt;1<y>"
-
- def test_volatile_scoping(self):
+
+ def test_volatile_scoping(self):
env = Environment()
tmplsource = """
- {% autoescape val %}
- {% macro foo(x) %}
- [{{ x }}]
- {% endmacro %}
- {{ foo().__class__.__name__ }}
- {% endautoescape %}
- {{ '<testing>' }}
+ {% autoescape val %}
+ {% macro foo(x) %}
+ [{{ x }}]
+ {% endmacro %}
+ {{ foo().__class__.__name__ }}
+ {% endautoescape %}
+ {{ '<testing>' }}
"""
- tmpl = env.from_string(tmplsource)
+ tmpl = env.from_string(tmplsource)
assert tmpl.render(val=True).split()[0] == "Markup"
assert tmpl.render(val=False).split()[0] == "str"
-
- # looking at the source we should see <testing> there in raw
- # (and then escaped as well)
+
+ # looking at the source we should see <testing> there in raw
+ # (and then escaped as well)
env = Environment()
- pysource = env.compile(tmplsource, raw=True)
+ pysource = env.compile(tmplsource, raw=True)
assert "<testing>\\n" in pysource
-
+
env = Environment(autoescape=True)
- pysource = env.compile(tmplsource, raw=True)
+ pysource = env.compile(tmplsource, raw=True)
assert "&lt;testing&gt;\\n" in pysource
-
- def test_overlay_scopes(self):
- class MagicScopeExtension(Extension):
+
+ def test_overlay_scopes(self):
+ class MagicScopeExtension(Extension):
tags = {"overlay"}
- def parse(self, parser):
- node = nodes.OverlayScope(lineno=next(parser.stream).lineno)
+ def parse(self, parser):
+ node = nodes.OverlayScope(lineno=next(parser.stream).lineno)
node.body = list(
parser.parse_statements(("name:endoverlay",), drop_needle=True)
)
node.context = self.call_method("get_scope")
- return node
+ return node
- def get_scope(self):
+ def get_scope(self):
return {"x": [1, 2, 3]}
-
- env = Environment(extensions=[MagicScopeExtension])
-
+
+ env = Environment(extensions=[MagicScopeExtension])
+
tmpl = env.from_string(
"""
- {{- x }}|{% set z = 99 %}
- {%- overlay %}
- {{- y }}|{{ z }}|{% for item in x %}[{{ item }}]{% endfor %}
- {%- endoverlay %}|
- {{- x -}}
+ {{- x }}|{% set z = 99 %}
+ {%- overlay %}
+ {{- y }}|{{ z }}|{% for item in x %}[{{ item }}]{% endfor %}
+ {%- endoverlay %}|
+ {{- x -}}
"""
)
assert tmpl.render(x=42, y=23) == "42|23|99|[1][2][3]|42"
diff --git a/contrib/python/Jinja2/py3/tests/test_features.py b/contrib/python/Jinja2/py3/tests/test_features.py
index 4f36458a7f..d2b68c75d0 100644
--- a/contrib/python/Jinja2/py3/tests/test_features.py
+++ b/contrib/python/Jinja2/py3/tests/test_features.py
@@ -1,14 +1,14 @@
-import pytest
-
+import pytest
+
from jinja2 import Template
-
-
+
+
# Python < 3.7
-def test_generator_stop():
+def test_generator_stop():
class X:
- def __getattr__(self, name):
- raise StopIteration()
-
+ def __getattr__(self, name):
+ raise StopIteration()
+
t = Template("a{{ bad.bar() }}b")
- with pytest.raises(RuntimeError):
- t.render(bad=X())
+ with pytest.raises(RuntimeError):
+ t.render(bad=X())
diff --git a/contrib/python/Jinja2/py3/tests/test_filters.py b/contrib/python/Jinja2/py3/tests/test_filters.py
index 2195157c4f..a246b11cbb 100644
--- a/contrib/python/Jinja2/py3/tests/test_filters.py
+++ b/contrib/python/Jinja2/py3/tests/test_filters.py
@@ -1,24 +1,24 @@
import random
from collections import namedtuple
-
-import pytest
+
+import pytest
from markupsafe import Markup
-
+
from jinja2 import Environment
from jinja2 import StrictUndefined
from jinja2 import TemplateRuntimeError
from jinja2 import UndefinedError
from jinja2.exceptions import TemplateAssertionError
-
+
class Magic:
- def __init__(self, value):
- self.value = value
-
- def __str__(self):
+ def __init__(self, value):
+ self.value = value
+
+ def __str__(self):
return str(self.value)
-
-
+
+
class Magic2:
def __init__(self, value1, value2):
self.value1 = value1
@@ -29,25 +29,25 @@ class Magic2:
class TestFilter:
- def test_filter_calling(self, env):
+ def test_filter_calling(self, env):
rv = env.call_filter("sum", [1, 2, 3])
- assert rv == 6
-
- def test_capitalize(self, env):
- tmpl = env.from_string('{{ "foo bar"|capitalize }}')
+ assert rv == 6
+
+ def test_capitalize(self, env):
+ tmpl = env.from_string('{{ "foo bar"|capitalize }}')
assert tmpl.render() == "Foo bar"
-
- def test_center(self, env):
- tmpl = env.from_string('{{ "foo"|center(9) }}')
+
+ def test_center(self, env):
+ tmpl = env.from_string('{{ "foo"|center(9) }}')
assert tmpl.render() == " foo "
-
- def test_default(self, env):
- tmpl = env.from_string(
- "{{ missing|default('no') }}|{{ false|default('no') }}|"
- "{{ false|default('no', true) }}|{{ given|default('no') }}"
- )
+
+ def test_default(self, env):
+ tmpl = env.from_string(
+ "{{ missing|default('no') }}|{{ false|default('no') }}|"
+ "{{ false|default('no', true) }}|{{ given|default('no') }}"
+ )
assert tmpl.render(given="yes") == "no|False|no|yes"
-
+
@pytest.mark.parametrize(
"args,expect",
(
@@ -57,32 +57,32 @@ class TestFilter:
("reverse=true", "[('c', 2), ('b', 1), ('AB', 3), ('aa', 0)]"),
),
)
- def test_dictsort(self, env, args, expect):
+ def test_dictsort(self, env, args, expect):
t = env.from_string(f"{{{{ foo|dictsort({args}) }}}}")
- out = t.render(foo={"aa": 0, "b": 1, "c": 2, "AB": 3})
- assert out == expect
-
- def test_batch(self, env):
+ out = t.render(foo={"aa": 0, "b": 1, "c": 2, "AB": 3})
+ assert out == expect
+
+ def test_batch(self, env):
tmpl = env.from_string("{{ foo|batch(3)|list }}|{{ foo|batch(3, 'X')|list }}")
- out = tmpl.render(foo=list(range(10)))
+ out = tmpl.render(foo=list(range(10)))
assert out == (
"[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]|"
"[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 'X', 'X']]"
)
-
- def test_slice(self, env):
+
+ def test_slice(self, env):
tmpl = env.from_string("{{ foo|slice(3)|list }}|{{ foo|slice(3, 'X')|list }}")
- out = tmpl.render(foo=list(range(10)))
+ out = tmpl.render(foo=list(range(10)))
assert out == (
"[[0, 1, 2, 3], [4, 5, 6], [7, 8, 9]]|"
"[[0, 1, 2, 3], [4, 5, 6, 'X'], [7, 8, 9, 'X']]"
)
-
- def test_escape(self, env):
+
+ def test_escape(self, env):
tmpl = env.from_string("""{{ '<">&'|escape }}""")
- out = tmpl.render()
+ out = tmpl.render()
assert out == "&lt;&#34;&gt;&amp;"
-
+
@pytest.mark.parametrize(
("chars", "expect"), [(None, "..stays.."), (".", " ..stays"), (" .", "stays")]
)
@@ -91,7 +91,7 @@ class TestFilter:
out = tmpl.render(foo=" ..stays..", chars=chars)
assert out == expect
- def test_striptags(self, env):
+ def test_striptags(self, env):
tmpl = env.from_string("""{{ foo|striptags }}""")
out = tmpl.render(
foo=' <p>just a small \n <a href="#">'
@@ -99,9 +99,9 @@ class TestFilter:
"<!-- <p>and some commented stuff</p> -->"
)
assert out == "just a small example link to a webpage"
-
- def test_filesizeformat(self, env):
- tmpl = env.from_string(
+
+ def test_filesizeformat(self, env):
+ tmpl = env.from_string(
"{{ 100|filesizeformat }}|"
"{{ 1000|filesizeformat }}|"
"{{ 1000000|filesizeformat }}|"
@@ -112,15 +112,15 @@ class TestFilter:
"{{ 1000000|filesizeformat(true) }}|"
"{{ 1000000000|filesizeformat(true) }}|"
"{{ 1000000000000|filesizeformat(true) }}"
- )
- out = tmpl.render()
- assert out == (
+ )
+ out = tmpl.render()
+ assert out == (
"100 Bytes|1.0 kB|1.0 MB|1.0 GB|1.0 TB|100 Bytes|"
"1000 Bytes|976.6 KiB|953.7 MiB|931.3 GiB"
- )
-
- def test_filesizeformat_issue59(self, env):
- tmpl = env.from_string(
+ )
+
+ def test_filesizeformat_issue59(self, env):
+ tmpl = env.from_string(
"{{ 300|filesizeformat }}|"
"{{ 3000|filesizeformat }}|"
"{{ 3000000|filesizeformat }}|"
@@ -129,33 +129,33 @@ class TestFilter:
"{{ 300|filesizeformat(true) }}|"
"{{ 3000|filesizeformat(true) }}|"
"{{ 3000000|filesizeformat(true) }}"
- )
- out = tmpl.render()
- assert out == (
+ )
+ out = tmpl.render()
+ assert out == (
"300 Bytes|3.0 kB|3.0 MB|3.0 GB|3.0 TB|300 Bytes|2.9 KiB|2.9 MiB"
- )
-
- def test_first(self, env):
+ )
+
+ def test_first(self, env):
tmpl = env.from_string("{{ foo|first }}")
- out = tmpl.render(foo=list(range(10)))
+ out = tmpl.render(foo=list(range(10)))
assert out == "0"
-
+
@pytest.mark.parametrize(
("value", "expect"), (("42", "42.0"), ("abc", "0.0"), ("32.32", "32.32"))
)
def test_float(self, env, value, expect):
t = env.from_string("{{ value|float }}")
assert t.render(value=value) == expect
-
+
def test_float_default(self, env):
t = env.from_string("{{ value|float(default=1.0) }}")
assert t.render(value="abc") == "1.0"
- def test_format(self, env):
+ def test_format(self, env):
tmpl = env.from_string("{{ '%s|%s'|format('a', 'b') }}")
- out = tmpl.render()
+ out = tmpl.render()
assert out == "a|b"
-
+
@staticmethod
def _test_indent_multiline_template(env, markup=False):
text = "\n".join(["", "foo bar", '"baz"', ""])
@@ -170,21 +170,21 @@ class TestFilter:
t = env.from_string("{{ foo|indent(2, true, true) }}")
assert t.render(foo=text) == ' \n foo bar\n "baz"\n '
- def test_indent(self, env):
+ def test_indent(self, env):
self._test_indent_multiline_template(env)
- t = env.from_string('{{ "jinja"|indent }}')
+ t = env.from_string('{{ "jinja"|indent }}')
assert t.render() == "jinja"
- t = env.from_string('{{ "jinja"|indent(first=true) }}')
+ t = env.from_string('{{ "jinja"|indent(first=true) }}')
assert t.render() == " jinja"
- t = env.from_string('{{ "jinja"|indent(blank=true) }}')
+ t = env.from_string('{{ "jinja"|indent(blank=true) }}')
assert t.render() == "jinja"
-
+
def test_indent_markup_input(self, env):
"""
Tests cases where the filter input is a Markup type
"""
self._test_indent_multiline_template(env, markup=True)
-
+
def test_indent_width_string(self, env):
t = env.from_string("{{ 'jinja\nflask'|indent(width='>>> ', first=True) }}")
assert t.render() == ">>> jinja\n>>> flask"
@@ -216,142 +216,142 @@ class TestFilter:
def test_int_special_method(self, env):
class IntIsh:
- def __int__(self):
- return 42
-
+ def __int__(self):
+ return 42
+
t = env.from_string("{{ value|int }}")
assert t.render(value=IntIsh()) == "42"
-
- def test_join(self, env):
- tmpl = env.from_string('{{ [1, 2, 3]|join("|") }}')
- out = tmpl.render()
+
+ def test_join(self, env):
+ tmpl = env.from_string('{{ [1, 2, 3]|join("|") }}')
+ out = tmpl.render()
assert out == "1|2|3"
-
- env2 = Environment(autoescape=True)
+
+ env2 = Environment(autoescape=True)
tmpl = env2.from_string('{{ ["<foo>", "<span>foo</span>"|safe]|join }}')
assert tmpl.render() == "&lt;foo&gt;<span>foo</span>"
-
- def test_join_attribute(self, env):
+
+ def test_join_attribute(self, env):
User = namedtuple("User", "username")
tmpl = env.from_string("""{{ users|join(', ', 'username') }}""")
assert tmpl.render(users=map(User, ["foo", "bar"])) == "foo, bar"
-
- def test_last(self, env):
+
+ def test_last(self, env):
tmpl = env.from_string("""{{ foo|last }}""")
- out = tmpl.render(foo=list(range(10)))
+ out = tmpl.render(foo=list(range(10)))
assert out == "9"
-
- def test_length(self, env):
+
+ def test_length(self, env):
tmpl = env.from_string("""{{ "hello world"|length }}""")
- out = tmpl.render()
+ out = tmpl.render()
assert out == "11"
-
- def test_lower(self, env):
+
+ def test_lower(self, env):
tmpl = env.from_string("""{{ "FOO"|lower }}""")
- out = tmpl.render()
+ out = tmpl.render()
assert out == "foo"
-
- def test_pprint(self, env):
- from pprint import pformat
+
+ def test_pprint(self, env):
+ from pprint import pformat
tmpl = env.from_string("""{{ data|pprint }}""")
- data = list(range(1000))
- assert tmpl.render(data=data) == pformat(data)
-
- def test_random(self, env, request):
- # restore the random state when the test ends
- state = random.getstate()
- request.addfinalizer(lambda: random.setstate(state))
- # generate the random values from a known seed
+ data = list(range(1000))
+ assert tmpl.render(data=data) == pformat(data)
+
+ def test_random(self, env, request):
+ # restore the random state when the test ends
+ state = random.getstate()
+ request.addfinalizer(lambda: random.setstate(state))
+ # generate the random values from a known seed
random.seed("jinja")
expected = [random.choice("1234567890") for _ in range(10)]
-
- # check that the random sequence is generated again by a template
- # ensures that filter result is not constant folded
+
+ # check that the random sequence is generated again by a template
+ # ensures that filter result is not constant folded
random.seed("jinja")
- t = env.from_string('{{ "1234567890"|random }}')
-
- for value in expected:
- assert t.render() == value
-
- def test_reverse(self, env):
+ t = env.from_string('{{ "1234567890"|random }}')
+
+ for value in expected:
+ assert t.render() == value
+
+ def test_reverse(self, env):
tmpl = env.from_string(
"{{ 'foobar'|reverse|join }}|{{ [1, 2, 3]|reverse|list }}"
)
assert tmpl.render() == "raboof|[3, 2, 1]"
-
- def test_string(self, env):
- x = [1, 2, 3, 4, 5]
+
+ def test_string(self, env):
+ x = [1, 2, 3, 4, 5]
tmpl = env.from_string("""{{ obj|string }}""")
assert tmpl.render(obj=x) == str(x)
-
- def test_title(self, env):
+
+ def test_title(self, env):
tmpl = env.from_string("""{{ "foo bar"|title }}""")
- assert tmpl.render() == "Foo Bar"
+ assert tmpl.render() == "Foo Bar"
tmpl = env.from_string("""{{ "foo's bar"|title }}""")
- assert tmpl.render() == "Foo's Bar"
+ assert tmpl.render() == "Foo's Bar"
tmpl = env.from_string("""{{ "foo bar"|title }}""")
- assert tmpl.render() == "Foo Bar"
+ assert tmpl.render() == "Foo Bar"
tmpl = env.from_string("""{{ "f bar f"|title }}""")
- assert tmpl.render() == "F Bar F"
+ assert tmpl.render() == "F Bar F"
tmpl = env.from_string("""{{ "foo-bar"|title }}""")
- assert tmpl.render() == "Foo-Bar"
+ assert tmpl.render() == "Foo-Bar"
tmpl = env.from_string("""{{ "foo\tbar"|title }}""")
- assert tmpl.render() == "Foo\tBar"
+ assert tmpl.render() == "Foo\tBar"
tmpl = env.from_string("""{{ "FOO\tBAR"|title }}""")
- assert tmpl.render() == "Foo\tBar"
+ assert tmpl.render() == "Foo\tBar"
tmpl = env.from_string("""{{ "foo (bar)"|title }}""")
- assert tmpl.render() == "Foo (Bar)"
+ assert tmpl.render() == "Foo (Bar)"
tmpl = env.from_string("""{{ "foo {bar}"|title }}""")
- assert tmpl.render() == "Foo {Bar}"
+ assert tmpl.render() == "Foo {Bar}"
tmpl = env.from_string("""{{ "foo [bar]"|title }}""")
- assert tmpl.render() == "Foo [Bar]"
+ assert tmpl.render() == "Foo [Bar]"
tmpl = env.from_string("""{{ "foo <bar>"|title }}""")
- assert tmpl.render() == "Foo <Bar>"
-
- class Foo:
- def __str__(self):
+ assert tmpl.render() == "Foo <Bar>"
+
+ class Foo:
+ def __str__(self):
return "foo-bar"
-
+
tmpl = env.from_string("""{{ data|title }}""")
- out = tmpl.render(data=Foo())
+ out = tmpl.render(data=Foo())
assert out == "Foo-Bar"
-
- def test_truncate(self, env):
- tmpl = env.from_string(
- '{{ data|truncate(15, true, ">>>") }}|'
- '{{ data|truncate(15, false, ">>>") }}|'
+
+ def test_truncate(self, env):
+ tmpl = env.from_string(
+ '{{ data|truncate(15, true, ">>>") }}|'
+ '{{ data|truncate(15, false, ">>>") }}|'
"{{ smalldata|truncate(15) }}"
- )
+ )
out = tmpl.render(data="foobar baz bar" * 1000, smalldata="foobar baz bar")
assert out == "foobar baz b>>>|foobar baz>>>|foobar baz bar"
-
- def test_truncate_very_short(self, env):
- tmpl = env.from_string(
+
+ def test_truncate_very_short(self, env):
+ tmpl = env.from_string(
'{{ "foo bar baz"|truncate(9) }}|{{ "foo bar baz"|truncate(9, true) }}'
- )
- out = tmpl.render()
+ )
+ out = tmpl.render()
assert out == "foo bar baz|foo bar baz"
-
- def test_truncate_end_length(self, env):
- tmpl = env.from_string('{{ "Joel is a slug"|truncate(7, true) }}')
- out = tmpl.render()
+
+ def test_truncate_end_length(self, env):
+ tmpl = env.from_string('{{ "Joel is a slug"|truncate(7, true) }}')
+ out = tmpl.render()
assert out == "Joel..."
-
- def test_upper(self, env):
- tmpl = env.from_string('{{ "foo"|upper }}')
+
+ def test_upper(self, env):
+ tmpl = env.from_string('{{ "foo"|upper }}')
assert tmpl.render() == "FOO"
-
- def test_urlize(self, env):
+
+ def test_urlize(self, env):
tmpl = env.from_string('{{ "foo example.org bar"|urlize }}')
assert tmpl.render() == (
'foo <a href="https://example.org" rel="noopener">' "example.org</a> bar"
)
tmpl = env.from_string('{{ "foo http://www.example.com/ bar"|urlize }}')
- assert tmpl.render() == (
- 'foo <a href="http://www.example.com/" rel="noopener">'
+ assert tmpl.render() == (
+ 'foo <a href="http://www.example.com/" rel="noopener">'
"http://www.example.com/</a> bar"
- )
+ )
tmpl = env.from_string('{{ "foo mailto:email@example.com bar"|urlize }}')
assert tmpl.render() == (
'foo <a href="mailto:email@example.com">email@example.com</a> bar'
@@ -360,25 +360,25 @@ class TestFilter:
assert tmpl.render() == (
'foo <a href="mailto:email@example.com">email@example.com</a> bar'
)
-
- def test_urlize_rel_policy(self):
- env = Environment()
+
+ def test_urlize_rel_policy(self):
+ env = Environment()
env.policies["urlize.rel"] = None
tmpl = env.from_string('{{ "foo http://www.example.com/ bar"|urlize }}')
- assert tmpl.render() == (
+ assert tmpl.render() == (
'foo <a href="http://www.example.com/">http://www.example.com/</a> bar'
- )
-
- def test_urlize_target_parameter(self, env):
- tmpl = env.from_string(
- '{{ "foo http://www.example.com/ bar"|urlize(target="_blank") }}'
- )
+ )
+
+ def test_urlize_target_parameter(self, env):
+ tmpl = env.from_string(
+ '{{ "foo http://www.example.com/ bar"|urlize(target="_blank") }}'
+ )
assert (
tmpl.render()
== 'foo <a href="http://www.example.com/" rel="noopener" target="_blank">'
"http://www.example.com/</a> bar"
)
-
+
def test_urlize_extra_schemes_parameter(self, env):
tmpl = env.from_string(
'{{ "foo tel:+1-514-555-1234 ftp://localhost bar"|'
@@ -390,32 +390,32 @@ class TestFilter:
"ftp://localhost</a> bar"
)
- def test_wordcount(self, env):
- tmpl = env.from_string('{{ "foo bar baz"|wordcount }}')
+ def test_wordcount(self, env):
+ 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):
+ def test_block(self, env):
tmpl = env.from_string("{% filter lower|escape %}<HEHE>{% endfilter %}")
assert tmpl.render() == "&lt;hehe&gt;"
-
- def test_chaining(self, env):
+
+ def test_chaining(self, env):
tmpl = env.from_string("""{{ ['<foo>', '<bar>']|first|upper|escape }}""")
assert tmpl.render() == "&lt;FOO&gt;"
-
- def test_sum(self, env):
+
+ def test_sum(self, env):
tmpl = env.from_string("""{{ [1, 2, 3, 4, 5, 6]|sum }}""")
assert tmpl.render() == "21"
-
- def test_sum_attributes(self, env):
+
+ def test_sum_attributes(self, env):
tmpl = env.from_string("""{{ values|sum('value') }}""")
assert tmpl.render(values=[{"value": 23}, {"value": 1}, {"value": 18}]) == "42"
-
- def test_sum_attributes_nested(self, env):
+
+ def test_sum_attributes_nested(self, env):
tmpl = env.from_string("""{{ values|sum('real.value') }}""")
assert (
tmpl.render(
@@ -427,58 +427,58 @@ class TestFilter:
)
== "42"
)
-
- def test_sum_attributes_tuple(self, env):
+
+ def test_sum_attributes_tuple(self, env):
tmpl = env.from_string("""{{ values.items()|sum('1') }}""")
assert tmpl.render(values={"foo": 23, "bar": 1, "baz": 18}) == "42"
-
- def test_abs(self, env):
+
+ def test_abs(self, env):
tmpl = env.from_string("""{{ -1|abs }}|{{ 1|abs }}""")
assert tmpl.render() == "1|1", tmpl.render()
-
- def test_round_positive(self, env):
+
+ def test_round_positive(self, env):
tmpl = env.from_string(
"{{ 2.7|round }}|{{ 2.1|round }}|"
"{{ 2.1234|round(3, 'floor') }}|"
"{{ 2.1|round(0, 'ceil') }}"
)
assert tmpl.render() == "3.0|2.0|2.123|3.0", tmpl.render()
-
- def test_round_negative(self, env):
+
+ def test_round_negative(self, env):
tmpl = env.from_string(
"{{ 21.3|round(-1)}}|"
"{{ 21.3|round(-1, 'ceil')}}|"
"{{ 21.3|round(-1, 'floor')}}"
)
assert tmpl.render() == "20.0|30.0|20.0", tmpl.render()
-
- def test_xmlattr(self, env):
- tmpl = env.from_string(
- "{{ {'foo': 42, 'bar': 23, 'fish': none, "
+
+ def test_xmlattr(self, env):
+ tmpl = env.from_string(
+ "{{ {'foo': 42, 'bar': 23, 'fish': none, "
"'spam': missing, 'blub:blub': '<?>'}|xmlattr }}"
)
- out = tmpl.render().split()
- assert len(out) == 3
- assert 'foo="42"' in out
- assert 'bar="23"' in out
- assert 'blub:blub="&lt;?&gt;"' in out
-
- def test_sort1(self, env):
+ out = tmpl.render().split()
+ assert len(out) == 3
+ assert 'foo="42"' in out
+ assert 'bar="23"' in out
+ assert 'blub:blub="&lt;?&gt;"' in out
+
+ def test_sort1(self, env):
tmpl = env.from_string("{{ [2, 3, 1]|sort }}|{{ [2, 3, 1]|sort(true) }}")
assert tmpl.render() == "[1, 2, 3]|[3, 2, 1]"
-
- def test_sort2(self, env):
- tmpl = env.from_string('{{ "".join(["c", "A", "b", "D"]|sort) }}')
+
+ def test_sort2(self, env):
+ tmpl = env.from_string('{{ "".join(["c", "A", "b", "D"]|sort) }}')
assert tmpl.render() == "AbcD"
-
- def test_sort3(self, env):
+
+ def test_sort3(self, env):
tmpl = env.from_string("""{{ ['foo', 'Bar', 'blah']|sort }}""")
- assert tmpl.render() == "['Bar', 'blah', 'foo']"
-
- def test_sort4(self, env):
+ assert tmpl.render() == "['Bar', 'blah', 'foo']"
+
+ def test_sort4(self, env):
tmpl = env.from_string("""{{ items|sort(attribute='value')|join }}""")
assert tmpl.render(items=map(Magic, [3, 2, 4, 1])) == "1234"
-
+
def test_sort5(self, env):
tmpl = env.from_string("""{{ items|sort(attribute='value.0')|join }}""")
assert tmpl.render(items=map(Magic, [[3], [2], [4], [1]])) == "[1][2][3][4]"
@@ -519,18 +519,18 @@ class TestFilter:
== "([2],[1])([2],[2])([2],[5])([3],[1])"
)
- def test_unique(self, env):
- t = env.from_string('{{ "".join(["b", "A", "a", "b"]|unique) }}')
- assert t.render() == "bA"
-
- def test_unique_case_sensitive(self, env):
- t = env.from_string('{{ "".join(["b", "A", "a", "b"]|unique(true)) }}')
- assert t.render() == "bAa"
-
- def test_unique_attribute(self, env):
- t = env.from_string("{{ items|unique(attribute='value')|join }}")
+ def test_unique(self, env):
+ t = env.from_string('{{ "".join(["b", "A", "a", "b"]|unique) }}')
+ assert t.render() == "bA"
+
+ def test_unique_case_sensitive(self, env):
+ t = env.from_string('{{ "".join(["b", "A", "a", "b"]|unique(true)) }}')
+ assert t.render() == "bAa"
+
+ def test_unique_attribute(self, env):
+ t = env.from_string("{{ items|unique(attribute='value')|join }}")
assert t.render(items=map(Magic, [3, 2, 4, 1, 2])) == "3241"
-
+
@pytest.mark.parametrize(
"source,expect",
(
@@ -542,57 +542,57 @@ class TestFilter:
("{{ []|max }}", ""),
),
)
- def test_min_max(self, env, source, expect):
- t = env.from_string(source)
- assert t.render() == expect
-
+ def test_min_max(self, env, source, expect):
+ t = env.from_string(source)
+ assert t.render() == expect
+
@pytest.mark.parametrize(("name", "expect"), [("min", "1"), ("max", "9")])
- def test_min_max_attribute(self, env, name, expect):
+ def test_min_max_attribute(self, env, name, expect):
t = env.from_string("{{ items|" + name + '(attribute="value") }}')
- assert t.render(items=map(Magic, [5, 1, 9])) == expect
-
- def test_groupby(self, env):
+ assert t.render(items=map(Magic, [5, 1, 9])) == expect
+
+ def test_groupby(self, env):
tmpl = env.from_string(
"""
- {%- for grouper, list in [{'foo': 1, 'bar': 2},
- {'foo': 2, 'bar': 3},
- {'foo': 1, 'bar': 1},
- {'foo': 3, 'bar': 4}]|groupby('foo') -%}
- {{ grouper }}{% for x in list %}: {{ x.foo }}, {{ x.bar }}{% endfor %}|
+ {%- for grouper, list in [{'foo': 1, 'bar': 2},
+ {'foo': 2, 'bar': 3},
+ {'foo': 1, 'bar': 1},
+ {'foo': 3, 'bar': 4}]|groupby('foo') -%}
+ {{ grouper }}{% for x in list %}: {{ x.foo }}, {{ x.bar }}{% endfor %}|
{%- endfor %}"""
)
assert tmpl.render().split("|") == ["1: 1, 2: 1, 1", "2: 2, 3", "3: 3, 4", ""]
-
- def test_groupby_tuple_index(self, env):
+
+ def test_groupby_tuple_index(self, env):
tmpl = env.from_string(
"""
- {%- for grouper, list in [('a', 1), ('a', 2), ('b', 1)]|groupby(0) -%}
- {{ grouper }}{% for x in list %}:{{ x.1 }}{% endfor %}|
+ {%- for grouper, list in [('a', 1), ('a', 2), ('b', 1)]|groupby(0) -%}
+ {{ grouper }}{% for x in list %}:{{ x.1 }}{% endfor %}|
{%- endfor %}"""
)
assert tmpl.render() == "a:1:2|b:1|"
-
- def test_groupby_multidot(self, env):
+
+ def test_groupby_multidot(self, env):
Date = namedtuple("Date", "day,month,year")
Article = namedtuple("Article", "title,date")
- articles = [
+ articles = [
Article("aha", Date(1, 1, 1970)),
Article("interesting", Date(2, 1, 1970)),
Article("really?", Date(3, 1, 1970)),
Article("totally not", Date(1, 1, 1971)),
- ]
+ ]
tmpl = env.from_string(
"""
- {%- for year, list in articles|groupby('date.year') -%}
- {{ year }}{% for x in list %}[{{ x.title }}]{% endfor %}|
+ {%- for year, list in articles|groupby('date.year') -%}
+ {{ year }}{% for x in list %}[{{ x.title }}]{% endfor %}|
{%- endfor %}"""
)
assert tmpl.render(articles=articles).split("|") == [
"1970[aha][interesting][really?]",
"1971[totally not]",
"",
- ]
-
+ ]
+
def test_groupby_default(self, env):
tmpl = env.from_string(
"{% for city, items in users|groupby('city', default='NY') %}"
@@ -608,35 +608,35 @@ class TestFilter:
)
assert out == "NY: emma, john\nWA: smith\n"
- def test_filtertag(self, env):
+ def test_filtertag(self, env):
tmpl = env.from_string(
"{% filter upper|replace('FOO', 'foo') %}foobar{% endfilter %}"
)
assert tmpl.render() == "fooBAR"
-
- def test_replace(self, env):
- env = Environment()
- tmpl = env.from_string('{{ string|replace("o", 42) }}')
+
+ def test_replace(self, env):
+ env = Environment()
+ tmpl = env.from_string('{{ string|replace("o", 42) }}')
assert tmpl.render(string="<foo>") == "<f4242>"
- env = Environment(autoescape=True)
- tmpl = env.from_string('{{ string|replace("o", 42) }}')
+ env = Environment(autoescape=True)
+ tmpl = env.from_string('{{ string|replace("o", 42) }}')
assert tmpl.render(string="<foo>") == "&lt;f4242&gt;"
- tmpl = env.from_string('{{ string|replace("<", 42) }}')
+ tmpl = env.from_string('{{ string|replace("<", 42) }}')
assert tmpl.render(string="<foo>") == "42foo&gt;"
- tmpl = env.from_string('{{ string|replace("o", ">x<") }}')
+ tmpl = env.from_string('{{ string|replace("o", ">x<") }}')
assert tmpl.render(string=Markup("foo")) == "f&gt;x&lt;&gt;x&lt;"
-
- def test_forceescape(self, env):
+
+ def test_forceescape(self, env):
tmpl = env.from_string("{{ x|forceescape }}")
assert tmpl.render(x=Markup("<div />")) == "&lt;div /&gt;"
-
- def test_safe(self, env):
- env = Environment(autoescape=True)
- tmpl = env.from_string('{{ "<div>foo</div>"|safe }}')
+
+ def test_safe(self, env):
+ env = Environment(autoescape=True)
+ tmpl = env.from_string('{{ "<div>foo</div>"|safe }}')
assert tmpl.render() == "<div>foo</div>"
- tmpl = env.from_string('{{ "<div>foo</div>" }}')
+ tmpl = env.from_string('{{ "<div>foo</div>" }}')
assert tmpl.render() == "&lt;div&gt;foo&lt;/div&gt;"
-
+
@pytest.mark.parametrize(
("value", "expect"),
[
@@ -654,32 +654,32 @@ class TestFilter:
e = Environment(autoescape=True)
t = e.from_string("{{ value|urlencode }}")
assert t.render(value=value) == expect
-
- def test_simple_map(self, env):
- env = Environment()
- tmpl = env.from_string('{{ ["1", "2", "3"]|map("int")|sum }}')
+
+ def test_simple_map(self, env):
+ env = Environment()
+ tmpl = env.from_string('{{ ["1", "2", "3"]|map("int")|sum }}')
assert tmpl.render() == "6"
-
+
def test_map_sum(self, env):
tmpl = env.from_string('{{ [[1,2], [3], [4,5,6]]|map("sum")|list }}')
assert tmpl.render() == "[3, 3, 15]"
- def test_attribute_map(self, env):
+ def test_attribute_map(self, env):
User = namedtuple("User", "name")
- env = Environment()
- users = [
+ env = Environment()
+ users = [
User("john"),
User("jane"),
User("mike"),
- ]
- tmpl = env.from_string('{{ users|map(attribute="name")|join("|") }}')
+ ]
+ tmpl = env.from_string('{{ users|map(attribute="name")|join("|") }}')
assert tmpl.render(users=users) == "john|jane|mike"
-
- def test_empty_map(self, env):
- env = Environment()
- tmpl = env.from_string('{{ none|map("upper")|list }}')
+
+ def test_empty_map(self, env):
+ env = Environment()
+ tmpl = env.from_string('{{ none|map("upper")|list }}')
assert tmpl.render() == "[]"
-
+
def test_map_default(self, env):
Fullname = namedtuple("Fullname", "firstname,lastname")
Firstname = namedtuple("Firstname", "firstname")
@@ -703,86 +703,86 @@ class TestFilter:
assert test_list.render(users=users) == "lennon, edwards, None, ['smith', 'x']"
assert test_str.render(users=users) == "lennon, edwards, None, "
- def test_simple_select(self, env):
- env = Environment()
- tmpl = env.from_string('{{ [1, 2, 3, 4, 5]|select("odd")|join("|") }}')
+ def test_simple_select(self, env):
+ env = Environment()
+ tmpl = env.from_string('{{ [1, 2, 3, 4, 5]|select("odd")|join("|") }}')
assert tmpl.render() == "1|3|5"
-
- def test_bool_select(self, env):
- env = Environment()
+
+ def test_bool_select(self, env):
+ env = Environment()
tmpl = env.from_string('{{ [none, false, 0, 1, 2, 3, 4, 5]|select|join("|") }}')
assert tmpl.render() == "1|2|3|4|5"
-
- def test_simple_reject(self, env):
- env = Environment()
- tmpl = env.from_string('{{ [1, 2, 3, 4, 5]|reject("odd")|join("|") }}')
+
+ def test_simple_reject(self, env):
+ env = Environment()
+ tmpl = env.from_string('{{ [1, 2, 3, 4, 5]|reject("odd")|join("|") }}')
assert tmpl.render() == "2|4"
-
- def test_bool_reject(self, env):
- env = Environment()
+
+ def test_bool_reject(self, env):
+ env = Environment()
tmpl = env.from_string('{{ [none, false, 0, 1, 2, 3, 4, 5]|reject|join("|") }}')
assert tmpl.render() == "None|False|0"
-
- def test_simple_select_attr(self, env):
+
+ def test_simple_select_attr(self, env):
User = namedtuple("User", "name,is_active")
- env = Environment()
- users = [
+ env = Environment()
+ users = [
User("john", True),
User("jane", True),
User("mike", False),
- ]
- tmpl = env.from_string(
+ ]
+ tmpl = env.from_string(
'{{ users|selectattr("is_active")|map(attribute="name")|join("|") }}'
- )
+ )
assert tmpl.render(users=users) == "john|jane"
-
- def test_simple_reject_attr(self, env):
+
+ def test_simple_reject_attr(self, env):
User = namedtuple("User", "name,is_active")
- env = Environment()
- users = [
+ env = Environment()
+ users = [
User("john", True),
User("jane", True),
User("mike", False),
- ]
+ ]
tmpl = env.from_string(
'{{ users|rejectattr("is_active")|map(attribute="name")|join("|") }}'
)
assert tmpl.render(users=users) == "mike"
-
- def test_func_select_attr(self, env):
+
+ def test_func_select_attr(self, env):
User = namedtuple("User", "id,name")
- env = Environment()
- users = [
+ env = Environment()
+ users = [
User(1, "john"),
User(2, "jane"),
User(3, "mike"),
- ]
+ ]
tmpl = env.from_string(
'{{ users|selectattr("id", "odd")|map(attribute="name")|join("|") }}'
)
assert tmpl.render(users=users) == "john|mike"
-
- def test_func_reject_attr(self, env):
+
+ def test_func_reject_attr(self, env):
User = namedtuple("User", "id,name")
- env = Environment()
- users = [
+ env = Environment()
+ users = [
User(1, "john"),
User(2, "jane"),
User(3, "mike"),
- ]
+ ]
tmpl = env.from_string(
'{{ users|rejectattr("id", "odd")|map(attribute="name")|join("|") }}'
)
assert tmpl.render(users=users) == "jane"
-
- def test_json_dump(self):
- env = Environment(autoescape=True)
+
+ def test_json_dump(self):
+ env = Environment(autoescape=True)
t = env.from_string("{{ x|tojson }}")
assert t.render(x={"foo": "bar"}) == '{"foo": "bar"}'
assert t.render(x="\"ba&r'") == r'"\"ba\u0026r\u0027"'
assert t.render(x="<bar>") == r'"\u003cbar\u003e"'
-
- def my_dumps(value, **options):
+
+ def my_dumps(value, **options):
assert options == {"foo": "bar"}
return "42"
diff --git a/contrib/python/Jinja2/py3/tests/test_idtracking.py b/contrib/python/Jinja2/py3/tests/test_idtracking.py
index 4e1d2c3d45..64676ac0f5 100644
--- a/contrib/python/Jinja2/py3/tests/test_idtracking.py
+++ b/contrib/python/Jinja2/py3/tests/test_idtracking.py
@@ -1,9 +1,9 @@
-from jinja2 import nodes
-from jinja2.idtracking import symbols_for_node
-
-
-def test_basics():
- for_loop = nodes.For(
+from jinja2 import nodes
+from jinja2.idtracking import symbols_for_node
+
+
+def test_basics():
+ for_loop = nodes.For(
nodes.Name("foo", "store"),
nodes.Name("seq", "load"),
[nodes.Output([nodes.Name("foo", "load")])],
@@ -14,33 +14,33 @@ def test_basics():
tmpl = nodes.Template(
[nodes.Assign(nodes.Name("foo", "store"), nodes.Name("bar", "load")), for_loop]
)
-
- sym = symbols_for_node(tmpl)
- assert sym.refs == {
+
+ sym = symbols_for_node(tmpl)
+ assert sym.refs == {
"foo": "l_0_foo",
"bar": "l_0_bar",
"seq": "l_0_seq",
- }
- assert sym.loads == {
+ }
+ assert sym.loads == {
"l_0_foo": ("undefined", None),
"l_0_bar": ("resolve", "bar"),
"l_0_seq": ("resolve", "seq"),
- }
-
- sym = symbols_for_node(for_loop, sym)
- assert sym.refs == {
+ }
+
+ sym = symbols_for_node(for_loop, sym)
+ assert sym.refs == {
"foo": "l_1_foo",
- }
- assert sym.loads == {
+ }
+ assert sym.loads == {
"l_1_foo": ("param", None),
- }
-
-
-def test_complex():
+ }
+
+
+def test_complex():
title_block = nodes.Block(
"title", [nodes.Output([nodes.TemplateData("Page Title")])], False, False
)
-
+
render_title_macro = nodes.Macro(
"render_title",
[nodes.Name("title", "param")],
@@ -97,8 +97,8 @@ def test_complex():
),
],
)
-
- for_loop = nodes.For(
+
+ for_loop = nodes.For(
nodes.Name("item", "store"),
nodes.Name("seq", "load"),
[
@@ -116,7 +116,7 @@ def test_complex():
None,
False,
)
-
+
body_block = nodes.Block(
"body",
[
@@ -139,7 +139,7 @@ def test_complex():
False,
False,
)
-
+
tmpl = nodes.Template(
[
nodes.Extends(nodes.Const("layout.html")),
@@ -148,68 +148,68 @@ def test_complex():
body_block,
]
)
-
- tmpl_sym = symbols_for_node(tmpl)
- assert tmpl_sym.refs == {
+
+ tmpl_sym = symbols_for_node(tmpl)
+ assert tmpl_sym.refs == {
"render_title": "l_0_render_title",
- }
- assert tmpl_sym.loads == {
+ }
+ assert tmpl_sym.loads == {
"l_0_render_title": ("undefined", None),
- }
+ }
assert tmpl_sym.stores == {"render_title"}
- assert tmpl_sym.dump_stores() == {
+ assert tmpl_sym.dump_stores() == {
"render_title": "l_0_render_title",
- }
-
- macro_sym = symbols_for_node(render_title_macro, tmpl_sym)
- assert macro_sym.refs == {
+ }
+
+ macro_sym = symbols_for_node(render_title_macro, tmpl_sym)
+ assert macro_sym.refs == {
"subtitle": "l_1_subtitle",
"something": "l_1_something",
"title": "l_1_title",
"title_upper": "l_1_title_upper",
- }
- assert macro_sym.loads == {
+ }
+ assert macro_sym.loads == {
"l_1_subtitle": ("resolve", "subtitle"),
"l_1_something": ("resolve", "something"),
"l_1_title": ("param", None),
"l_1_title_upper": ("resolve", "title_upper"),
- }
+ }
assert macro_sym.stores == {"title", "title_upper", "subtitle"}
assert macro_sym.find_ref("render_title") == "l_0_render_title"
- assert macro_sym.dump_stores() == {
+ assert macro_sym.dump_stores() == {
"title": "l_1_title",
"title_upper": "l_1_title_upper",
"subtitle": "l_1_subtitle",
"render_title": "l_0_render_title",
- }
-
- body_sym = symbols_for_node(body_block)
- assert body_sym.refs == {
+ }
+
+ body_sym = symbols_for_node(body_block)
+ assert body_sym.refs == {
"item": "l_0_item",
"seq": "l_0_seq",
"render_title": "l_0_render_title",
- }
- assert body_sym.loads == {
+ }
+ assert body_sym.loads == {
"l_0_item": ("resolve", "item"),
"l_0_seq": ("resolve", "seq"),
"l_0_render_title": ("resolve", "render_title"),
- }
+ }
assert body_sym.stores == set()
-
- for_sym = symbols_for_node(for_loop, body_sym)
- assert for_sym.refs == {
+
+ for_sym = symbols_for_node(for_loop, body_sym)
+ assert for_sym.refs == {
"item": "l_1_item",
- }
- assert for_sym.loads == {
+ }
+ assert for_sym.loads == {
"l_1_item": ("param", None),
- }
+ }
assert for_sym.stores == {"item"}
- assert for_sym.dump_stores() == {
+ assert for_sym.dump_stores() == {
"item": "l_1_item",
- }
-
-
-def test_if_branching_stores():
+ }
+
+
+def test_if_branching_stores():
tmpl = nodes.Template(
[
nodes.If(
@@ -220,20 +220,20 @@ def test_if_branching_stores():
)
]
)
-
- sym = symbols_for_node(tmpl)
+
+ sym = symbols_for_node(tmpl)
assert sym.refs == {"variable": "l_0_variable", "expression": "l_0_expression"}
assert sym.stores == {"variable"}
- assert sym.loads == {
+ assert sym.loads == {
"l_0_variable": ("resolve", "variable"),
"l_0_expression": ("resolve", "expression"),
- }
- assert sym.dump_stores() == {
+ }
+ assert sym.dump_stores() == {
"variable": "l_0_variable",
- }
-
-
-def test_if_branching_stores_undefined():
+ }
+
+
+def test_if_branching_stores_undefined():
tmpl = nodes.Template(
[
nodes.Assign(nodes.Name("variable", "store"), nodes.Const(23)),
@@ -245,20 +245,20 @@ def test_if_branching_stores_undefined():
),
]
)
-
- sym = symbols_for_node(tmpl)
+
+ sym = symbols_for_node(tmpl)
assert sym.refs == {"variable": "l_0_variable", "expression": "l_0_expression"}
assert sym.stores == {"variable"}
- assert sym.loads == {
+ assert sym.loads == {
"l_0_variable": ("undefined", None),
"l_0_expression": ("resolve", "expression"),
- }
- assert sym.dump_stores() == {
+ }
+ assert sym.dump_stores() == {
"variable": "l_0_variable",
- }
-
-
-def test_if_branching_multi_scope():
+ }
+
+
+def test_if_branching_multi_scope():
for_loop = nodes.For(
nodes.Name("item", "store"),
nodes.Name("seq", "load"),
@@ -275,16 +275,16 @@ def test_if_branching_multi_scope():
None,
False,
)
-
+
tmpl = nodes.Template(
[nodes.Assign(nodes.Name("x", "store"), nodes.Const(23)), for_loop]
)
-
- tmpl_sym = symbols_for_node(tmpl)
- for_sym = symbols_for_node(for_loop, tmpl_sym)
+
+ tmpl_sym = symbols_for_node(tmpl)
+ for_sym = symbols_for_node(for_loop, tmpl_sym)
assert for_sym.stores == {"item", "x"}
- assert for_sym.loads == {
+ assert for_sym.loads == {
"l_1_x": ("alias", "l_0_x"),
"l_1_item": ("param", None),
"l_1_expression": ("resolve", "expression"),
- }
+ }
diff --git a/contrib/python/Jinja2/py3/tests/test_imports.py b/contrib/python/Jinja2/py3/tests/test_imports.py
index b59fb49dde..035aea3cc3 100644
--- a/contrib/python/Jinja2/py3/tests/test_imports.py
+++ b/contrib/python/Jinja2/py3/tests/test_imports.py
@@ -1,15 +1,15 @@
-import pytest
-
+import pytest
+
from jinja2.environment import Environment
from jinja2.exceptions import TemplateNotFound
from jinja2.exceptions import TemplatesNotFound
from jinja2.exceptions import TemplateSyntaxError
from jinja2.exceptions import UndefinedError
from jinja2.loaders import DictLoader
-
-
-@pytest.fixture
-def test_env():
+
+
+@pytest.fixture
+def test_env():
env = Environment(
loader=DictLoader(
dict(
@@ -20,81 +20,81 @@ def test_env():
)
)
env.globals["bar"] = 23
- return env
-
-
+ return env
+
+
class TestImports:
- def test_context_imports(self, test_env):
- t = test_env.from_string('{% import "module" as m %}{{ m.test() }}')
+ def test_context_imports(self, test_env):
+ t = test_env.from_string('{% import "module" as m %}{{ m.test() }}')
assert t.render(foo=42) == "[|23]"
- t = test_env.from_string(
- '{% import "module" as m without context %}{{ m.test() }}'
- )
+ t = test_env.from_string(
+ '{% import "module" as m without context %}{{ m.test() }}'
+ )
assert t.render(foo=42) == "[|23]"
- t = test_env.from_string(
- '{% import "module" as m with context %}{{ m.test() }}'
- )
+ t = test_env.from_string(
+ '{% import "module" as m with context %}{{ m.test() }}'
+ )
assert t.render(foo=42) == "[42|23]"
- t = test_env.from_string('{% from "module" import test %}{{ test() }}')
+ t = test_env.from_string('{% from "module" import test %}{{ test() }}')
assert t.render(foo=42) == "[|23]"
- t = test_env.from_string(
- '{% from "module" import test without context %}{{ test() }}'
- )
+ t = test_env.from_string(
+ '{% from "module" import test without context %}{{ test() }}'
+ )
assert t.render(foo=42) == "[|23]"
- t = test_env.from_string(
- '{% from "module" import test with context %}{{ test() }}'
- )
+ t = test_env.from_string(
+ '{% from "module" import test with context %}{{ test() }}'
+ )
assert t.render(foo=42) == "[42|23]"
-
- def test_import_needs_name(self, test_env):
- test_env.from_string('{% from "foo" import bar %}')
- test_env.from_string('{% from "foo" import bar, baz %}')
-
- with pytest.raises(TemplateSyntaxError):
- test_env.from_string('{% from "foo" import %}')
-
- def test_no_trailing_comma(self, test_env):
- with pytest.raises(TemplateSyntaxError):
- test_env.from_string('{% from "foo" import bar, %}')
-
- with pytest.raises(TemplateSyntaxError):
- test_env.from_string('{% from "foo" import bar,, %}')
-
- with pytest.raises(TemplateSyntaxError):
- test_env.from_string('{% from "foo" import, %}')
-
- def test_trailing_comma_with_context(self, test_env):
- test_env.from_string('{% from "foo" import bar, baz with context %}')
- test_env.from_string('{% from "foo" import bar, baz, with context %}')
- test_env.from_string('{% from "foo" import bar, with context %}')
- test_env.from_string('{% from "foo" import bar, with, context %}')
- test_env.from_string('{% from "foo" import bar, with with context %}')
-
- with pytest.raises(TemplateSyntaxError):
- test_env.from_string('{% from "foo" import bar,, with context %}')
-
- with pytest.raises(TemplateSyntaxError):
- test_env.from_string('{% from "foo" import bar with context, %}')
-
- def test_exports(self, test_env):
+
+ def test_import_needs_name(self, test_env):
+ test_env.from_string('{% from "foo" import bar %}')
+ test_env.from_string('{% from "foo" import bar, baz %}')
+
+ with pytest.raises(TemplateSyntaxError):
+ test_env.from_string('{% from "foo" import %}')
+
+ def test_no_trailing_comma(self, test_env):
+ with pytest.raises(TemplateSyntaxError):
+ test_env.from_string('{% from "foo" import bar, %}')
+
+ with pytest.raises(TemplateSyntaxError):
+ test_env.from_string('{% from "foo" import bar,, %}')
+
+ with pytest.raises(TemplateSyntaxError):
+ test_env.from_string('{% from "foo" import, %}')
+
+ def test_trailing_comma_with_context(self, test_env):
+ test_env.from_string('{% from "foo" import bar, baz with context %}')
+ test_env.from_string('{% from "foo" import bar, baz, with context %}')
+ test_env.from_string('{% from "foo" import bar, with context %}')
+ test_env.from_string('{% from "foo" import bar, with, context %}')
+ test_env.from_string('{% from "foo" import bar, with with context %}')
+
+ with pytest.raises(TemplateSyntaxError):
+ test_env.from_string('{% from "foo" import bar,, with context %}')
+
+ with pytest.raises(TemplateSyntaxError):
+ test_env.from_string('{% from "foo" import bar with context, %}')
+
+ def test_exports(self, test_env):
m = test_env.from_string(
"""
- {% macro toplevel() %}...{% endmacro %}
- {% macro __private() %}...{% endmacro %}
- {% set variable = 42 %}
- {% for item in [1] %}
- {% macro notthere() %}{% endmacro %}
- {% endfor %}
+ {% macro toplevel() %}...{% endmacro %}
+ {% macro __private() %}...{% endmacro %}
+ {% set variable = 42 %}
+ {% for item in [1] %}
+ {% macro notthere() %}{% endmacro %}
+ {% endfor %}
"""
).module
assert m.toplevel() == "..."
assert not hasattr(m, "__missing")
- assert m.variable == 42
+ assert m.variable == 42
assert not hasattr(m, "notthere")
-
+
def test_not_exported(self, test_env):
t = test_env.from_string("{% from 'module' import nothing %}{{ nothing() }}")
-
+
with pytest.raises(UndefinedError, match="does not export the requested name"):
t.render()
@@ -123,54 +123,54 @@ class TestImports:
class TestIncludes:
- def test_context_include(self, test_env):
- t = test_env.from_string('{% include "header" %}')
+ def test_context_include(self, test_env):
+ t = test_env.from_string('{% include "header" %}')
assert t.render(foo=42) == "[42|23]"
- t = test_env.from_string('{% include "header" with context %}')
+ t = test_env.from_string('{% include "header" with context %}')
assert t.render(foo=42) == "[42|23]"
- t = test_env.from_string('{% include "header" without context %}')
+ t = test_env.from_string('{% include "header" without context %}')
assert t.render(foo=42) == "[|23]"
-
- def test_choice_includes(self, test_env):
- t = test_env.from_string('{% include ["missing", "header"] %}')
+
+ def test_choice_includes(self, test_env):
+ t = test_env.from_string('{% include ["missing", "header"] %}')
assert t.render(foo=42) == "[42|23]"
-
+
t = test_env.from_string('{% include ["missing", "missing2"] ignore missing %}')
assert t.render(foo=42) == ""
-
- t = test_env.from_string('{% include ["missing", "missing2"] %}')
- pytest.raises(TemplateNotFound, t.render)
+
+ t = test_env.from_string('{% include ["missing", "missing2"] %}')
+ pytest.raises(TemplateNotFound, t.render)
with pytest.raises(TemplatesNotFound) as e:
- t.render()
-
+ t.render()
+
assert e.value.templates == ["missing", "missing2"]
assert e.value.name == "missing2"
- def test_includes(t, **ctx):
+ def test_includes(t, **ctx):
ctx["foo"] = 42
assert t.render(ctx) == "[42|23]"
-
- t = test_env.from_string('{% include ["missing", "header"] %}')
- test_includes(t)
+
+ t = test_env.from_string('{% include ["missing", "header"] %}')
+ test_includes(t)
t = test_env.from_string("{% include x %}")
test_includes(t, x=["missing", "header"])
- t = test_env.from_string('{% include [x, "header"] %}')
+ t = test_env.from_string('{% include [x, "header"] %}')
test_includes(t, x="missing")
t = test_env.from_string("{% include x %}")
test_includes(t, x="header")
t = test_env.from_string("{% include [x] %}")
test_includes(t, x="header")
-
- def test_include_ignoring_missing(self, test_env):
- t = test_env.from_string('{% include "missing" %}')
- pytest.raises(TemplateNotFound, t.render)
+
+ def test_include_ignoring_missing(self, test_env):
+ t = test_env.from_string('{% include "missing" %}')
+ pytest.raises(TemplateNotFound, t.render)
for extra in "", "with context", "without context":
t = test_env.from_string(
'{% include "missing" ignore missing ' + extra + " %}"
)
assert t.render() == ""
-
- def test_context_include_with_overrides(self, test_env):
+
+ def test_context_include_with_overrides(self, test_env):
env = Environment(
loader=DictLoader(
dict(
@@ -179,23 +179,23 @@ class TestIncludes:
)
)
)
- assert env.get_template("main").render() == "123"
-
- def test_unoptimized_scopes(self, test_env):
+ assert env.get_template("main").render() == "123"
+
+ def test_unoptimized_scopes(self, test_env):
t = test_env.from_string(
"""
- {% macro outer(o) %}
- {% macro inner() %}
- {% include "o_printer" %}
- {% endmacro %}
- {{ inner() }}
- {% endmacro %}
- {{ outer("FOO") }}
+ {% macro outer(o) %}
+ {% macro inner() %}
+ {% include "o_printer" %}
+ {% endmacro %}
+ {{ inner() }}
+ {% endmacro %}
+ {{ outer("FOO") }}
"""
)
assert t.render().strip() == "(FOO)"
-
- def test_import_from_with_context(self):
+
+ def test_import_from_with_context(self):
env = Environment(
loader=DictLoader({"a": "{% macro x() %}{{ foobar }}{% endmacro %}"})
)
diff --git a/contrib/python/Jinja2/py3/tests/test_inheritance.py b/contrib/python/Jinja2/py3/tests/test_inheritance.py
index 0c20d4da7d..1b2a5c217f 100644
--- a/contrib/python/Jinja2/py3/tests/test_inheritance.py
+++ b/contrib/python/Jinja2/py3/tests/test_inheritance.py
@@ -1,63 +1,63 @@
-import pytest
-
+import pytest
+
from jinja2 import DictLoader
from jinja2 import Environment
from jinja2 import TemplateRuntimeError
from jinja2 import TemplateSyntaxError
-
+
LAYOUTTEMPLATE = """\
-|{% block block1 %}block 1 from layout{% endblock %}
-|{% block block2 %}block 2 from layout{% endblock %}
-|{% block block3 %}
-{% block block4 %}nested block 4 from layout{% endblock %}
+|{% block block1 %}block 1 from layout{% endblock %}
+|{% block block2 %}block 2 from layout{% endblock %}
+|{% block block3 %}
+{% block block4 %}nested block 4 from layout{% endblock %}
{% endblock %}|"""
-
+
LEVEL1TEMPLATE = """\
-{% extends "layout" %}
+{% extends "layout" %}
{% block block1 %}block 1 from level1{% endblock %}"""
-
+
LEVEL2TEMPLATE = """\
-{% extends "level1" %}
-{% block block2 %}{% block block5 %}nested block 5 from level2{%
+{% extends "level1" %}
+{% block block2 %}{% block block5 %}nested block 5 from level2{%
endblock %}{% endblock %}"""
-
+
LEVEL3TEMPLATE = """\
-{% extends "level2" %}
-{% block block5 %}block 5 from level3{% endblock %}
-{% block block4 %}block 4 from level3{% endblock %}
+{% extends "level2" %}
+{% block block5 %}block 5 from level3{% endblock %}
+{% block block4 %}block 4 from level3{% endblock %}
"""
-
+
LEVEL4TEMPLATE = """\
-{% extends "level3" %}
-{% block block3 %}block 3 from level4{% endblock %}
+{% extends "level3" %}
+{% block block3 %}block 3 from level4{% endblock %}
"""
-
+
WORKINGTEMPLATE = """\
-{% extends "layout" %}
-{% block block1 %}
- {% if false %}
- {% block block2 %}
+{% extends "layout" %}
+{% block block1 %}
+ {% if false %}
+ {% block block2 %}
this should work
- {% endblock %}
- {% endif %}
-{% endblock %}
+ {% endblock %}
+ {% endif %}
+{% endblock %}
"""
-
+
DOUBLEEXTENDS = """\
-{% extends "layout" %}
-{% extends "layout" %}
-{% block block1 %}
- {% if false %}
- {% block block2 %}
+{% extends "layout" %}
+{% extends "layout" %}
+{% block block1 %}
+ {% if false %}
+ {% block block2 %}
this should work
- {% endblock %}
- {% endif %}
-{% endblock %}
+ {% endblock %}
+ {% endif %}
+{% endblock %}
"""
-
-
-@pytest.fixture
-def env():
+
+
+@pytest.fixture
+def env():
return Environment(
loader=DictLoader(
{
@@ -72,41 +72,41 @@ def env():
),
trim_blocks=True,
)
-
-
+
+
class TestInheritance:
- def test_layout(self, env):
+ def test_layout(self, env):
tmpl = env.get_template("layout")
assert tmpl.render() == (
"|block 1 from layout|block 2 from layout|nested block 4 from layout|"
)
-
- def test_level1(self, env):
+
+ def test_level1(self, env):
tmpl = env.get_template("level1")
assert tmpl.render() == (
"|block 1 from level1|block 2 from layout|nested block 4 from layout|"
)
-
- def test_level2(self, env):
+
+ def test_level2(self, env):
tmpl = env.get_template("level2")
assert tmpl.render() == (
"|block 1 from level1|nested block 5 from "
"level2|nested block 4 from layout|"
)
-
- def test_level3(self, env):
+
+ def test_level3(self, env):
tmpl = env.get_template("level3")
assert tmpl.render() == (
"|block 1 from level1|block 5 from level3|block 4 from level3|"
)
-
- def test_level4(self, env):
+
+ def test_level4(self, env):
tmpl = env.get_template("level4")
assert tmpl.render() == (
"|block 1 from level1|block 5 from level3|block 3 from level4|"
)
-
- def test_super(self, env):
+
+ def test_super(self, env):
env = Environment(
loader=DictLoader(
{
@@ -122,17 +122,17 @@ class TestInheritance:
)
tmpl = env.get_template("c")
assert tmpl.render() == "--INTRO--|BEFORE|[(INNER)]|AFTER"
-
- def test_working(self, env):
+
+ def test_working(self, env):
env.get_template("working")
-
- def test_reuse_blocks(self, env):
+
+ def test_reuse_blocks(self, env):
tmpl = env.from_string(
"{{ self.foo() }}|{% block foo %}42{% endblock %}|{{ self.foo() }}"
)
assert tmpl.render() == "42|42|42"
-
- def test_preserve_blocks(self, env):
+
+ def test_preserve_blocks(self, env):
env = Environment(
loader=DictLoader(
{
@@ -144,8 +144,8 @@ class TestInheritance:
)
tmpl = env.get_template("b")
assert tmpl.render() == "BA"
-
- def test_dynamic_inheritance(self, env):
+
+ def test_dynamic_inheritance(self, env):
env = Environment(
loader=DictLoader(
{
@@ -156,10 +156,10 @@ class TestInheritance:
)
)
tmpl = env.get_template("child")
- for m in range(1, 3):
+ for m in range(1, 3):
assert tmpl.render(default=f"default{m}") == f"DEFAULT{m}CHILD"
-
- def test_multi_inheritance(self, env):
+
+ def test_multi_inheritance(self, env):
env = Environment(
loader=DictLoader(
{
@@ -177,8 +177,8 @@ class TestInheritance:
assert tmpl.render(default="default2") == "DEFAULT2CHILD"
assert tmpl.render(default="default1") == "DEFAULT1CHILD"
assert tmpl.render() == "DEFAULT1CHILD"
-
- def test_scoped_block(self, env):
+
+ def test_scoped_block(self, env):
env = Environment(
loader=DictLoader(
{
@@ -191,8 +191,8 @@ class TestInheritance:
"{% extends 'default.html' %}{% block item %}{{ item }}{% endblock %}"
)
assert t.render(seq=list(range(5))) == "[0][1][2][3][4]"
-
- def test_super_in_scoped_block(self, env):
+
+ def test_super_in_scoped_block(self, env):
env = Environment(
loader=DictLoader(
{
@@ -206,34 +206,34 @@ class TestInheritance:
"{{ super() }}|{{ item * 2 }}{% endblock %}"
)
assert t.render(seq=list(range(5))) == "[0|0][1|2][2|4][3|6][4|8]"
-
- def test_scoped_block_after_inheritance(self, env):
+
+ def test_scoped_block_after_inheritance(self, env):
env = Environment(
loader=DictLoader(
{
"layout.html": """
- {% block useless %}{% endblock %}
+ {% block useless %}{% endblock %}
""",
"index.html": """
- {%- extends 'layout.html' %}
- {% from 'helpers.html' import foo with context %}
- {% block useless %}
- {% for x in [1, 2, 3] %}
- {% block testing scoped %}
- {{ foo(x) }}
- {% endblock %}
- {% endfor %}
- {% endblock %}
+ {%- extends 'layout.html' %}
+ {% from 'helpers.html' import foo with context %}
+ {% block useless %}
+ {% for x in [1, 2, 3] %}
+ {% block testing scoped %}
+ {{ foo(x) }}
+ {% endblock %}
+ {% endfor %}
+ {% endblock %}
""",
"helpers.html": """
- {% macro foo(x) %}{{ the_foo + x }}{% endmacro %}
+ {% macro foo(x) %}{{ the_foo + x }}{% endmacro %}
""",
}
)
)
rv = env.get_template("index.html").render(the_foo=42).split()
assert rv == ["43", "44", "45"]
-
+
def test_level1_required(self, env):
env = Environment(
loader=DictLoader(
@@ -245,7 +245,7 @@ class TestInheritance:
)
rv = env.get_template("level1").render()
assert rv == "[1]"
-
+
def test_level2_required(self, env):
env = Environment(
loader=DictLoader(
@@ -353,40 +353,40 @@ class TestInheritance:
class TestBugFix:
- def test_fixed_macro_scoping_bug(self, env):
+ def test_fixed_macro_scoping_bug(self, env):
assert (
Environment(
loader=DictLoader(
{
"test.html": """\
- {% extends 'details.html' %}
-
- {% macro my_macro() %}
- my_macro
- {% endmacro %}
-
- {% block inner_box %}
- {{ my_macro() }}
- {% endblock %}
+ {% extends 'details.html' %}
+
+ {% macro my_macro() %}
+ my_macro
+ {% endmacro %}
+
+ {% block inner_box %}
+ {{ my_macro() }}
+ {% endblock %}
""",
"details.html": """\
- {% extends 'standard.html' %}
-
- {% macro my_macro() %}
- my_macro
- {% endmacro %}
-
- {% block content %}
- {% block outer_box %}
- outer_box
- {% block inner_box %}
- inner_box
- {% endblock %}
- {% endblock %}
- {% endblock %}
+ {% extends 'standard.html' %}
+
+ {% macro my_macro() %}
+ my_macro
+ {% endmacro %}
+
+ {% block content %}
+ {% block outer_box %}
+ outer_box
+ {% block inner_box %}
+ inner_box
+ {% endblock %}
+ {% endblock %}
+ {% endblock %}
""",
"standard.html": """
- {% block content %}&nbsp;{% endblock %}
+ {% block content %}&nbsp;{% endblock %}
""",
}
)
@@ -396,10 +396,10 @@ class TestBugFix:
.split()
== ["outer_box", "my_macro"]
)
-
- def test_double_extends(self, env):
- """Ensures that a template with more than 1 {% extends ... %} usage
- raises a ``TemplateError``.
- """
+
+ def test_double_extends(self, env):
+ """Ensures that a template with more than 1 {% extends ... %} usage
+ raises a ``TemplateError``.
+ """
with pytest.raises(TemplateRuntimeError, match="extended multiple times"):
env.get_template("doublee").render()
diff --git a/contrib/python/Jinja2/py3/tests/test_lexnparse.py b/contrib/python/Jinja2/py3/tests/test_lexnparse.py
index c02adad5a9..35cc8f8854 100644
--- a/contrib/python/Jinja2/py3/tests/test_lexnparse.py
+++ b/contrib/python/Jinja2/py3/tests/test_lexnparse.py
@@ -1,5 +1,5 @@
-import pytest
-
+import pytest
+
from jinja2 import Environment
from jinja2 import nodes
from jinja2 import Template
@@ -10,48 +10,48 @@ from jinja2.lexer import TOKEN_BLOCK_BEGIN
from jinja2.lexer import TOKEN_BLOCK_END
from jinja2.lexer import TOKEN_EOF
from jinja2.lexer import TokenStream
-
-
+
+
class TestTokenStream:
test_tokens = [
Token(1, TOKEN_BLOCK_BEGIN, ""),
Token(2, TOKEN_BLOCK_END, ""),
]
-
- def test_simple(self, env):
- ts = TokenStream(self.test_tokens, "foo", "bar")
- assert ts.current.type is TOKEN_BLOCK_BEGIN
- assert bool(ts)
- assert not bool(ts.eos)
- next(ts)
- assert ts.current.type is TOKEN_BLOCK_END
- assert bool(ts)
- assert not bool(ts.eos)
- next(ts)
- assert ts.current.type is TOKEN_EOF
- assert not bool(ts)
- assert bool(ts.eos)
-
- def test_iter(self, env):
+
+ def test_simple(self, env):
+ ts = TokenStream(self.test_tokens, "foo", "bar")
+ assert ts.current.type is TOKEN_BLOCK_BEGIN
+ assert bool(ts)
+ assert not bool(ts.eos)
+ next(ts)
+ assert ts.current.type is TOKEN_BLOCK_END
+ assert bool(ts)
+ assert not bool(ts.eos)
+ next(ts)
+ assert ts.current.type is TOKEN_EOF
+ assert not bool(ts)
+ assert bool(ts.eos)
+
+ def test_iter(self, env):
token_types = [t.type for t in TokenStream(self.test_tokens, "foo", "bar")]
assert token_types == [
"block_begin",
"block_end",
- ]
-
-
+ ]
+
+
class TestLexer:
- def test_raw1(self, env):
- tmpl = env.from_string(
+ def test_raw1(self, env):
+ tmpl = env.from_string(
"{% raw %}foo{% endraw %}|"
"{%raw%}{{ bar }}|{% baz %}{% endraw %}"
)
assert tmpl.render() == "foo|{{ bar }}|{% baz %}"
-
- def test_raw2(self, env):
+
+ def test_raw2(self, env):
tmpl = env.from_string("1 {%- raw -%} 2 {%- endraw -%} 3")
assert tmpl.render() == "123"
-
+
def test_raw3(self, env):
# The second newline after baz exists because it is AFTER the
# {% raw %} and is ignored.
@@ -68,71 +68,71 @@ class TestLexer:
)
assert tmpl.render() == "bar2 spaces\n spacefoo"
- def test_balancing(self, env):
+ def test_balancing(self, env):
env = Environment("{%", "%}", "${", "}")
tmpl = env.from_string(
"""{% for item in seq
%}${{'foo': item}|upper}{% endfor %}"""
)
assert tmpl.render(seq=list(range(3))) == "{'FOO': 0}{'FOO': 1}{'FOO': 2}"
-
- def test_comments(self, env):
+
+ def test_comments(self, env):
env = Environment("<!--", "-->", "{", "}")
tmpl = env.from_string(
"""\
-<ul>
-<!--- for item in seq -->
- <li>{item}</li>
-<!--- endfor -->
+<ul>
+<!--- for item in seq -->
+ <li>{item}</li>
+<!--- endfor -->
</ul>"""
)
assert tmpl.render(seq=list(range(3))) == (
"<ul>\n <li>0</li>\n <li>1</li>\n <li>2</li>\n</ul>"
)
-
- def test_string_escapes(self, env):
+
+ def test_string_escapes(self, env):
for char in "\0", "\u2668", "\xe4", "\t", "\r", "\n":
tmpl = env.from_string(f"{{{{ {char!r} }}}}")
- assert tmpl.render() == char
+ assert tmpl.render() == char
assert env.from_string('{{ "\N{HOT SPRINGS}" }}').render() == "\u2668"
-
- def test_bytefallback(self, env):
- from pprint import pformat
-
+
+ def test_bytefallback(self, env):
+ from pprint import pformat
+
tmpl = env.from_string("""{{ 'foo'|pprint }}|{{ 'bär'|pprint }}""")
assert tmpl.render() == pformat("foo") + "|" + pformat("bär")
- def test_operators(self, env):
- from jinja2.lexer import operators
+ def test_operators(self, env):
+ from jinja2.lexer import operators
for test, expect in operators.items():
if test in "([{}])":
- continue
+ continue
stream = env.lexer.tokenize(f"{{{{ {test} }}}}")
- next(stream)
- assert stream.current.type == expect
-
- def test_normalizing(self, env):
+ next(stream)
+ assert stream.current.type == expect
+
+ def test_normalizing(self, env):
for seq in "\r", "\r\n", "\n":
- env = Environment(newline_sequence=seq)
+ env = Environment(newline_sequence=seq)
tmpl = env.from_string("1\n2\r\n3\n4\n")
- result = tmpl.render()
+ result = tmpl.render()
assert result.replace(seq, "X") == "1X2X3X4"
-
- def test_trailing_newline(self, env):
- for keep in [True, False]:
- env = Environment(keep_trailing_newline=keep)
- for template, expected in [
+
+ def test_trailing_newline(self, env):
+ for keep in [True, False]:
+ env = Environment(keep_trailing_newline=keep)
+ for template, expected in [
("", {}),
("no\nnewline", {}),
("with\nnewline\n", {False: "with\nnewline"}),
("with\nseveral\n\n\n", {False: "with\nseveral\n\n"}),
]:
- tmpl = env.from_string(template)
- expect = expected.get(keep, template)
- result = tmpl.render()
- assert result == expect, (keep, template, result, expect)
-
+ tmpl = env.from_string(template)
+ expect = expected.get(keep, template)
+ result = tmpl.render()
+ assert result == expect, (keep, template, result, expect)
+
@pytest.mark.parametrize(
("name", "valid"),
[
@@ -156,13 +156,13 @@ class TestLexer:
)
def test_name(self, env, name, valid):
t = "{{ " + name + " }}"
-
+
if valid:
- # valid for version being tested, shouldn't raise
- env.from_string(t)
- else:
- pytest.raises(TemplateSyntaxError, env.from_string, t)
-
+ # valid for version being tested, shouldn't raise
+ env.from_string(t)
+ else:
+ pytest.raises(TemplateSyntaxError, env.from_string, t)
+
def test_lineno_with_strip(self, env):
tokens = env.lex(
"""\
@@ -180,110 +180,110 @@ class TestLexer:
if token_type == "name" and value == "item":
assert lineno == 5
break
-
+
class TestParser:
- def test_php_syntax(self, env):
+ def test_php_syntax(self, env):
env = Environment("<?", "?>", "<?=", "?>", "<!--", "-->")
tmpl = env.from_string(
"""\
-<!-- I'm a comment, I'm not interesting -->\
-<? for item in seq -?>
- <?= item ?>
+<!-- I'm a comment, I'm not interesting -->\
+<? for item in seq -?>
+ <?= item ?>
<?- endfor ?>"""
)
assert tmpl.render(seq=list(range(5))) == "01234"
-
- def test_erb_syntax(self, env):
+
+ def test_erb_syntax(self, env):
env = Environment("<%", "%>", "<%=", "%>", "<%#", "%>")
tmpl = env.from_string(
"""\
-<%# I'm a comment, I'm not interesting %>\
-<% for item in seq -%>
- <%= item %>
+<%# I'm a comment, I'm not interesting %>\
+<% for item in seq -%>
+ <%= item %>
<%- endfor %>"""
)
assert tmpl.render(seq=list(range(5))) == "01234"
-
- def test_comment_syntax(self, env):
+
+ def test_comment_syntax(self, env):
env = Environment("<!--", "-->", "${", "}", "<!--#", "-->")
tmpl = env.from_string(
"""\
-<!--# I'm a comment, I'm not interesting -->\
-<!-- for item in seq --->
- ${item}
+<!--# I'm a comment, I'm not interesting -->\
+<!-- for item in seq --->
+ ${item}
<!--- endfor -->"""
)
assert tmpl.render(seq=list(range(5))) == "01234"
-
- def test_balancing(self, env):
+
+ def test_balancing(self, env):
tmpl = env.from_string("""{{{'foo':'bar'}.foo}}""")
assert tmpl.render() == "bar"
-
- def test_start_comment(self, env):
+
+ def test_start_comment(self, env):
tmpl = env.from_string(
"""{# foo comment
-and bar comment #}
-{% macro blub() %}foo{% endmacro %}
+and bar comment #}
+{% macro blub() %}foo{% endmacro %}
{{ blub() }}"""
)
assert tmpl.render().strip() == "foo"
-
- def test_line_syntax(self, env):
+
+ def test_line_syntax(self, env):
env = Environment("<%", "%>", "${", "}", "<%#", "%>", "%")
tmpl = env.from_string(
"""\
-<%# regular comment %>
-% for item in seq:
- ${item}
+<%# regular comment %>
+% for item in seq:
+ ${item}
% endfor"""
)
- assert [
- int(x.strip()) for x in tmpl.render(seq=list(range(5))).split()
- ] == list(range(5))
-
+ assert [
+ int(x.strip()) for x in tmpl.render(seq=list(range(5))).split()
+ ] == list(range(5))
+
env = Environment("<%", "%>", "${", "}", "<%#", "%>", "%", "##")
tmpl = env.from_string(
"""\
-<%# regular comment %>
-% for item in seq:
- ${item} ## the rest of the stuff
+<%# regular comment %>
+% for item in seq:
+ ${item} ## the rest of the stuff
% endfor"""
)
- assert [
- int(x.strip()) for x in tmpl.render(seq=list(range(5))).split()
- ] == list(range(5))
-
- def test_line_syntax_priority(self, env):
- # XXX: why is the whitespace there in front of the newline?
+ assert [
+ int(x.strip()) for x in tmpl.render(seq=list(range(5))).split()
+ ] == list(range(5))
+
+ def test_line_syntax_priority(self, env):
+ # XXX: why is the whitespace there in front of the newline?
env = Environment("{%", "%}", "${", "}", "/*", "*/", "##", "#")
tmpl = env.from_string(
"""\
-/* ignore me.
- I'm a multiline comment */
-## for item in seq:
-* ${item} # this is just extra stuff
+/* ignore me.
+ I'm a multiline comment */
+## for item in seq:
+* ${item} # this is just extra stuff
## endfor"""
)
assert tmpl.render(seq=[1, 2]).strip() == "* 1\n* 2"
env = Environment("{%", "%}", "${", "}", "/*", "*/", "#", "##")
tmpl = env.from_string(
"""\
-/* ignore me.
- I'm a multiline comment */
-# for item in seq:
-* ${item} ## this is just extra stuff
- ## extra stuff i just want to ignore
+/* ignore me.
+ I'm a multiline comment */
+# for item in seq:
+* ${item} ## this is just extra stuff
+ ## extra stuff i just want to ignore
# endfor"""
)
assert tmpl.render(seq=[1, 2]).strip() == "* 1\n\n* 2"
-
- def test_error_messages(self, env):
- def assert_error(code, expected):
+
+ def test_error_messages(self, env):
+ def assert_error(code, expected):
with pytest.raises(TemplateSyntaxError, match=expected):
- Template(code)
-
- assert_error(
+ Template(code)
+
+ assert_error(
"{% for item in seq %}...{% endif %}",
"Encountered unknown tag 'endif'. Jinja was looking "
"for the following tags: 'endfor' or 'else'. The "
@@ -291,11 +291,11 @@ and bar comment #}
)
assert_error(
"{% if foo %}{% for item in seq %}...{% endfor %}{% endfor %}",
- "Encountered unknown tag 'endfor'. Jinja was looking for "
- "the following tags: 'elif' or 'else' or 'endif'. The "
+ "Encountered unknown tag 'endfor'. Jinja was looking for "
+ "the following tags: 'elif' or 'else' or 'endif'. The "
"innermost block that needs to be closed is 'if'.",
)
- assert_error(
+ assert_error(
"{% if foo %}",
"Unexpected end of template. Jinja was looking for the "
"following tags: 'elif' or 'else' or 'endif'. The "
@@ -309,51 +309,51 @@ and bar comment #}
)
assert_error(
"{% block foo-bar-baz %}",
- "Block names in Jinja have to be valid Python identifiers "
+ "Block names in Jinja have to be valid Python identifiers "
"and may not contain hyphens, use an underscore instead.",
)
assert_error("{% unknown_tag %}", "Encountered unknown tag 'unknown_tag'.")
-
-
+
+
class TestSyntax:
- def test_call(self, env):
- env = Environment()
+ def test_call(self, env):
+ env = Environment()
env.globals["foo"] = lambda a, b, c, e, g: a + b + c + e + g
tmpl = env.from_string("{{ foo('a', c='d', e='f', *['b'], **{'g': 'h'}) }}")
assert tmpl.render() == "abdfh"
-
- def test_slicing(self, env):
+
+ def test_slicing(self, env):
tmpl = env.from_string("{{ [1, 2, 3][:] }}|{{ [1, 2, 3][::-1] }}")
assert tmpl.render() == "[1, 2, 3]|[3, 2, 1]"
-
- def test_attr(self, env):
- tmpl = env.from_string("{{ foo.bar }}|{{ foo['bar'] }}")
+
+ def test_attr(self, env):
+ tmpl = env.from_string("{{ foo.bar }}|{{ foo['bar'] }}")
assert tmpl.render(foo={"bar": 42}) == "42|42"
-
- def test_subscript(self, env):
- tmpl = env.from_string("{{ foo[0] }}|{{ foo[-1] }}")
+
+ def test_subscript(self, env):
+ tmpl = env.from_string("{{ foo[0] }}|{{ foo[-1] }}")
assert tmpl.render(foo=[0, 1, 2]) == "0|2"
-
- def test_tuple(self, env):
+
+ def test_tuple(self, env):
tmpl = env.from_string("{{ () }}|{{ (1,) }}|{{ (1, 2) }}")
assert tmpl.render() == "()|(1,)|(1, 2)"
-
- def test_math(self, env):
+
+ def test_math(self, env):
tmpl = env.from_string("{{ (1 + 1 * 2) - 3 / 2 }}|{{ 2**3 }}")
assert tmpl.render() == "1.5|8"
-
- def test_div(self, env):
+
+ def test_div(self, env):
tmpl = env.from_string("{{ 3 // 2 }}|{{ 3 / 2 }}|{{ 3 % 2 }}")
assert tmpl.render() == "1|1.5|1"
-
- def test_unary(self, env):
+
+ def test_unary(self, env):
tmpl = env.from_string("{{ +3 }}|{{ -3 }}")
assert tmpl.render() == "3|-3"
-
- def test_concat(self, env):
- tmpl = env.from_string("{{ [1, 2] ~ 'foo' }}")
+
+ def test_concat(self, env):
+ tmpl = env.from_string("{{ [1, 2] ~ 'foo' }}")
assert tmpl.render() == "[1, 2]foo"
-
+
@pytest.mark.parametrize(
("a", "op", "b"),
[
@@ -368,7 +368,7 @@ class TestSyntax:
def test_compare(self, env, a, op, b):
t = env.from_string(f"{{{{ {a} {op} {b} }}}}")
assert t.render() == "True"
-
+
def test_compare_parens(self, env):
t = env.from_string("{{ i * (j < 5) }}")
assert t.render(i=2, j=3) == "2"
@@ -388,15 +388,15 @@ class TestSyntax:
t = env.from_string(src)
assert t.render(a=4, b=2, c=3) == expect
- def test_inop(self, env):
+ def test_inop(self, env):
tmpl = env.from_string("{{ 1 in [1, 2, 3] }}|{{ 1 not in [1, 2, 3] }}")
assert tmpl.render() == "True|False"
-
+
@pytest.mark.parametrize("value", ("[]", "{}", "()"))
def test_collection_literal(self, env, value):
t = env.from_string(f"{{{{ {value} }}}}")
assert t.render() == value
-
+
@pytest.mark.parametrize(
("value", "expect"),
(
@@ -425,39 +425,39 @@ class TestSyntax:
t = env.from_string(f"{{{{ {value} }}}}")
assert t.render() == expect
- def test_bool(self, env):
+ def test_bool(self, env):
tmpl = env.from_string(
"{{ true and false }}|{{ false or true }}|{{ not false }}"
)
assert tmpl.render() == "False|True|True"
-
- def test_grouping(self, env):
- tmpl = env.from_string(
+
+ def test_grouping(self, env):
+ tmpl = env.from_string(
"{{ (true and false) or (false and true) and not false }}"
)
assert tmpl.render() == "False"
-
- def test_django_attr(self, env):
+
+ def test_django_attr(self, env):
tmpl = env.from_string("{{ [1, 2, 3].0 }}|{{ [[1]].0.0 }}")
assert tmpl.render() == "1|1"
-
- def test_conditional_expression(self, env):
+
+ def test_conditional_expression(self, env):
tmpl = env.from_string("""{{ 0 if true else 1 }}""")
assert tmpl.render() == "0"
-
- def test_short_conditional_expression(self, env):
+
+ def test_short_conditional_expression(self, env):
tmpl = env.from_string("<{{ 1 if false }}>")
assert tmpl.render() == "<>"
-
+
tmpl = env.from_string("<{{ (1 if false).bar }}>")
- pytest.raises(UndefinedError, tmpl.render)
-
- def test_filter_priority(self, env):
- tmpl = env.from_string('{{ "foo"|upper + "bar"|upper }}')
+ pytest.raises(UndefinedError, tmpl.render)
+
+ def test_filter_priority(self, env):
+ tmpl = env.from_string('{{ "foo"|upper + "bar"|upper }}')
assert tmpl.render() == "FOOBAR"
-
- def test_function_calls(self, env):
- tests = [
+
+ def test_function_calls(self, env):
+ tests = [
(True, "*foo, bar"),
(True, "*foo, *bar"),
(True, "**foo, *bar"),
@@ -473,16 +473,16 @@ class TestSyntax:
(False, "*foo, **bar"),
(False, "*foo, bar=42, **baz"),
(False, "foo, *args, bar=23, **baz"),
- ]
- for should_fail, sig in tests:
- if should_fail:
+ ]
+ for should_fail, sig in tests:
+ if should_fail:
with pytest.raises(TemplateSyntaxError):
env.from_string(f"{{{{ foo({sig}) }}}}")
- else:
+ else:
env.from_string(f"foo({sig})")
-
- def test_tuple_expr(self, env):
- for tmpl in [
+
+ def test_tuple_expr(self, env):
+ for tmpl in [
"{{ () }}",
"{{ (1, 2) }}",
"{{ (1, 2,) }}",
@@ -491,107 +491,107 @@ class TestSyntax:
"{% for foo, bar in seq %}...{% endfor %}",
"{% for x in foo, bar %}...{% endfor %}",
"{% for x in foo, %}...{% endfor %}",
- ]:
- assert env.from_string(tmpl)
-
- def test_trailing_comma(self, env):
+ ]:
+ assert env.from_string(tmpl)
+
+ def test_trailing_comma(self, env):
tmpl = env.from_string("{{ (1, 2,) }}|{{ [1, 2,] }}|{{ {1: 2,} }}")
assert tmpl.render().lower() == "(1, 2)|[1, 2]|{1: 2}"
-
- def test_block_end_name(self, env):
+
+ def test_block_end_name(self, env):
env.from_string("{% block foo %}...{% endblock foo %}")
pytest.raises(
TemplateSyntaxError, env.from_string, "{% block x %}{% endblock y %}"
)
-
- def test_constant_casing(self, env):
- for const in True, False, None:
+
+ def test_constant_casing(self, env):
+ for const in True, False, None:
const = str(const)
tmpl = env.from_string(
f"{{{{ {const} }}}}|{{{{ {const.lower()} }}}}|{{{{ {const.upper()} }}}}"
)
assert tmpl.render() == f"{const}|{const}|"
-
- def test_test_chaining(self, env):
+
+ def test_test_chaining(self, env):
pytest.raises(
TemplateSyntaxError, env.from_string, "{{ foo is string is sequence }}"
)
assert env.from_string("{{ 42 is string or 42 is number }}").render() == "True"
-
- def test_string_concatenation(self, env):
- tmpl = env.from_string('{{ "foo" "bar" "baz" }}')
+
+ def test_string_concatenation(self, env):
+ tmpl = env.from_string('{{ "foo" "bar" "baz" }}')
assert tmpl.render() == "foobarbaz"
-
- def test_notin(self, env):
- bar = range(100)
+
+ def test_notin(self, env):
+ bar = range(100)
tmpl = env.from_string("""{{ not 42 in bar }}""")
assert tmpl.render(bar=bar) == "False"
-
- def test_operator_precedence(self, env):
+
+ def test_operator_precedence(self, env):
tmpl = env.from_string("""{{ 2 * 3 + 4 % 2 + 1 - 2 }}""")
assert tmpl.render() == "5"
-
- def test_implicit_subscribed_tuple(self, env):
+
+ def test_implicit_subscribed_tuple(self, env):
class Foo:
- def __getitem__(self, x):
- return x
-
+ def __getitem__(self, x):
+ return x
+
t = env.from_string("{{ foo[1, 2] }}")
assert t.render(foo=Foo()) == "(1, 2)"
- def test_raw2(self, env):
+ def test_raw2(self, env):
tmpl = env.from_string("{% raw %}{{ FOO }} and {% BAR %}{% endraw %}")
assert tmpl.render() == "{{ FOO }} and {% BAR %}"
-
- def test_const(self, env):
- tmpl = env.from_string(
+
+ def test_const(self, env):
+ tmpl = env.from_string(
"{{ true }}|{{ false }}|{{ none }}|"
"{{ none is defined }}|{{ missing is defined }}"
)
assert tmpl.render() == "True|False|None|True|False"
-
- def test_neg_filter_priority(self, env):
+
+ def test_neg_filter_priority(self, env):
node = env.parse("{{ -1|foo }}")
- assert isinstance(node.body[0].nodes[0], nodes.Filter)
- assert isinstance(node.body[0].nodes[0].node, nodes.Neg)
-
- def test_const_assign(self, env):
+ assert isinstance(node.body[0].nodes[0], nodes.Filter)
+ assert isinstance(node.body[0].nodes[0].node, nodes.Neg)
+
+ def test_const_assign(self, env):
constass1 = """{% set true = 42 %}"""
constass2 = """{% for none in seq %}{% endfor %}"""
- for tmpl in constass1, constass2:
- pytest.raises(TemplateSyntaxError, env.from_string, tmpl)
-
- def test_localset(self, env):
+ for tmpl in constass1, constass2:
+ pytest.raises(TemplateSyntaxError, env.from_string, tmpl)
+
+ def test_localset(self, env):
tmpl = env.from_string(
"""{% set foo = 0 %}\
-{% for item in [1, 2] %}{% set foo = 1 %}{% endfor %}\
+{% for item in [1, 2] %}{% set foo = 1 %}{% endfor %}\
{{ foo }}"""
)
assert tmpl.render() == "0"
-
- def test_parse_unary(self, env):
- tmpl = env.from_string('{{ -foo["bar"] }}')
+
+ def test_parse_unary(self, env):
+ tmpl = env.from_string('{{ -foo["bar"] }}')
assert tmpl.render(foo={"bar": 42}) == "-42"
- tmpl = env.from_string('{{ -foo["bar"]|abs }}')
+ tmpl = env.from_string('{{ -foo["bar"]|abs }}')
assert tmpl.render(foo={"bar": 42}) == "42"
-
-
+
+
class TestLstripBlocks:
- def test_lstrip(self, env):
- env = Environment(lstrip_blocks=True, trim_blocks=False)
+ def test_lstrip(self, env):
+ env = Environment(lstrip_blocks=True, trim_blocks=False)
tmpl = env.from_string(""" {% if True %}\n {% endif %}""")
- assert tmpl.render() == "\n"
-
- def test_lstrip_trim(self, env):
- env = Environment(lstrip_blocks=True, trim_blocks=True)
+ assert tmpl.render() == "\n"
+
+ def test_lstrip_trim(self, env):
+ env = Environment(lstrip_blocks=True, trim_blocks=True)
tmpl = env.from_string(""" {% if True %}\n {% endif %}""")
- assert tmpl.render() == ""
-
- def test_no_lstrip(self, env):
- env = Environment(lstrip_blocks=True, trim_blocks=False)
+ assert tmpl.render() == ""
+
+ def test_no_lstrip(self, env):
+ env = Environment(lstrip_blocks=True, trim_blocks=False)
tmpl = env.from_string(""" {%+ if True %}\n {%+ endif %}""")
- assert tmpl.render() == " \n "
-
+ assert tmpl.render() == " \n "
+
def test_lstrip_blocks_false_with_no_lstrip(self, env):
# Test that + is a NOP (but does not cause an error) if lstrip_blocks=False
env = Environment(lstrip_blocks=False, trim_blocks=False)
@@ -600,51 +600,51 @@ class TestLstripBlocks:
tmpl = env.from_string(""" {%+ if True %}\n {%+ endif %}""")
assert tmpl.render() == " \n "
- def test_lstrip_endline(self, env):
- env = Environment(lstrip_blocks=True, trim_blocks=False)
+ def test_lstrip_endline(self, env):
+ env = Environment(lstrip_blocks=True, trim_blocks=False)
tmpl = env.from_string(""" hello{% if True %}\n goodbye{% endif %}""")
- assert tmpl.render() == " hello\n goodbye"
-
- def test_lstrip_inline(self, env):
- env = Environment(lstrip_blocks=True, trim_blocks=False)
+ assert tmpl.render() == " hello\n goodbye"
+
+ def test_lstrip_inline(self, env):
+ env = Environment(lstrip_blocks=True, trim_blocks=False)
tmpl = env.from_string(""" {% if True %}hello {% endif %}""")
assert tmpl.render() == "hello "
-
- def test_lstrip_nested(self, env):
- env = Environment(lstrip_blocks=True, trim_blocks=False)
- tmpl = env.from_string(
+
+ def test_lstrip_nested(self, env):
+ env = Environment(lstrip_blocks=True, trim_blocks=False)
+ tmpl = env.from_string(
""" {% if True %}a {% if True %}b {% endif %}c {% endif %}"""
)
assert tmpl.render() == "a b c "
-
- def test_lstrip_left_chars(self, env):
- env = Environment(lstrip_blocks=True, trim_blocks=False)
+
+ def test_lstrip_left_chars(self, env):
+ env = Environment(lstrip_blocks=True, trim_blocks=False)
tmpl = env.from_string(
""" abc {% if True %}
hello{% endif %}"""
)
assert tmpl.render() == " abc \n hello"
-
- def test_lstrip_embeded_strings(self, env):
- env = Environment(lstrip_blocks=True, trim_blocks=False)
+
+ def test_lstrip_embeded_strings(self, env):
+ env = Environment(lstrip_blocks=True, trim_blocks=False)
tmpl = env.from_string(""" {% set x = " {% str %} " %}{{ x }}""")
assert tmpl.render() == " {% str %} "
-
- def test_lstrip_preserve_leading_newlines(self, env):
- env = Environment(lstrip_blocks=True, trim_blocks=False)
+
+ def test_lstrip_preserve_leading_newlines(self, env):
+ env = Environment(lstrip_blocks=True, trim_blocks=False)
tmpl = env.from_string("""\n\n\n{% set hello = 1 %}""")
assert tmpl.render() == "\n\n\n"
-
- def test_lstrip_comment(self, env):
- env = Environment(lstrip_blocks=True, trim_blocks=False)
+
+ def test_lstrip_comment(self, env):
+ env = Environment(lstrip_blocks=True, trim_blocks=False)
tmpl = env.from_string(
""" {# if True #}
-hello
+hello
{#endif#}"""
)
assert tmpl.render() == "\nhello\n"
-
- def test_lstrip_angle_bracket_simple(self, env):
+
+ def test_lstrip_angle_bracket_simple(self, env):
env = Environment(
"<%",
"%>",
@@ -659,8 +659,8 @@ hello
)
tmpl = env.from_string(""" <% if True %>hello <% endif %>""")
assert tmpl.render() == "hello "
-
- def test_lstrip_angle_bracket_comment(self, env):
+
+ def test_lstrip_angle_bracket_comment(self, env):
env = Environment(
"<%",
"%>",
@@ -675,8 +675,8 @@ hello
)
tmpl = env.from_string(""" <%# if True %>hello <%# endif %>""")
assert tmpl.render() == "hello "
-
- def test_lstrip_angle_bracket(self, env):
+
+ def test_lstrip_angle_bracket(self, env):
env = Environment(
"<%",
"%>",
@@ -691,14 +691,14 @@ hello
)
tmpl = env.from_string(
"""\
- <%# regular comment %>
- <% for item in seq %>
-${item} ## the rest of the stuff
+ <%# regular comment %>
+ <% for item in seq %>
+${item} ## the rest of the stuff
<% endfor %>"""
)
assert tmpl.render(seq=range(5)) == "".join(f"{x}\n" for x in range(5))
-
- def test_lstrip_angle_bracket_compact(self, env):
+
+ def test_lstrip_angle_bracket_compact(self, env):
env = Environment(
"<%",
"%>",
@@ -713,13 +713,13 @@ ${item} ## the rest of the stuff
)
tmpl = env.from_string(
"""\
- <%#regular comment%>
- <%for item in seq%>
-${item} ## the rest of the stuff
+ <%#regular comment%>
+ <%for item in seq%>
+${item} ## the rest of the stuff
<%endfor%>"""
)
assert tmpl.render(seq=range(5)) == "".join(f"{x}\n" 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(
@@ -812,86 +812,86 @@ ${item} ## the rest of the stuff
out = tmpl.render(x=1, y=2)
assert out == "1 2"
- def test_php_syntax_with_manual(self, env):
+ def test_php_syntax_with_manual(self, env):
env = Environment(
"<?", "?>", "<?=", "?>", "<!--", "-->", lstrip_blocks=True, trim_blocks=True
)
tmpl = env.from_string(
"""\
- <!-- I'm a comment, I'm not interesting -->
- <? for item in seq -?>
- <?= item ?>
+ <!-- I'm a comment, I'm not interesting -->
+ <? for item in seq -?>
+ <?= item ?>
<?- endfor ?>"""
)
assert tmpl.render(seq=range(5)) == "01234"
-
- def test_php_syntax(self, env):
+
+ def test_php_syntax(self, env):
env = Environment(
"<?", "?>", "<?=", "?>", "<!--", "-->", lstrip_blocks=True, trim_blocks=True
)
tmpl = env.from_string(
"""\
- <!-- I'm a comment, I'm not interesting -->
- <? for item in seq ?>
- <?= item ?>
+ <!-- I'm a comment, I'm not interesting -->
+ <? for item in seq ?>
+ <?= item ?>
<? endfor ?>"""
)
assert tmpl.render(seq=range(5)) == "".join(f" {x}\n" for x in range(5))
-
- def test_php_syntax_compact(self, env):
+
+ def test_php_syntax_compact(self, env):
env = Environment(
"<?", "?>", "<?=", "?>", "<!--", "-->", lstrip_blocks=True, trim_blocks=True
)
tmpl = env.from_string(
"""\
- <!-- I'm a comment, I'm not interesting -->
- <?for item in seq?>
- <?=item?>
+ <!-- I'm a comment, I'm not interesting -->
+ <?for item in seq?>
+ <?=item?>
<?endfor?>"""
)
assert tmpl.render(seq=range(5)) == "".join(f" {x}\n" for x in range(5))
-
- def test_erb_syntax(self, env):
+
+ def test_erb_syntax(self, env):
env = Environment(
"<%", "%>", "<%=", "%>", "<%#", "%>", lstrip_blocks=True, trim_blocks=True
)
tmpl = env.from_string(
"""\
-<%# I'm a comment, I'm not interesting %>
- <% for item in seq %>
- <%= item %>
- <% endfor %>
+<%# I'm a comment, I'm not interesting %>
+ <% for item in seq %>
+ <%= item %>
+ <% endfor %>
"""
)
assert tmpl.render(seq=range(5)) == "".join(f" {x}\n" for x in range(5))
-
- def test_erb_syntax_with_manual(self, env):
+
+ def test_erb_syntax_with_manual(self, env):
env = Environment(
"<%", "%>", "<%=", "%>", "<%#", "%>", lstrip_blocks=True, trim_blocks=True
)
tmpl = env.from_string(
"""\
-<%# I'm a comment, I'm not interesting %>
- <% for item in seq -%>
- <%= item %>
+<%# I'm a comment, I'm not interesting %>
+ <% for item in seq -%>
+ <%= item %>
<%- endfor %>"""
)
assert tmpl.render(seq=range(5)) == "01234"
-
- def test_erb_syntax_no_lstrip(self, env):
+
+ def test_erb_syntax_no_lstrip(self, env):
env = Environment(
"<%", "%>", "<%=", "%>", "<%#", "%>", lstrip_blocks=True, trim_blocks=True
)
tmpl = env.from_string(
"""\
-<%# I'm a comment, I'm not interesting %>
- <%+ for item in seq -%>
- <%= item %>
+<%# I'm a comment, I'm not interesting %>
+ <%+ for item in seq -%>
+ <%= item %>
<%- endfor %>"""
)
assert tmpl.render(seq=range(5)) == " 01234"
-
- def test_comment_syntax(self, env):
+
+ def test_comment_syntax(self, env):
env = Environment(
"<!--",
"-->",
@@ -904,9 +904,9 @@ ${item} ## the rest of the stuff
)
tmpl = env.from_string(
"""\
-<!--# I'm a comment, I'm not interesting -->\
-<!-- for item in seq --->
- ${item}
+<!--# I'm a comment, I'm not interesting -->\
+<!-- for item in seq --->
+ ${item}
<!--- endfor -->"""
)
assert tmpl.render(seq=range(5)) == "01234"
diff --git a/contrib/python/Jinja2/py3/tests/test_loader.py b/contrib/python/Jinja2/py3/tests/test_loader.py
index 5042350607..ef7dad5aa8 100644
--- a/contrib/python/Jinja2/py3/tests/test_loader.py
+++ b/contrib/python/Jinja2/py3/tests/test_loader.py
@@ -1,39 +1,39 @@
import importlib.abc
import importlib.machinery
import importlib.util
-import os
+import os
import platform
import shutil
-import sys
-import tempfile
+import sys
+import tempfile
import time
-import weakref
+import weakref
from pathlib import Path
-
+
import pytest
from jinja2 import Environment
from jinja2 import loaders
from jinja2 import PackageLoader
from jinja2.exceptions import TemplateNotFound
-from jinja2.loaders import split_template_path
-
+from jinja2.loaders import split_template_path
+
import yatest.common as yc
-
+
class TestLoaders:
- def test_dict_loader(self, dict_loader):
- env = Environment(loader=dict_loader)
+ def test_dict_loader(self, dict_loader):
+ env = Environment(loader=dict_loader)
tmpl = env.get_template("justdict.html")
assert tmpl.render().strip() == "FOO"
pytest.raises(TemplateNotFound, env.get_template, "missing.html")
-
- def test_package_loader(self, package_loader):
- env = Environment(loader=package_loader)
+
+ def test_package_loader(self, package_loader):
+ env = Environment(loader=package_loader)
tmpl = env.get_template("test.html")
assert tmpl.render().strip() == "BAR"
pytest.raises(TemplateNotFound, env.get_template, "missing.html")
-
+
def test_filesystem_loader_overlapping_names(self, filesystem_loader):
t2_dir = Path(filesystem_loader.searchpath[0]) / ".." / "templates2"
# Make "foo" show up before "foo/test.html".
@@ -42,83 +42,83 @@ class TestLoaders:
e.get_template("foo")
# This would raise NotADirectoryError if "t2/foo" wasn't skipped.
e.get_template("foo/test.html")
-
- def test_choice_loader(self, choice_loader):
- env = Environment(loader=choice_loader)
+
+ def test_choice_loader(self, choice_loader):
+ env = Environment(loader=choice_loader)
tmpl = env.get_template("justdict.html")
assert tmpl.render().strip() == "FOO"
tmpl = env.get_template("test.html")
assert tmpl.render().strip() == "BAR"
pytest.raises(TemplateNotFound, env.get_template, "missing.html")
-
- def test_function_loader(self, function_loader):
- env = Environment(loader=function_loader)
+
+ def test_function_loader(self, function_loader):
+ env = Environment(loader=function_loader)
tmpl = env.get_template("justfunction.html")
assert tmpl.render().strip() == "FOO"
pytest.raises(TemplateNotFound, env.get_template, "missing.html")
-
- def test_prefix_loader(self, prefix_loader):
- env = Environment(loader=prefix_loader)
+
+ def test_prefix_loader(self, prefix_loader):
+ env = Environment(loader=prefix_loader)
tmpl = env.get_template("a/test.html")
assert tmpl.render().strip() == "BAR"
tmpl = env.get_template("b/justdict.html")
assert tmpl.render().strip() == "FOO"
pytest.raises(TemplateNotFound, env.get_template, "missing")
-
- def test_caching(self):
- changed = False
-
- class TestLoader(loaders.BaseLoader):
- def get_source(self, environment, template):
+
+ def test_caching(self):
+ changed = False
+
+ class TestLoader(loaders.BaseLoader):
+ def get_source(self, environment, template):
return "foo", None, lambda: not changed
- env = Environment(loader=TestLoader(), cache_size=-1)
+ env = Environment(loader=TestLoader(), cache_size=-1)
tmpl = env.get_template("template")
assert tmpl is env.get_template("template")
- changed = True
+ changed = True
assert tmpl is not env.get_template("template")
- changed = False
-
- def test_no_cache(self):
+ changed = False
+
+ def test_no_cache(self):
mapping = {"foo": "one"}
- env = Environment(loader=loaders.DictLoader(mapping), cache_size=0)
+ env = Environment(loader=loaders.DictLoader(mapping), cache_size=0)
assert env.get_template("foo") is not env.get_template("foo")
-
- def test_limited_size_cache(self):
+
+ def test_limited_size_cache(self):
mapping = {"one": "foo", "two": "bar", "three": "baz"}
- loader = loaders.DictLoader(mapping)
- env = Environment(loader=loader, cache_size=2)
+ loader = loaders.DictLoader(mapping)
+ env = Environment(loader=loader, cache_size=2)
t1 = env.get_template("one")
t2 = env.get_template("two")
assert t2 is env.get_template("two")
assert t1 is env.get_template("one")
env.get_template("three")
- loader_ref = weakref.ref(loader)
+ loader_ref = weakref.ref(loader)
assert (loader_ref, "one") in env.cache
assert (loader_ref, "two") not in env.cache
assert (loader_ref, "three") in env.cache
-
- def test_cache_loader_change(self):
+
+ def test_cache_loader_change(self):
loader1 = loaders.DictLoader({"foo": "one"})
loader2 = loaders.DictLoader({"foo": "two"})
- env = Environment(loader=loader1, cache_size=2)
+ env = Environment(loader=loader1, cache_size=2)
assert env.get_template("foo").render() == "one"
- env.loader = loader2
+ env.loader = loader2
assert env.get_template("foo").render() == "two"
-
- def test_dict_loader_cache_invalidates(self):
+
+ def test_dict_loader_cache_invalidates(self):
mapping = {"foo": "one"}
- env = Environment(loader=loaders.DictLoader(mapping))
+ env = Environment(loader=loaders.DictLoader(mapping))
assert env.get_template("foo").render() == "one"
mapping["foo"] = "two"
assert env.get_template("foo").render() == "two"
-
- def test_split_template_path(self):
+
+ def test_split_template_path(self):
assert split_template_path("foo/bar") == ["foo", "bar"]
assert split_template_path("./foo/bar") == ["foo", "bar"]
pytest.raises(TemplateNotFound, split_template_path, "../foo")
-
-
+
+
class TestFileSystemLoader:
searchpath = (Path(yc.test_source_path()) / "res" / "templates").resolve()
@@ -176,30 +176,30 @@ class TestFileSystemLoader:
class TestModuleLoader:
- archive = None
-
+ archive = None
+
def compile_down(self, prefix_loader, zip="deflated"):
- log = []
- self.reg_env = Environment(loader=prefix_loader)
- if zip is not None:
+ log = []
+ self.reg_env = Environment(loader=prefix_loader)
+ if zip is not None:
fd, self.archive = tempfile.mkstemp(suffix=".zip")
- os.close(fd)
- else:
- self.archive = tempfile.mkdtemp()
+ os.close(fd)
+ else:
+ self.archive = tempfile.mkdtemp()
self.reg_env.compile_templates(self.archive, zip=zip, log_function=log.append)
- self.mod_env = Environment(loader=loaders.ModuleLoader(self.archive))
+ self.mod_env = Environment(loader=loaders.ModuleLoader(self.archive))
return "".join(log)
-
- def teardown(self):
+
+ def teardown(self):
if hasattr(self, "mod_env"):
- if os.path.isfile(self.archive):
- os.remove(self.archive)
- else:
- shutil.rmtree(self.archive)
- self.archive = None
-
- def test_log(self, prefix_loader):
- log = self.compile_down(prefix_loader)
+ if os.path.isfile(self.archive):
+ os.remove(self.archive)
+ else:
+ shutil.rmtree(self.archive)
+ self.archive = None
+
+ def test_log(self, prefix_loader):
+ log = self.compile_down(prefix_loader)
assert (
'Compiled "a/foo/test.html" as '
"tmpl_a790caf9d669e39ea4d280d597ec891c4ef0404a" in log
@@ -209,50 +209,50 @@ class TestModuleLoader:
'Could not compile "a/syntaxerror.html": '
"Encountered unknown tag 'endif'" in log
)
-
- def _test_common(self):
+
+ def _test_common(self):
tmpl1 = self.reg_env.get_template("a/test.html")
tmpl2 = self.mod_env.get_template("a/test.html")
- assert tmpl1.render() == tmpl2.render()
-
+ assert tmpl1.render() == tmpl2.render()
+
tmpl1 = self.reg_env.get_template("b/justdict.html")
tmpl2 = self.mod_env.get_template("b/justdict.html")
- assert tmpl1.render() == tmpl2.render()
-
- def test_deflated_zip_compile(self, prefix_loader):
+ assert tmpl1.render() == tmpl2.render()
+
+ def test_deflated_zip_compile(self, prefix_loader):
self.compile_down(prefix_loader, zip="deflated")
- self._test_common()
-
- def test_stored_zip_compile(self, prefix_loader):
+ self._test_common()
+
+ def test_stored_zip_compile(self, prefix_loader):
self.compile_down(prefix_loader, zip="stored")
- self._test_common()
-
- def test_filesystem_compile(self, prefix_loader):
- self.compile_down(prefix_loader, zip=None)
- self._test_common()
-
- def test_weak_references(self, prefix_loader):
- self.compile_down(prefix_loader)
+ self._test_common()
+
+ def test_filesystem_compile(self, prefix_loader):
+ self.compile_down(prefix_loader, zip=None)
+ self._test_common()
+
+ def test_weak_references(self, prefix_loader):
+ self.compile_down(prefix_loader)
self.mod_env.get_template("a/test.html")
key = loaders.ModuleLoader.get_template_key("a/test.html")
- name = self.mod_env.loader.module.__name__
-
- assert hasattr(self.mod_env.loader.module, key)
- assert name in sys.modules
-
- # unset all, ensure the module is gone from sys.modules
+ name = self.mod_env.loader.module.__name__
+
+ assert hasattr(self.mod_env.loader.module, key)
+ assert name in sys.modules
+
+ # unset all, ensure the module is gone from sys.modules
self.mod_env = None
+
+ try:
+ import gc
- try:
- import gc
-
- gc.collect()
+ gc.collect()
except BaseException:
- pass
-
- assert name not in sys.modules
-
- def test_choice_loader(self, prefix_loader):
+ pass
+
+ assert name not in sys.modules
+
+ def test_choice_loader(self, prefix_loader):
self.compile_down(prefix_loader)
self.mod_env.loader = loaders.ChoiceLoader(
[self.mod_env.loader, loaders.DictLoader({"DICT_SOURCE": "DICT_TEMPLATE"})]
@@ -261,7 +261,7 @@ class TestModuleLoader:
assert tmpl1.render() == "BAR"
tmpl2 = self.mod_env.get_template("DICT_SOURCE")
assert tmpl2.render() == "DICT_TEMPLATE"
-
+
def test_prefix_loader(self, prefix_loader):
self.compile_down(prefix_loader)
self.mod_env.loader = loaders.PrefixLoader(
@@ -274,10 +274,10 @@ class TestModuleLoader:
assert tmpl1.render() == "BAR"
tmpl2 = self.mod_env.get_template("DICT/test.html")
assert tmpl2.render() == "DICT_TEMPLATE"
-
+
def test_path_as_pathlib(self, prefix_loader):
self.compile_down(prefix_loader)
-
+
mod_path = self.mod_env.loader.module.__path__[0]
mod_loader = loaders.ModuleLoader(Path(mod_path))
self.mod_env = Environment(loader=mod_loader)
diff --git a/contrib/python/Jinja2/py3/tests/test_nativetypes.py b/contrib/python/Jinja2/py3/tests/test_nativetypes.py
index 9bae938cdb..42e45c418b 100644
--- a/contrib/python/Jinja2/py3/tests/test_nativetypes.py
+++ b/contrib/python/Jinja2/py3/tests/test_nativetypes.py
@@ -1,76 +1,76 @@
import math
-import pytest
-
-from jinja2.exceptions import UndefinedError
-from jinja2.nativetypes import NativeEnvironment
+import pytest
+
+from jinja2.exceptions import UndefinedError
+from jinja2.nativetypes import NativeEnvironment
from jinja2.nativetypes import NativeTemplate
-from jinja2.runtime import Undefined
-
-
-@pytest.fixture
-def env():
- return NativeEnvironment()
-
-
+from jinja2.runtime import Undefined
+
+
+@pytest.fixture
+def env():
+ return NativeEnvironment()
+
+
def test_is_defined_native_return(env):
t = env.from_string("{{ missing is defined }}")
assert not t.render()
-
-
+
+
def test_undefined_native_return(env):
t = env.from_string("{{ missing }}")
assert isinstance(t.render(), Undefined)
-
-
+
+
def test_adding_undefined_native_return(env):
t = env.from_string("{{ 3 + missing }}")
-
+
with pytest.raises(UndefinedError):
t.render()
-
-
+
+
def test_cast_int(env):
t = env.from_string("{{ value|int }}")
result = t.render(value="3")
assert isinstance(result, int)
assert result == 3
-
-
+
+
def test_list_add(env):
t = env.from_string("{{ a + b }}")
result = t.render(a=["a", "b"], b=["c", "d"])
assert isinstance(result, list)
assert result == ["a", "b", "c", "d"]
-
-
+
+
def test_multi_expression_add(env):
t = env.from_string("{{ a }} + {{ b }}")
result = t.render(a=["a", "b"], b=["c", "d"])
assert not isinstance(result, list)
assert result == "['a', 'b'] + ['c', 'd']"
-
-
+
+
def test_loops(env):
t = env.from_string("{% for x in value %}{{ x }}{% endfor %}")
result = t.render(value=["a", "b", "c", "d"])
assert isinstance(result, str)
assert result == "abcd"
-
-
+
+
def test_loops_with_ints(env):
t = env.from_string("{% for x in value %}{{ x }}{% endfor %}")
result = t.render(value=[1, 2, 3, 4])
assert isinstance(result, int)
assert result == 1234
-
-
+
+
def test_loop_look_alike(env):
t = env.from_string("{% for x in value %}{{ x }}{% endfor %}")
result = t.render(value=[1])
assert isinstance(result, int)
assert result == 1
-
+
@pytest.mark.parametrize(
("source", "expect"),
diff --git a/contrib/python/Jinja2/py3/tests/test_regression.py b/contrib/python/Jinja2/py3/tests/test_regression.py
index 7e2336978e..4c74044ceb 100644
--- a/contrib/python/Jinja2/py3/tests/test_regression.py
+++ b/contrib/python/Jinja2/py3/tests/test_regression.py
@@ -1,5 +1,5 @@
-import pytest
-
+import pytest
+
from jinja2 import DictLoader
from jinja2 import Environment
from jinja2 import PrefixLoader
@@ -8,108 +8,108 @@ from jinja2 import TemplateAssertionError
from jinja2 import TemplateNotFound
from jinja2 import TemplateSyntaxError
from jinja2.utils import pass_context
-
-
+
+
class TestCorner:
- def test_assigned_scoping(self, env):
+ def test_assigned_scoping(self, env):
t = env.from_string(
"""
- {%- for item in (1, 2, 3, 4) -%}
- [{{ item }}]
- {%- endfor %}
- {{- item -}}
+ {%- for item in (1, 2, 3, 4) -%}
+ [{{ item }}]
+ {%- endfor %}
+ {{- item -}}
"""
)
assert t.render(item=42) == "[1][2][3][4]42"
-
+
t = env.from_string(
"""
- {%- for item in (1, 2, 3, 4) -%}
- [{{ item }}]
- {%- endfor %}
- {%- set item = 42 %}
- {{- item -}}
+ {%- for item in (1, 2, 3, 4) -%}
+ [{{ item }}]
+ {%- endfor %}
+ {%- set item = 42 %}
+ {{- item -}}
"""
)
assert t.render() == "[1][2][3][4]42"
-
+
t = env.from_string(
"""
- {%- set item = 42 %}
- {%- for item in (1, 2, 3, 4) -%}
- [{{ item }}]
- {%- endfor %}
- {{- item -}}
+ {%- set item = 42 %}
+ {%- for item in (1, 2, 3, 4) -%}
+ [{{ item }}]
+ {%- endfor %}
+ {{- item -}}
"""
)
assert t.render() == "[1][2][3][4]42"
-
- def test_closure_scoping(self, env):
+
+ def test_closure_scoping(self, env):
t = env.from_string(
"""
- {%- set wrapper = "<FOO>" %}
- {%- for item in (1, 2, 3, 4) %}
- {%- macro wrapper() %}[{{ item }}]{% endmacro %}
- {{- wrapper() }}
- {%- endfor %}
- {{- wrapper -}}
+ {%- set wrapper = "<FOO>" %}
+ {%- for item in (1, 2, 3, 4) %}
+ {%- macro wrapper() %}[{{ item }}]{% endmacro %}
+ {{- wrapper() }}
+ {%- endfor %}
+ {{- wrapper -}}
"""
)
assert t.render() == "[1][2][3][4]<FOO>"
-
+
t = env.from_string(
"""
- {%- for item in (1, 2, 3, 4) %}
- {%- macro wrapper() %}[{{ item }}]{% endmacro %}
- {{- wrapper() }}
- {%- endfor %}
- {%- set wrapper = "<FOO>" %}
- {{- wrapper -}}
+ {%- for item in (1, 2, 3, 4) %}
+ {%- macro wrapper() %}[{{ item }}]{% endmacro %}
+ {{- wrapper() }}
+ {%- endfor %}
+ {%- set wrapper = "<FOO>" %}
+ {{- wrapper -}}
"""
)
assert t.render() == "[1][2][3][4]<FOO>"
-
+
t = env.from_string(
"""
- {%- for item in (1, 2, 3, 4) %}
- {%- macro wrapper() %}[{{ item }}]{% endmacro %}
- {{- wrapper() }}
- {%- endfor %}
- {{- wrapper -}}
+ {%- for item in (1, 2, 3, 4) %}
+ {%- macro wrapper() %}[{{ item }}]{% endmacro %}
+ {{- wrapper() }}
+ {%- endfor %}
+ {{- wrapper -}}
"""
)
assert t.render(wrapper=23) == "[1][2][3][4]23"
-
-
+
+
class TestBug:
- def test_keyword_folding(self, env):
- env = Environment()
+ def test_keyword_folding(self, env):
+ env = Environment()
env.filters["testing"] = lambda value, some: value + some
assert (
env.from_string("{{ 'test'|testing(some='stuff') }}").render()
== "teststuff"
)
-
- def test_extends_output_bugs(self, env):
+
+ def test_extends_output_bugs(self, env):
env = Environment(
loader=DictLoader({"parent.html": "(({% block title %}{% endblock %}))"})
)
-
- t = env.from_string(
- '{% if expr %}{% extends "parent.html" %}{% endif %}'
+
+ t = env.from_string(
+ '{% if expr %}{% extends "parent.html" %}{% endif %}'
"[[{% block title %}title{% endblock %}]]"
"{% for item in [1, 2, 3] %}({{ item }}){% endfor %}"
- )
+ )
assert t.render(expr=False) == "[[title]](1)(2)(3)"
assert t.render(expr=True) == "((title))"
-
- def test_urlize_filter_escaping(self, env):
- tmpl = env.from_string('{{ "http://www.example.org/<foo"|urlize }}')
+
+ def test_urlize_filter_escaping(self, env):
+ tmpl = env.from_string('{{ "http://www.example.org/<foo"|urlize }}')
assert (
tmpl.render() == '<a href="http://www.example.org/&lt;foo" rel="noopener">'
"http://www.example.org/&lt;foo</a>"
)
-
+
def test_urlize_filter_closing_punctuation(self, env):
tmpl = env.from_string(
'{{ "(see http://www.example.org/?page=subj_<desc.h>)"|urlize }}'
@@ -119,108 +119,108 @@ class TestBug:
'rel="noopener">http://www.example.org/?page=subj_&lt;desc.h&gt;</a>)'
)
- def test_loop_call_loop(self, env):
+ def test_loop_call_loop(self, env):
tmpl = env.from_string(
"""
-
- {% macro test() %}
- {{ caller() }}
- {% endmacro %}
-
- {% for num1 in range(5) %}
- {% call test() %}
- {% for num2 in range(10) %}
- {{ loop.index }}
- {% endfor %}
- {% endcall %}
- {% endfor %}
-
+
+ {% macro test() %}
+ {{ caller() }}
+ {% endmacro %}
+
+ {% for num1 in range(5) %}
+ {% call test() %}
+ {% for num2 in range(10) %}
+ {{ loop.index }}
+ {% endfor %}
+ {% endcall %}
+ {% endfor %}
+
"""
)
-
+
assert tmpl.render().split() == [str(x) for x in range(1, 11)] * 5
-
- def test_weird_inline_comment(self, env):
+
+ def test_weird_inline_comment(self, env):
env = Environment(line_statement_prefix="%")
pytest.raises(
TemplateSyntaxError,
env.from_string,
"% for item in seq {# missing #}\n...% endfor",
)
-
- def test_old_macro_loop_scoping_bug(self, env):
+
+ def test_old_macro_loop_scoping_bug(self, env):
tmpl = env.from_string(
"{% for i in (1, 2) %}{{ i }}{% endfor %}"
"{% macro i() %}3{% endmacro %}{{ i() }}"
)
assert tmpl.render() == "123"
-
- def test_partial_conditional_assignments(self, env):
+
+ def test_partial_conditional_assignments(self, env):
tmpl = env.from_string("{% if b %}{% set a = 42 %}{% endif %}{{ a }}")
assert tmpl.render(a=23) == "23"
assert tmpl.render(b=True) == "42"
-
- def test_stacked_locals_scoping_bug(self, env):
+
+ def test_stacked_locals_scoping_bug(self, env):
env = Environment(line_statement_prefix="#")
t = env.from_string(
"""\
-# for j in [1, 2]:
-# set x = 1
-# for i in [1, 2]:
-# print x
-# if i % 2 == 0:
-# set x = x + 1
-# endif
-# endfor
-# endfor
-# if a
-# print 'A'
-# elif b
-# print 'B'
-# elif c == d
-# print 'C'
-# else
-# print 'D'
-# endif
+# for j in [1, 2]:
+# set x = 1
+# for i in [1, 2]:
+# print x
+# if i % 2 == 0:
+# set x = x + 1
+# endif
+# endfor
+# endfor
+# if a
+# print 'A'
+# elif b
+# print 'B'
+# elif c == d
+# print 'C'
+# else
+# print 'D'
+# endif
"""
)
assert t.render(a=0, b=False, c=42, d=42.0) == "1111C"
-
- def test_stacked_locals_scoping_bug_twoframe(self, env):
+
+ def test_stacked_locals_scoping_bug_twoframe(self, env):
t = Template(
"""
- {% set x = 1 %}
- {% for item in foo %}
- {% if item == 1 %}
- {% set x = 2 %}
- {% endif %}
- {% endfor %}
- {{ x }}
+ {% set x = 1 %}
+ {% for item in foo %}
+ {% if item == 1 %}
+ {% set x = 2 %}
+ {% endif %}
+ {% endfor %}
+ {{ x }}
"""
)
- rv = t.render(foo=[1]).strip()
+ rv = t.render(foo=[1]).strip()
assert rv == "1"
-
- def test_call_with_args(self, env):
+
+ def test_call_with_args(self, env):
t = Template(
"""{% macro dump_users(users) -%}
- <ul>
- {%- for user in users -%}
- <li><p>{{ user.username|e }}</p>{{ caller(user) }}</li>
- {%- endfor -%}
- </ul>
- {%- endmacro -%}
-
- {% call(user) dump_users(list_of_user) -%}
- <dl>
- <dl>Realname</dl>
- <dd>{{ user.realname|e }}</dd>
- <dl>Description</dl>
- <dd>{{ user.description }}</dd>
- </dl>
+ <ul>
+ {%- for user in users -%}
+ <li><p>{{ user.username|e }}</p>{{ caller(user) }}</li>
+ {%- endfor -%}
+ </ul>
+ {%- endmacro -%}
+
+ {% call(user) dump_users(list_of_user) -%}
+ <dl>
+ <dl>Realname</dl>
+ <dd>{{ user.realname|e }}</dd>
+ <dl>Description</dl>
+ <dd>{{ user.description }}</dd>
+ </dl>
{% endcall %}"""
)
-
+
assert [
x.strip()
for x in t.render(
@@ -240,20 +240,20 @@ class TestBug:
"<dd>test</dd>",
"</dl>",
"</li></ul>",
- ]
-
- def test_empty_if_condition_fails(self, env):
+ ]
+
+ def test_empty_if_condition_fails(self, env):
pytest.raises(TemplateSyntaxError, Template, "{% if %}....{% endif %}")
pytest.raises(
TemplateSyntaxError, Template, "{% if foo %}...{% elif %}...{% endif %}"
)
pytest.raises(TemplateSyntaxError, Template, "{% for x in %}..{% endfor %}")
-
+
def test_recursive_loop_compile(self, env):
Template(
"""
{% for p in foo recursive%}
- {{p.bar}}
+ {{p.bar}}
{% for f in p.fields recursive%}
{{f.baz}}
{{p.bar}}
@@ -261,13 +261,13 @@ class TestBug:
{{ loop(f.sub) }}
{% endif %}
{% endfor %}
- {% endfor %}
+ {% endfor %}
"""
)
Template(
"""
{% for p in foo%}
- {{p.bar}}
+ {{p.bar}}
{% for f in p.fields recursive%}
{{f.baz}}
{{p.bar}}
@@ -275,148 +275,148 @@ class TestBug:
{{ loop(f.sub) }}
{% endif %}
{% endfor %}
- {% endfor %}
+ {% endfor %}
"""
)
-
- def test_else_loop_bug(self, env):
+
+ def test_else_loop_bug(self, env):
t = Template(
"""
- {% for x in y %}
- {{ loop.index0 }}
- {% else %}
- {% for i in range(3) %}{{ i }}{% endfor %}
- {% endfor %}
+ {% for x in y %}
+ {{ loop.index0 }}
+ {% else %}
+ {% for i in range(3) %}{{ i }}{% endfor %}
+ {% endfor %}
"""
)
assert t.render(y=[]).strip() == "012"
-
- def test_correct_prefix_loader_name(self, env):
+
+ def test_correct_prefix_loader_name(self, env):
env = Environment(loader=PrefixLoader({"foo": DictLoader({})}))
with pytest.raises(TemplateNotFound) as e:
env.get_template("foo/bar.html")
-
+
assert e.value.name == "foo/bar.html"
def test_pass_context_callable_class(self, env):
class CallableClass:
@pass_context
- def __call__(self, ctx):
+ def __call__(self, ctx):
return ctx.resolve("hello")
-
- tpl = Template("""{{ callableclass() }}""")
+
+ tpl = Template("""{{ callableclass() }}""")
output = tpl.render(callableclass=CallableClass(), hello="TEST")
expected = "TEST"
-
- assert output == expected
-
- def test_block_set_with_extends(self):
+
+ assert output == expected
+
+ def test_block_set_with_extends(self):
env = Environment(
loader=DictLoader({"main": "{% block body %}[{{ x }}]{% endblock %}"})
)
- t = env.from_string('{% extends "main" %}{% set x %}42{% endset %}')
+ t = env.from_string('{% extends "main" %}{% set x %}42{% endset %}')
assert t.render() == "[42]"
-
- def test_nested_for_else(self, env):
+
+ def test_nested_for_else(self, env):
tmpl = env.from_string(
"{% for x in y %}{{ loop.index0 }}{% else %}"
"{% for i in range(3) %}{{ i }}{% endfor %}"
"{% endfor %}"
)
assert tmpl.render() == "012"
-
- def test_macro_var_bug(self, env):
+
+ def test_macro_var_bug(self, env):
tmpl = env.from_string(
"""
- {% set i = 1 %}
- {% macro test() %}
- {% for i in range(0, 10) %}{{ i }}{% endfor %}
- {% endmacro %}{{ test() }}
+ {% set i = 1 %}
+ {% macro test() %}
+ {% for i in range(0, 10) %}{{ i }}{% endfor %}
+ {% endmacro %}{{ test() }}
"""
)
assert tmpl.render().strip() == "0123456789"
-
- def test_macro_var_bug_advanced(self, env):
+
+ def test_macro_var_bug_advanced(self, env):
tmpl = env.from_string(
"""
- {% macro outer() %}
- {% set i = 1 %}
- {% macro test() %}
- {% for i in range(0, 10) %}{{ i }}{% endfor %}
- {% endmacro %}{{ test() }}
- {% endmacro %}{{ outer() }}
+ {% macro outer() %}
+ {% set i = 1 %}
+ {% macro test() %}
+ {% for i in range(0, 10) %}{{ i }}{% endfor %}
+ {% endmacro %}{{ test() }}
+ {% endmacro %}{{ outer() }}
"""
)
assert tmpl.render().strip() == "0123456789"
-
- def test_callable_defaults(self):
- env = Environment()
+
+ def test_callable_defaults(self):
+ env = Environment()
env.globals["get_int"] = lambda: 42
t = env.from_string(
"""
- {% macro test(a, b, c=get_int()) -%}
- {{ a + b + c }}
- {%- endmacro %}
- {{ test(1, 2) }}|{{ test(1, 2, 3) }}
+ {% macro test(a, b, c=get_int()) -%}
+ {{ a + b + c }}
+ {%- endmacro %}
+ {{ test(1, 2) }}|{{ test(1, 2, 3) }}
"""
)
assert t.render().strip() == "45|6"
-
- def test_macro_escaping(self):
+
+ def test_macro_escaping(self):
env = Environment(autoescape=lambda x: False)
- template = "{% macro m() %}<html>{% endmacro %}"
- template += "{% autoescape true %}{{ m() }}{% endautoescape %}"
- assert env.from_string(template).render()
-
- def test_macro_scoping(self, env):
+ template = "{% macro m() %}<html>{% endmacro %}"
+ template += "{% autoescape true %}{{ m() }}{% endautoescape %}"
+ assert env.from_string(template).render()
+
+ def test_macro_scoping(self, env):
tmpl = env.from_string(
"""
- {% set n=[1,2,3,4,5] %}
- {% for n in [[1,2,3], [3,4,5], [5,6,7]] %}
-
- {% macro x(l) %}
- {{ l.pop() }}
- {% if l %}{{ x(l) }}{% endif %}
- {% endmacro %}
-
- {{ x(n) }}
-
- {% endfor %}
+ {% set n=[1,2,3,4,5] %}
+ {% for n in [[1,2,3], [3,4,5], [5,6,7]] %}
+
+ {% macro x(l) %}
+ {{ l.pop() }}
+ {% if l %}{{ x(l) }}{% endif %}
+ {% endmacro %}
+
+ {{ x(n) }}
+
+ {% endfor %}
"""
)
assert list(map(int, tmpl.render().split())) == [3, 2, 1, 5, 4, 3, 7, 6, 5]
-
- def test_scopes_and_blocks(self):
+
+ def test_scopes_and_blocks(self):
env = Environment(
loader=DictLoader(
{
"a.html": """
- {%- set foo = 'bar' -%}
- {% include 'x.html' -%}
+ {%- set foo = 'bar' -%}
+ {% include 'x.html' -%}
""",
"b.html": """
- {%- set foo = 'bar' -%}
- {% block test %}{% include 'x.html' %}{% endblock -%}
+ {%- set foo = 'bar' -%}
+ {% block test %}{% include 'x.html' %}{% endblock -%}
""",
"c.html": """
- {%- set foo = 'bar' -%}
- {% block test %}{% set foo = foo
- %}{% include 'x.html' %}{% endblock -%}
+ {%- set foo = 'bar' -%}
+ {% block test %}{% set foo = foo
+ %}{% include 'x.html' %}{% endblock -%}
""",
"x.html": """{{ foo }}|{{ test }}""",
}
)
)
-
+
a = env.get_template("a.html")
b = env.get_template("b.html")
c = env.get_template("c.html")
-
+
assert a.render(test="x").strip() == "bar|x"
assert b.render(test="x").strip() == "bar|x"
assert c.render(test="x").strip() == "bar|x"
-
- def test_scopes_and_include(self):
+
+ def test_scopes_and_include(self):
env = Environment(
loader=DictLoader(
{
@@ -428,54 +428,54 @@ class TestBug:
)
t = env.get_template("child.html")
assert t.render() == "42"
-
- def test_caller_scoping(self, env):
+
+ def test_caller_scoping(self, env):
t = env.from_string(
"""
- {% macro detail(icon, value) -%}
- {% if value -%}
- <p><span class="fa fa-fw fa-{{ icon }}"></span>
- {%- if caller is undefined -%}
- {{ value }}
- {%- else -%}
- {{ caller(value, *varargs) }}
- {%- endif -%}</p>
- {%- endif %}
- {%- endmacro %}
-
-
- {% macro link_detail(icon, value, href) -%}
- {% call(value, href) detail(icon, value, href) -%}
- <a href="{{ href }}">{{ value }}</a>
- {%- endcall %}
- {%- endmacro %}
+ {% macro detail(icon, value) -%}
+ {% if value -%}
+ <p><span class="fa fa-fw fa-{{ icon }}"></span>
+ {%- if caller is undefined -%}
+ {{ value }}
+ {%- else -%}
+ {{ caller(value, *varargs) }}
+ {%- endif -%}</p>
+ {%- endif %}
+ {%- endmacro %}
+
+
+ {% macro link_detail(icon, value, href) -%}
+ {% call(value, href) detail(icon, value, href) -%}
+ <a href="{{ href }}">{{ value }}</a>
+ {%- endcall %}
+ {%- endmacro %}
"""
)
-
+
assert t.module.link_detail("circle", "Index", "/") == (
'<p><span class="fa fa-fw fa-circle"></span><a href="/">Index</a></p>'
)
-
- def test_variable_reuse(self, env):
+
+ def test_variable_reuse(self, env):
t = env.from_string("{% for x in x.y %}{{ x }}{% endfor %}")
assert t.render(x={"y": [0, 1, 2]}) == "012"
-
+
t = env.from_string("{% for x in x.y %}{{ loop.index0 }}|{{ x }}{% endfor %}")
assert t.render(x={"y": [0, 1, 2]}) == "0|01|12|2"
-
+
t = env.from_string("{% for x in x.y recursive %}{{ x }}{% endfor %}")
assert t.render(x={"y": [0, 1, 2]}) == "012"
-
- def test_double_caller(self, env):
+
+ def test_double_caller(self, env):
t = env.from_string(
"{% macro x(caller=none) %}[{% if caller %}"
"{{ caller() }}{% endif %}]{% endmacro %}"
"{{ x() }}{% call x() %}aha!{% endcall %}"
)
assert t.render() == "[][aha!]"
-
- def test_double_caller_no_default(self, env):
- with pytest.raises(TemplateAssertionError) as exc_info:
+
+ def test_double_caller_no_default(self, env):
+ with pytest.raises(TemplateAssertionError) as exc_info:
env.from_string(
"{% macro x(caller) %}[{% if caller %}"
"{{ caller() }}{% endif %}]{% endmacro %}"
@@ -483,59 +483,59 @@ class TestBug:
assert exc_info.match(
r'"caller" argument must be omitted or ' r"be given a default"
)
-
+
t = env.from_string(
"{% macro x(caller=none) %}[{% if caller %}"
"{{ caller() }}{% endif %}]{% endmacro %}"
)
- with pytest.raises(TypeError) as exc_info:
- t.module.x(None, caller=lambda: 42)
+ with pytest.raises(TypeError) as exc_info:
+ t.module.x(None, caller=lambda: 42)
assert exc_info.match(
r"\'x\' was invoked with two values for the " r"special caller argument"
)
-
- def test_macro_blocks(self, env):
+
+ def test_macro_blocks(self, env):
t = env.from_string(
"{% macro x() %}{% block foo %}x{% endblock %}{% endmacro %}{{ x() }}"
)
assert t.render() == "x"
-
- def test_scoped_block(self, env):
+
+ def test_scoped_block(self, env):
t = env.from_string(
"{% set x = 1 %}{% with x = 2 %}{% block y scoped %}"
"{{ x }}{% endblock %}{% endwith %}"
)
assert t.render() == "2"
-
- def test_recursive_loop_filter(self, env):
+
+ def test_recursive_loop_filter(self, env):
t = env.from_string(
"""
- <?xml version="1.0" encoding="UTF-8"?>
- <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
- {%- for page in [site.root] if page.url != this recursive %}
- <url><loc>{{ page.url }}</loc></url>
- {{- loop(page.children) }}
- {%- endfor %}
- </urlset>
+ <?xml version="1.0" encoding="UTF-8"?>
+ <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
+ {%- for page in [site.root] if page.url != this recursive %}
+ <url><loc>{{ page.url }}</loc></url>
+ {{- loop(page.children) }}
+ {%- endfor %}
+ </urlset>
"""
)
sm = t.render(
this="/foo",
site={"root": {"url": "/", "children": [{"url": "/foo"}, {"url": "/bar"}]}},
)
- lines = [x.strip() for x in sm.splitlines() if x.strip()]
- assert lines == [
- '<?xml version="1.0" encoding="UTF-8"?>',
- '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
+ lines = [x.strip() for x in sm.splitlines() if x.strip()]
+ assert lines == [
+ '<?xml version="1.0" encoding="UTF-8"?>',
+ '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
"<url><loc>/</loc></url>",
"<url><loc>/bar</loc></url>",
"</urlset>",
- ]
-
- def test_empty_if(self, env):
+ ]
+
+ def test_empty_if(self, env):
t = env.from_string("{% if foo %}{% else %}42{% endif %}")
assert t.render(foo=False) == "42"
-
+
def test_subproperty_if(self, env):
t = env.from_string(
"{% if object1.subproperty1 is eq object2.subproperty2 %}42{% endif %}"
@@ -547,7 +547,7 @@ class TestBug:
== "42"
)
- def test_set_and_include(self):
+ def test_set_and_include(self):
env = Environment(
loader=DictLoader(
{
@@ -557,8 +557,8 @@ class TestBug:
)
)
assert env.get_template("main").render() == "foobar"
-
- def test_loop_include(self):
+
+ def test_loop_include(self):
env = Environment(
loader=DictLoader(
{
@@ -568,34 +568,34 @@ class TestBug:
)
)
assert env.get_template("main").render() == "123"
-
- def test_grouper_repr(self):
- from jinja2.filters import _GroupTuple
+
+ def test_grouper_repr(self):
+ from jinja2.filters import _GroupTuple
t = _GroupTuple("foo", [1, 2])
assert t.grouper == "foo"
- assert t.list == [1, 2]
- assert repr(t) == "('foo', [1, 2])"
- assert str(t) == "('foo', [1, 2])"
-
- def test_custom_context(self, env):
- from jinja2.runtime import Context
-
- class MyContext(Context):
- pass
-
- class MyEnvironment(Environment):
- context_class = MyContext
-
+ assert t.list == [1, 2]
+ assert repr(t) == "('foo', [1, 2])"
+ assert str(t) == "('foo', [1, 2])"
+
+ def test_custom_context(self, env):
+ from jinja2.runtime import Context
+
+ class MyContext(Context):
+ pass
+
+ class MyEnvironment(Environment):
+ context_class = MyContext
+
loader = DictLoader({"base": "{{ foobar }}", "test": '{% extends "base" %}'})
- env = MyEnvironment(loader=loader)
+ env = MyEnvironment(loader=loader)
assert env.get_template("test").render(foobar="test") == "test"
-
- def test_legacy_custom_context(self, env):
+
+ def test_legacy_custom_context(self, env):
from jinja2.runtime import Context, missing
-
+
with pytest.deprecated_call():
-
+
class MyContext(Context):
def resolve(self, name):
if name == "foo":
@@ -603,12 +603,12 @@ class TestBug:
return super().resolve(name)
x = MyContext(env, parent={"bar": 23}, name="foo", blocks={})
- assert x._legacy_resolve_mode
+ assert x._legacy_resolve_mode
assert x.resolve_or_missing("foo") == 42
assert x.resolve_or_missing("bar") == 23
assert x.resolve_or_missing("baz") is missing
-
- def test_recursive_loop_bug(self, env):
+
+ def test_recursive_loop_bug(self, env):
tmpl = env.from_string(
"{%- for value in values recursive %}1{% else %}0{% endfor -%}"
)
diff --git a/contrib/python/Jinja2/py3/tests/test_security.py b/contrib/python/Jinja2/py3/tests/test_security.py
index 0e8dc5c038..d045c30f8b 100644
--- a/contrib/python/Jinja2/py3/tests/test_security.py
+++ b/contrib/python/Jinja2/py3/tests/test_security.py
@@ -1,67 +1,67 @@
-import pytest
+import pytest
from markupsafe import escape
-
-from jinja2 import Environment
+
+from jinja2 import Environment
from jinja2.exceptions import SecurityError
from jinja2.exceptions import TemplateRuntimeError
from jinja2.exceptions import TemplateSyntaxError
-from jinja2.nodes import EvalContext
+from jinja2.nodes import EvalContext
from jinja2.sandbox import ImmutableSandboxedEnvironment
from jinja2.sandbox import SandboxedEnvironment
from jinja2.sandbox import unsafe
-
-
+
+
class PrivateStuff:
- def bar(self):
- return 23
-
- @unsafe
- def foo(self):
- return 42
-
- def __repr__(self):
+ def bar(self):
+ return 23
+
+ @unsafe
+ def foo(self):
+ return 42
+
+ def __repr__(self):
return "PrivateStuff"
-
-
+
+
class PublicStuff:
def bar(self):
return 23
-
+
def _foo(self):
return 42
- def __repr__(self):
+ def __repr__(self):
return "PublicStuff"
-
-
+
+
class TestSandbox:
- def test_unsafe(self, env):
- env = SandboxedEnvironment()
+ def test_unsafe(self, env):
+ env = SandboxedEnvironment()
pytest.raises(
SecurityError, env.from_string("{{ foo.foo() }}").render, foo=PrivateStuff()
)
assert env.from_string("{{ foo.bar() }}").render(foo=PrivateStuff()) == "23"
-
+
pytest.raises(
SecurityError, env.from_string("{{ foo._foo() }}").render, foo=PublicStuff()
)
assert env.from_string("{{ foo.bar() }}").render(foo=PublicStuff()) == "23"
assert env.from_string("{{ foo.__class__ }}").render(foo=42) == ""
assert env.from_string("{{ foo.func_code }}").render(foo=lambda: None) == ""
- # security error comes from __class__ already.
+ # security error comes from __class__ already.
pytest.raises(
SecurityError,
env.from_string("{{ foo.__class__.__subclasses__() }}").render,
foo=42,
)
-
- def test_immutable_environment(self, env):
- env = ImmutableSandboxedEnvironment()
+
+ def test_immutable_environment(self, env):
+ env = ImmutableSandboxedEnvironment()
pytest.raises(SecurityError, env.from_string("{{ [].append(23) }}").render)
pytest.raises(SecurityError, env.from_string("{{ {1:2}.clear() }}").render)
-
- def test_restricted(self, env):
- env = SandboxedEnvironment()
+
+ def test_restricted(self, env):
+ env = SandboxedEnvironment()
pytest.raises(
TemplateSyntaxError,
env.from_string,
@@ -72,78 +72,78 @@ class TestSandbox:
env.from_string,
"{% for foo, bar.baz in seq %}...{% endfor %}",
)
-
- def test_template_data(self, env):
- env = Environment(autoescape=True)
+
+ def test_template_data(self, env):
+ env = Environment(autoescape=True)
t = env.from_string(
"{% macro say_hello(name) %}"
"<p>Hello {{ name }}!</p>{% endmacro %}"
'{{ say_hello("<blink>foo</blink>") }}'
)
escaped_out = "<p>Hello &lt;blink&gt;foo&lt;/blink&gt;!</p>"
- assert t.render() == escaped_out
+ assert t.render() == escaped_out
assert str(t.module) == escaped_out
- assert escape(t.module) == escaped_out
+ assert escape(t.module) == escaped_out
assert t.module.say_hello("<blink>foo</blink>") == escaped_out
assert (
escape(t.module.say_hello(EvalContext(env), "<blink>foo</blink>"))
== escaped_out
)
assert escape(t.module.say_hello("<blink>foo</blink>")) == escaped_out
-
- def test_attr_filter(self, env):
- env = SandboxedEnvironment()
- tmpl = env.from_string('{{ cls|attr("__subclasses__")() }}')
- pytest.raises(SecurityError, tmpl.render, cls=int)
-
- def test_binary_operator_intercepting(self, env):
- def disable_op(left, right):
+
+ def test_attr_filter(self, env):
+ env = SandboxedEnvironment()
+ tmpl = env.from_string('{{ cls|attr("__subclasses__")() }}')
+ pytest.raises(SecurityError, tmpl.render, cls=int)
+
+ def test_binary_operator_intercepting(self, env):
+ def disable_op(left, right):
raise TemplateRuntimeError("that operator so does not work")
for expr, ctx, rv in ("1 + 2", {}, "3"), ("a + 2", {"a": 2}, "4"):
- env = SandboxedEnvironment()
+ env = SandboxedEnvironment()
env.binop_table["+"] = disable_op
t = env.from_string(f"{{{{ {expr} }}}}")
- assert t.render(ctx) == rv
+ assert t.render(ctx) == rv
env.intercepted_binops = frozenset(["+"])
t = env.from_string(f"{{{{ {expr} }}}}")
with pytest.raises(TemplateRuntimeError):
- t.render(ctx)
-
- def test_unary_operator_intercepting(self, env):
- def disable_op(arg):
+ t.render(ctx)
+
+ def test_unary_operator_intercepting(self, env):
+ def disable_op(arg):
raise TemplateRuntimeError("that operator so does not work")
for expr, ctx, rv in ("-1", {}, "-1"), ("-a", {"a": 2}, "-2"):
- env = SandboxedEnvironment()
+ env = SandboxedEnvironment()
env.unop_table["-"] = disable_op
t = env.from_string(f"{{{{ {expr} }}}}")
- assert t.render(ctx) == rv
+ assert t.render(ctx) == rv
env.intercepted_unops = frozenset(["-"])
t = env.from_string(f"{{{{ {expr} }}}}")
with pytest.raises(TemplateRuntimeError):
- t.render(ctx)
-
-
+ t.render(ctx)
+
+
class TestStringFormat:
- def test_basic_format_safety(self):
- env = SandboxedEnvironment()
- t = env.from_string('{{ "a{0.__class__}b".format(42) }}')
+ def test_basic_format_safety(self):
+ env = SandboxedEnvironment()
+ t = env.from_string('{{ "a{0.__class__}b".format(42) }}')
assert t.render() == "ab"
-
- def test_basic_format_all_okay(self):
- env = SandboxedEnvironment()
- t = env.from_string('{{ "a{0.foo}b".format({"foo": 42}) }}')
+
+ def test_basic_format_all_okay(self):
+ env = SandboxedEnvironment()
+ t = env.from_string('{{ "a{0.foo}b".format({"foo": 42}) }}')
assert t.render() == "a42b"
-
- def test_safe_format_safety(self):
- env = SandboxedEnvironment()
- t = env.from_string('{{ ("a{0.__class__}b{1}"|safe).format(42, "<foo>") }}')
+
+ def test_safe_format_safety(self):
+ env = SandboxedEnvironment()
+ t = env.from_string('{{ ("a{0.__class__}b{1}"|safe).format(42, "<foo>") }}')
assert t.render() == "ab&lt;foo&gt;"
-
- def test_safe_format_all_okay(self):
- env = SandboxedEnvironment()
- t = env.from_string('{{ ("a{0.foo}b{1}"|safe).format({"foo": 42}, "<foo>") }}')
+
+ def test_safe_format_all_okay(self):
+ env = SandboxedEnvironment()
+ t = env.from_string('{{ ("a{0.foo}b{1}"|safe).format({"foo": 42}, "<foo>") }}')
assert t.render() == "a42b&lt;foo&gt;"
def test_empty_braces_format(self):
diff --git a/contrib/python/Jinja2/py3/tests/test_tests.py b/contrib/python/Jinja2/py3/tests/test_tests.py
index 75178d6adf..1fc5fe9fed 100644
--- a/contrib/python/Jinja2/py3/tests/test_tests.py
+++ b/contrib/python/Jinja2/py3/tests/test_tests.py
@@ -1,32 +1,32 @@
import pytest
from markupsafe import Markup
-
+
from jinja2 import Environment
from jinja2 import TemplateAssertionError
from jinja2 import TemplateRuntimeError
-
-
+
+
class MyDict(dict):
pass
-
-
+
+
class TestTestsCase:
- def test_defined(self, env):
+ def test_defined(self, env):
tmpl = env.from_string("{{ missing is defined }}|{{ true is defined }}")
assert tmpl.render() == "False|True"
-
- def test_even(self, env):
+
+ def test_even(self, env):
tmpl = env.from_string("""{{ 1 is even }}|{{ 2 is even }}""")
assert tmpl.render() == "False|True"
-
- def test_odd(self, env):
+
+ def test_odd(self, env):
tmpl = env.from_string("""{{ 1 is odd }}|{{ 2 is odd }}""")
assert tmpl.render() == "True|False"
-
- def test_lower(self, env):
+
+ def test_lower(self, env):
tmpl = env.from_string("""{{ "foo" is lower }}|{{ "FOO" is lower }}""")
assert tmpl.render() == "True|False"
-
+
# Test type checks
@pytest.mark.parametrize(
"op,expect",
@@ -113,27 +113,27 @@ class TestTestsCase:
def test_types(self, env, op, expect):
t = env.from_string(f"{{{{ {op} }}}}")
assert t.render(mydict=MyDict(), complex=complex(1, 2)) == str(expect)
-
- def test_upper(self, env):
- tmpl = env.from_string('{{ "FOO" is upper }}|{{ "foo" is upper }}')
+
+ def test_upper(self, env):
+ tmpl = env.from_string('{{ "FOO" is upper }}|{{ "foo" is upper }}')
assert tmpl.render() == "True|False"
-
- def test_equalto(self, env):
- tmpl = env.from_string(
+
+ def test_equalto(self, env):
+ tmpl = env.from_string(
"{{ foo is eq 12 }}|"
"{{ foo is eq 0 }}|"
"{{ foo is eq (3 * 4) }}|"
- '{{ bar is eq "baz" }}|'
- '{{ bar is eq "zab" }}|'
- '{{ bar is eq ("ba" + "z") }}|'
+ '{{ bar is eq "baz" }}|'
+ '{{ bar is eq "zab" }}|'
+ '{{ bar is eq ("ba" + "z") }}|'
"{{ bar is eq bar }}|"
"{{ bar is eq foo }}"
- )
+ )
assert (
tmpl.render(foo=12, bar="baz")
== "True|False|True|True|False|True|True|False"
)
-
+
@pytest.mark.parametrize(
"op,expect",
(
@@ -151,39 +151,39 @@ class TestTestsCase:
("ge 3", False),
),
)
- def test_compare_aliases(self, env, op, expect):
+ def test_compare_aliases(self, env, op, expect):
t = env.from_string(f"{{{{ 2 is {op} }}}}")
- assert t.render() == str(expect)
-
- def test_sameas(self, env):
+ assert t.render() == str(expect)
+
+ def test_sameas(self, env):
tmpl = env.from_string("{{ foo is sameas false }}|{{ 0 is sameas false }}")
assert tmpl.render(foo=False) == "True|False"
-
- def test_no_paren_for_arg1(self, env):
+
+ def test_no_paren_for_arg1(self, env):
tmpl = env.from_string("{{ foo is sameas none }}")
assert tmpl.render(foo=None) == "True"
-
- def test_escaped(self, env):
- env = Environment(autoescape=True)
+
+ def test_escaped(self, env):
+ env = Environment(autoescape=True)
tmpl = env.from_string("{{ x is escaped }}|{{ y is escaped }}")
assert tmpl.render(x="foo", y=Markup("foo")) == "False|True"
-
- def test_greaterthan(self, env):
+
+ def test_greaterthan(self, env):
tmpl = env.from_string("{{ 1 is greaterthan 0 }}|{{ 0 is greaterthan 1 }}")
assert tmpl.render() == "True|False"
-
- def test_lessthan(self, env):
+
+ def test_lessthan(self, env):
tmpl = env.from_string("{{ 0 is lessthan 1 }}|{{ 1 is lessthan 0 }}")
assert tmpl.render() == "True|False"
+
+ def test_multiple_tests(self):
+ items = []
- def test_multiple_tests(self):
- items = []
+ def matching(x, y):
+ items.append((x, y))
+ return False
- def matching(x, y):
- items.append((x, y))
- return False
-
- env = Environment()
+ env = Environment()
env.tests["matching"] = matching
tmpl = env.from_string(
"{{ 'us-west-1' is matching '(us-east-1|ap-northeast-1)'"
@@ -194,8 +194,8 @@ class TestTestsCase:
("us-west-1", "(us-east-1|ap-northeast-1)"),
("stage", "(dev|stage)"),
]
-
- def test_in(self, env):
+
+ def test_in(self, env):
tmpl = env.from_string(
'{{ "o" is in "foo" }}|'
'{{ "foo" is in "foo" }}|'
diff --git a/contrib/python/Jinja2/py3/tests/test_utils.py b/contrib/python/Jinja2/py3/tests/test_utils.py
index feaf8dc1d4..7f3e3614cd 100644
--- a/contrib/python/Jinja2/py3/tests/test_utils.py
+++ b/contrib/python/Jinja2/py3/tests/test_utils.py
@@ -2,10 +2,10 @@ import pickle
import random
from collections import deque
from copy import copy as shallow_copy
-
-import pytest
+
+import pytest
from markupsafe import Markup
-
+
from jinja2.utils import consume
from jinja2.utils import generate_lorem_ipsum
from jinja2.utils import LRUCache
@@ -13,18 +13,18 @@ from jinja2.utils import missing
from jinja2.utils import object_type_repr
from jinja2.utils import select_autoescape
from jinja2.utils import urlize
-
-
+
+
class TestLRUCache:
- def test_simple(self):
- d = LRUCache(3)
- d["a"] = 1
- d["b"] = 2
- d["c"] = 3
- d["a"]
- d["d"] = 4
+ def test_simple(self):
+ d = LRUCache(3)
+ d["a"] = 1
+ d["b"] = 2
+ d["c"] = 3
+ d["a"]
+ d["d"] = 4
assert d.keys() == ["d", "a", "c"]
-
+
def test_values(self):
cache = LRUCache(3)
cache["b"] = 1
@@ -35,18 +35,18 @@ class TestLRUCache:
cache = LRUCache(2)
assert cache.values() == []
- def test_pickleable(self):
- cache = LRUCache(2)
- cache["foo"] = 42
- cache["bar"] = 23
- cache["foo"]
-
- for protocol in range(3):
- copy = pickle.loads(pickle.dumps(cache, protocol))
- assert copy.capacity == cache.capacity
- assert copy._mapping == cache._mapping
- assert copy._queue == cache._queue
-
+ def test_pickleable(self):
+ cache = LRUCache(2)
+ cache["foo"] = 42
+ cache["bar"] = 23
+ cache["foo"]
+
+ for protocol in range(3):
+ copy = pickle.loads(pickle.dumps(cache, protocol))
+ assert copy.capacity == cache.capacity
+ assert copy._mapping == cache._mapping
+ assert copy._queue == cache._queue
+
@pytest.mark.parametrize("copy_func", [LRUCache.copy, shallow_copy])
def test_copy(self, copy_func):
cache = LRUCache(2)
@@ -57,7 +57,7 @@ class TestLRUCache:
copy["c"] = 3
assert copy._queue != cache._queue
assert copy.keys() == ["c", "b"]
-
+
def test_clear(self):
d = LRUCache(3)
d["a"] = 1
@@ -104,24 +104,24 @@ class TestLRUCache:
class TestHelpers:
- def test_object_type_repr(self):
+ def test_object_type_repr(self):
class X:
- pass
-
+ pass
+
assert object_type_repr(42) == "int object"
assert object_type_repr([]) == "list object"
assert object_type_repr(X()) == "__tests__.test_utils.X object"
assert object_type_repr(None) == "None"
assert object_type_repr(Ellipsis) == "Ellipsis"
- def test_autoescape_select(self):
- func = select_autoescape(
+ def test_autoescape_select(self):
+ func = select_autoescape(
enabled_extensions=("html", ".htm"),
disabled_extensions=("txt",),
default_for_string="STRING",
default="NONE",
- )
-
+ )
+
assert func(None) == "STRING"
assert func("unknown.foo") == "NONE"
assert func("foo.html")
@@ -129,12 +129,12 @@ class TestHelpers:
assert not func("foo.txt")
assert func("FOO.HTML")
assert not func("FOO.TXT")
-
-
+
+
class TestEscapeUrlizeTarget:
- def test_escape_urlize_target(self):
- url = "http://example.org"
- target = "<script>"
+ def test_escape_urlize_target(self):
+ url = "http://example.org"
+ target = "<script>"
assert urlize(url, target=target) == (
'<a href="http://example.org"'
' target="&lt;script&gt;">'
diff --git a/contrib/python/Jinja2/py3/ya.make b/contrib/python/Jinja2/py3/ya.make
index 3043e7fc3d..c81b7b94e1 100644
--- a/contrib/python/Jinja2/py3/ya.make
+++ b/contrib/python/Jinja2/py3/ya.make
@@ -1,48 +1,48 @@
# Generated by devtools/yamaker (pypi).
PY3_LIBRARY()
-
+
OWNER(floatdrop g:python-contrib)
VERSION(3.0.3)
-
+
LICENSE(BSD-3-Clause)
-
-PEERDIR(
- contrib/python/MarkupSafe
-)
-
+
+PEERDIR(
+ contrib/python/MarkupSafe
+)
+
NO_LINT()
-PY_SRCS(
- TOP_LEVEL
- jinja2/__init__.py
- jinja2/_identifier.py
+PY_SRCS(
+ TOP_LEVEL
+ jinja2/__init__.py
+ jinja2/_identifier.py
jinja2/async_utils.py
- jinja2/bccache.py
- jinja2/compiler.py
- jinja2/constants.py
- jinja2/debug.py
- jinja2/defaults.py
- jinja2/environment.py
- jinja2/exceptions.py
- jinja2/ext.py
- jinja2/filters.py
- jinja2/idtracking.py
- jinja2/lexer.py
- jinja2/loaders.py
- jinja2/meta.py
- jinja2/nativetypes.py
- jinja2/nodes.py
- jinja2/optimizer.py
- jinja2/parser.py
- jinja2/runtime.py
- jinja2/sandbox.py
- jinja2/tests.py
- jinja2/utils.py
- jinja2/visitor.py
-)
-
+ jinja2/bccache.py
+ jinja2/compiler.py
+ jinja2/constants.py
+ jinja2/debug.py
+ jinja2/defaults.py
+ jinja2/environment.py
+ jinja2/exceptions.py
+ jinja2/ext.py
+ jinja2/filters.py
+ jinja2/idtracking.py
+ jinja2/lexer.py
+ jinja2/loaders.py
+ jinja2/meta.py
+ jinja2/nativetypes.py
+ jinja2/nodes.py
+ jinja2/optimizer.py
+ jinja2/parser.py
+ jinja2/runtime.py
+ jinja2/sandbox.py
+ jinja2/tests.py
+ jinja2/utils.py
+ jinja2/visitor.py
+)
+
RESOURCE_FILES(
PREFIX contrib/python/Jinja2/py3/
.dist-info/METADATA
@@ -51,7 +51,7 @@ RESOURCE_FILES(
jinja2/py.typed
)
-END()
+END()
RECURSE_FOR_TESTS(
tests
diff --git a/contrib/python/Jinja2/ya.make b/contrib/python/Jinja2/ya.make
index 40f6572401..0b283b9bdf 100644
--- a/contrib/python/Jinja2/ya.make
+++ b/contrib/python/Jinja2/ya.make
@@ -1,18 +1,18 @@
PY23_LIBRARY()
-
+
LICENSE(Service-Py23-Proxy)
OWNER(g:python-contrib)
-
+
IF (PYTHON2)
PEERDIR(contrib/python/Jinja2/py2)
ELSE()
PEERDIR(contrib/python/Jinja2/py3)
ENDIF()
-NO_LINT()
-
-END()
+NO_LINT()
+
+END()
RECURSE(
examples
diff --git a/contrib/python/botocore/botocore/data/endpoints.json b/contrib/python/botocore/botocore/data/endpoints.json
index 6564eaa04a..fd1c33e302 100644
--- a/contrib/python/botocore/botocore/data/endpoints.json
+++ b/contrib/python/botocore/botocore/data/endpoints.json
@@ -2766,7 +2766,7 @@
"endpoints" : {
"us-east-1" : { }
}
- },
+ },
"es" : {
"endpoints" : {
"af-south-1" : { },
@@ -5412,12 +5412,12 @@
}
}
},
- "s3" : {
- "defaults" : {
- "protocols" : [ "http", "https" ],
- "signatureVersions" : [ "s3v4" ]
- },
- "endpoints" : {
+ "s3" : {
+ "defaults" : {
+ "protocols" : [ "http", "https" ],
+ "signatureVersions" : [ "s3v4" ]
+ },
+ "endpoints" : {
"accesspoint-af-south-1" : {
"hostname" : "s3-accesspoint.af-south-1.amazonaws.com",
"signatureVersions" : [ "s3v4" ]
@@ -5504,21 +5504,21 @@
},
"af-south-1" : { },
"ap-east-1" : { },
- "ap-northeast-1" : {
- "hostname" : "s3.ap-northeast-1.amazonaws.com",
- "signatureVersions" : [ "s3", "s3v4" ]
- },
- "ap-northeast-2" : { },
+ "ap-northeast-1" : {
+ "hostname" : "s3.ap-northeast-1.amazonaws.com",
+ "signatureVersions" : [ "s3", "s3v4" ]
+ },
+ "ap-northeast-2" : { },
"ap-northeast-3" : { },
- "ap-south-1" : { },
- "ap-southeast-1" : {
- "hostname" : "s3.ap-southeast-1.amazonaws.com",
- "signatureVersions" : [ "s3", "s3v4" ]
- },
- "ap-southeast-2" : {
- "hostname" : "s3.ap-southeast-2.amazonaws.com",
- "signatureVersions" : [ "s3", "s3v4" ]
- },
+ "ap-south-1" : { },
+ "ap-southeast-1" : {
+ "hostname" : "s3.ap-southeast-1.amazonaws.com",
+ "signatureVersions" : [ "s3", "s3v4" ]
+ },
+ "ap-southeast-2" : {
+ "hostname" : "s3.ap-southeast-2.amazonaws.com",
+ "signatureVersions" : [ "s3", "s3v4" ]
+ },
"aws-global" : {
"credentialScope" : {
"region" : "us-east-1"
@@ -5526,16 +5526,16 @@
"hostname" : "s3.amazonaws.com",
"signatureVersions" : [ "s3", "s3v4" ]
},
- "ca-central-1" : { },
- "eu-central-1" : { },
+ "ca-central-1" : { },
+ "eu-central-1" : { },
"eu-north-1" : { },
"eu-south-1" : { },
- "eu-west-1" : {
- "hostname" : "s3.eu-west-1.amazonaws.com",
- "signatureVersions" : [ "s3", "s3v4" ]
- },
- "eu-west-2" : { },
- "eu-west-3" : { },
+ "eu-west-1" : {
+ "hostname" : "s3.eu-west-1.amazonaws.com",
+ "signatureVersions" : [ "s3", "s3v4" ]
+ },
+ "eu-west-2" : { },
+ "eu-west-3" : { },
"fips-accesspoint-ca-central-1" : {
"hostname" : "s3-accesspoint-fips.ca-central-1.amazonaws.com",
"signatureVersions" : [ "s3v4" ]
@@ -5557,32 +5557,32 @@
"signatureVersions" : [ "s3v4" ]
},
"me-south-1" : { },
- "s3-external-1" : {
- "credentialScope" : {
- "region" : "us-east-1"
- },
- "hostname" : "s3-external-1.amazonaws.com",
- "signatureVersions" : [ "s3", "s3v4" ]
- },
- "sa-east-1" : {
- "hostname" : "s3.sa-east-1.amazonaws.com",
- "signatureVersions" : [ "s3", "s3v4" ]
- },
- "us-east-1" : {
+ "s3-external-1" : {
+ "credentialScope" : {
+ "region" : "us-east-1"
+ },
+ "hostname" : "s3-external-1.amazonaws.com",
+ "signatureVersions" : [ "s3", "s3v4" ]
+ },
+ "sa-east-1" : {
+ "hostname" : "s3.sa-east-1.amazonaws.com",
+ "signatureVersions" : [ "s3", "s3v4" ]
+ },
+ "us-east-1" : {
"hostname" : "s3.us-east-1.amazonaws.com",
- "signatureVersions" : [ "s3", "s3v4" ]
- },
- "us-east-2" : { },
- "us-west-1" : {
- "hostname" : "s3.us-west-1.amazonaws.com",
- "signatureVersions" : [ "s3", "s3v4" ]
- },
- "us-west-2" : {
- "hostname" : "s3.us-west-2.amazonaws.com",
- "signatureVersions" : [ "s3", "s3v4" ]
- }
- },
- "isRegionalized" : true,
+ "signatureVersions" : [ "s3", "s3v4" ]
+ },
+ "us-east-2" : { },
+ "us-west-1" : {
+ "hostname" : "s3.us-west-1.amazonaws.com",
+ "signatureVersions" : [ "s3", "s3v4" ]
+ },
+ "us-west-2" : {
+ "hostname" : "s3.us-west-2.amazonaws.com",
+ "signatureVersions" : [ "s3", "s3v4" ]
+ }
+ },
+ "isRegionalized" : true,
"partitionEndpoint" : "aws-global"
},
"s3-control" : {
diff --git a/contrib/python/botocore/botocore/data/s3/2006-03-01/examples-1.json b/contrib/python/botocore/botocore/data/s3/2006-03-01/examples-1.json
index 38a47bb331..93a5e868ac 100644
--- a/contrib/python/botocore/botocore/data/s3/2006-03-01/examples-1.json
+++ b/contrib/python/botocore/botocore/data/s3/2006-03-01/examples-1.json
@@ -1,6 +1,6 @@
-{
- "version": "1.0",
- "examples": {
+{
+ "version": "1.0",
+ "examples": {
"AbortMultipartUpload": [
{
"input": {
@@ -1839,5 +1839,5 @@
"title": "To upload a part by copying byte range from an existing object as data source"
}
]
- }
-}
+ }
+}
diff --git a/contrib/python/botocore/botocore/data/s3/2006-03-01/paginators-1.json b/contrib/python/botocore/botocore/data/s3/2006-03-01/paginators-1.json
index d6c97ba480..0ea113ecbf 100644
--- a/contrib/python/botocore/botocore/data/s3/2006-03-01/paginators-1.json
+++ b/contrib/python/botocore/botocore/data/s3/2006-03-01/paginators-1.json
@@ -1,69 +1,69 @@
-{
- "pagination": {
- "ListMultipartUploads": {
- "limit_key": "MaxUploads",
- "more_results": "IsTruncated",
- "output_token": [
- "NextKeyMarker",
- "NextUploadIdMarker"
- ],
- "input_token": [
- "KeyMarker",
- "UploadIdMarker"
- ],
- "result_key": [
- "Uploads",
- "CommonPrefixes"
- ]
- },
- "ListObjectVersions": {
- "more_results": "IsTruncated",
- "limit_key": "MaxKeys",
- "output_token": [
- "NextKeyMarker",
- "NextVersionIdMarker"
- ],
- "input_token": [
- "KeyMarker",
- "VersionIdMarker"
- ],
- "result_key": [
- "Versions",
- "DeleteMarkers",
- "CommonPrefixes"
- ]
- },
- "ListObjects": {
- "more_results": "IsTruncated",
- "limit_key": "MaxKeys",
- "output_token": "NextMarker || Contents[-1].Key",
- "input_token": "Marker",
- "result_key": [
- "Contents",
- "CommonPrefixes"
- ]
- },
- "ListObjectsV2": {
- "more_results": "IsTruncated",
- "limit_key": "MaxKeys",
- "output_token": "NextContinuationToken",
- "input_token": "ContinuationToken",
- "result_key": [
- "Contents",
- "CommonPrefixes"
- ]
- },
- "ListParts": {
- "more_results": "IsTruncated",
- "limit_key": "MaxParts",
- "output_token": "NextPartNumberMarker",
- "input_token": "PartNumberMarker",
- "result_key": "Parts",
- "non_aggregate_keys": [
- "Initiator",
- "Owner",
- "StorageClass"
- ]
- }
- }
-}
+{
+ "pagination": {
+ "ListMultipartUploads": {
+ "limit_key": "MaxUploads",
+ "more_results": "IsTruncated",
+ "output_token": [
+ "NextKeyMarker",
+ "NextUploadIdMarker"
+ ],
+ "input_token": [
+ "KeyMarker",
+ "UploadIdMarker"
+ ],
+ "result_key": [
+ "Uploads",
+ "CommonPrefixes"
+ ]
+ },
+ "ListObjectVersions": {
+ "more_results": "IsTruncated",
+ "limit_key": "MaxKeys",
+ "output_token": [
+ "NextKeyMarker",
+ "NextVersionIdMarker"
+ ],
+ "input_token": [
+ "KeyMarker",
+ "VersionIdMarker"
+ ],
+ "result_key": [
+ "Versions",
+ "DeleteMarkers",
+ "CommonPrefixes"
+ ]
+ },
+ "ListObjects": {
+ "more_results": "IsTruncated",
+ "limit_key": "MaxKeys",
+ "output_token": "NextMarker || Contents[-1].Key",
+ "input_token": "Marker",
+ "result_key": [
+ "Contents",
+ "CommonPrefixes"
+ ]
+ },
+ "ListObjectsV2": {
+ "more_results": "IsTruncated",
+ "limit_key": "MaxKeys",
+ "output_token": "NextContinuationToken",
+ "input_token": "ContinuationToken",
+ "result_key": [
+ "Contents",
+ "CommonPrefixes"
+ ]
+ },
+ "ListParts": {
+ "more_results": "IsTruncated",
+ "limit_key": "MaxParts",
+ "output_token": "NextPartNumberMarker",
+ "input_token": "PartNumberMarker",
+ "result_key": "Parts",
+ "non_aggregate_keys": [
+ "Initiator",
+ "Owner",
+ "StorageClass"
+ ]
+ }
+ }
+}
diff --git a/contrib/python/botocore/botocore/data/s3/2006-03-01/service-2.json b/contrib/python/botocore/botocore/data/s3/2006-03-01/service-2.json
index 0135cb580d..885cb2e375 100644
--- a/contrib/python/botocore/botocore/data/s3/2006-03-01/service-2.json
+++ b/contrib/python/botocore/botocore/data/s3/2006-03-01/service-2.json
@@ -1,129 +1,129 @@
-{
- "version":"2.0",
- "metadata":{
- "apiVersion":"2006-03-01",
- "checksumFormat":"md5",
- "endpointPrefix":"s3",
- "globalEndpoint":"s3.amazonaws.com",
- "protocol":"rest-xml",
- "serviceAbbreviation":"Amazon S3",
- "serviceFullName":"Amazon Simple Storage Service",
- "serviceId":"S3",
- "signatureVersion":"s3",
- "uid":"s3-2006-03-01"
- },
- "operations":{
- "AbortMultipartUpload":{
- "name":"AbortMultipartUpload",
- "http":{
- "method":"DELETE",
+{
+ "version":"2.0",
+ "metadata":{
+ "apiVersion":"2006-03-01",
+ "checksumFormat":"md5",
+ "endpointPrefix":"s3",
+ "globalEndpoint":"s3.amazonaws.com",
+ "protocol":"rest-xml",
+ "serviceAbbreviation":"Amazon S3",
+ "serviceFullName":"Amazon Simple Storage Service",
+ "serviceId":"S3",
+ "signatureVersion":"s3",
+ "uid":"s3-2006-03-01"
+ },
+ "operations":{
+ "AbortMultipartUpload":{
+ "name":"AbortMultipartUpload",
+ "http":{
+ "method":"DELETE",
"requestUri":"/{Bucket}/{Key+}",
"responseCode":204
- },
- "input":{"shape":"AbortMultipartUploadRequest"},
- "output":{"shape":"AbortMultipartUploadOutput"},
- "errors":[
- {"shape":"NoSuchUpload"}
- ],
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/mpUploadAbort.html",
+ },
+ "input":{"shape":"AbortMultipartUploadRequest"},
+ "output":{"shape":"AbortMultipartUploadOutput"},
+ "errors":[
+ {"shape":"NoSuchUpload"}
+ ],
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/mpUploadAbort.html",
"documentation":"<p>This action aborts a multipart upload. After a multipart upload is aborted, no additional parts can be uploaded using that upload ID. The storage consumed by any previously uploaded parts will be freed. However, if any part uploads are currently in progress, those part uploads might or might not succeed. As a result, it might be necessary to abort a given multipart upload multiple times in order to completely free all storage consumed by all parts. </p> <p>To verify that all parts have been removed, so you don't get charged for the part storage, you should call the <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListParts.html\">ListParts</a> action and ensure that the parts list is empty.</p> <p>For information about permissions required to use the multipart upload, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html\">Multipart Upload and Permissions</a>.</p> <p>The following operations are related to <code>AbortMultipartUpload</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateMultipartUpload.html\">CreateMultipartUpload</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPart.html\">UploadPart</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_CompleteMultipartUpload.html\">CompleteMultipartUpload</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListParts.html\">ListParts</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListMultipartUploads.html\">ListMultipartUploads</a> </p> </li> </ul>"
- },
- "CompleteMultipartUpload":{
- "name":"CompleteMultipartUpload",
- "http":{
- "method":"POST",
- "requestUri":"/{Bucket}/{Key+}"
- },
- "input":{"shape":"CompleteMultipartUploadRequest"},
- "output":{"shape":"CompleteMultipartUploadOutput"},
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/mpUploadComplete.html",
+ },
+ "CompleteMultipartUpload":{
+ "name":"CompleteMultipartUpload",
+ "http":{
+ "method":"POST",
+ "requestUri":"/{Bucket}/{Key+}"
+ },
+ "input":{"shape":"CompleteMultipartUploadRequest"},
+ "output":{"shape":"CompleteMultipartUploadOutput"},
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/mpUploadComplete.html",
"documentation":"<p>Completes a multipart upload by assembling previously uploaded parts.</p> <p>You first initiate the multipart upload and then upload all parts using the <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPart.html\">UploadPart</a> operation. After successfully uploading all relevant parts of an upload, you call this action to complete the upload. Upon receiving this request, Amazon S3 concatenates all the parts in ascending order by part number to create a new object. In the Complete Multipart Upload request, you must provide the parts list. You must ensure that the parts list is complete. This action concatenates the parts that you provide in the list. For each part in the list, you must provide the part number and the <code>ETag</code> value, returned after that part was uploaded.</p> <p>Processing of a Complete Multipart Upload request could take several minutes to complete. After Amazon S3 begins processing the request, it sends an HTTP response header that specifies a 200 OK response. While processing is in progress, Amazon S3 periodically sends white space characters to keep the connection from timing out. Because a request could fail after the initial 200 OK response has been sent, it is important that you check the response body to determine whether the request succeeded.</p> <p>Note that if <code>CompleteMultipartUpload</code> fails, applications should be prepared to retry the failed requests. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/ErrorBestPractices.html\">Amazon S3 Error Best Practices</a>.</p> <p>For more information about multipart uploads, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/uploadobjusingmpu.html\">Uploading Objects Using Multipart Upload</a>.</p> <p>For information about permissions required to use the multipart upload API, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html\">Multipart Upload and Permissions</a>.</p> <p> <code>CompleteMultipartUpload</code> has the following special errors:</p> <ul> <li> <p>Error code: <code>EntityTooSmall</code> </p> <ul> <li> <p>Description: Your proposed upload is smaller than the minimum allowed object size. Each part must be at least 5 MB in size, except the last part.</p> </li> <li> <p>400 Bad Request</p> </li> </ul> </li> <li> <p>Error code: <code>InvalidPart</code> </p> <ul> <li> <p>Description: One or more of the specified parts could not be found. The part might not have been uploaded, or the specified entity tag might not have matched the part's entity tag.</p> </li> <li> <p>400 Bad Request</p> </li> </ul> </li> <li> <p>Error code: <code>InvalidPartOrder</code> </p> <ul> <li> <p>Description: The list of parts was not in ascending order. The parts list must be specified in order by part number.</p> </li> <li> <p>400 Bad Request</p> </li> </ul> </li> <li> <p>Error code: <code>NoSuchUpload</code> </p> <ul> <li> <p>Description: The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed.</p> </li> <li> <p>404 Not Found</p> </li> </ul> </li> </ul> <p>The following operations are related to <code>CompleteMultipartUpload</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateMultipartUpload.html\">CreateMultipartUpload</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPart.html\">UploadPart</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_AbortMultipartUpload.html\">AbortMultipartUpload</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListParts.html\">ListParts</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListMultipartUploads.html\">ListMultipartUploads</a> </p> </li> </ul>"
- },
- "CopyObject":{
- "name":"CopyObject",
- "http":{
- "method":"PUT",
- "requestUri":"/{Bucket}/{Key+}"
- },
- "input":{"shape":"CopyObjectRequest"},
- "output":{"shape":"CopyObjectOutput"},
- "errors":[
- {"shape":"ObjectNotInActiveTierError"}
- ],
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectCOPY.html",
+ },
+ "CopyObject":{
+ "name":"CopyObject",
+ "http":{
+ "method":"PUT",
+ "requestUri":"/{Bucket}/{Key+}"
+ },
+ "input":{"shape":"CopyObjectRequest"},
+ "output":{"shape":"CopyObjectOutput"},
+ "errors":[
+ {"shape":"ObjectNotInActiveTierError"}
+ ],
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectCOPY.html",
"documentation":"<p>Creates a copy of an object that is already stored in Amazon S3.</p> <note> <p>You can store individual objects of up to 5 TB in Amazon S3. You create a copy of your object up to 5 GB in size in a single atomic action using this API. However, to copy an object greater than 5 GB, you must use the multipart upload Upload Part - Copy API. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/CopyingObjctsUsingRESTMPUapi.html\">Copy Object Using the REST Multipart Upload API</a>.</p> </note> <p>All copy requests must be authenticated. Additionally, you must have <i>read</i> access to the source object and <i>write</i> access to the destination bucket. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html\">REST Authentication</a>. Both the Region that you want to copy the object from and the Region that you want to copy the object to must be enabled for your account.</p> <p>A copy request might return an error when Amazon S3 receives the copy request or while Amazon S3 is copying the files. If the error occurs before the copy action starts, you receive a standard Amazon S3 error. If the error occurs during the copy operation, the error response is embedded in the <code>200 OK</code> response. This means that a <code>200 OK</code> response can contain either a success or an error. Design your application to parse the contents of the response and handle it appropriately.</p> <p>If the copy is successful, you receive a response with information about the copied object.</p> <note> <p>If the request is an HTTP 1.1 request, the response is chunk encoded. If it were not, it would not contain the content-length, and you would need to read the entire body.</p> </note> <p>The copy request charge is based on the storage class and Region that you specify for the destination object. For pricing information, see <a href=\"http://aws.amazon.com/s3/pricing/\">Amazon S3 pricing</a>.</p> <important> <p>Amazon S3 transfer acceleration does not support cross-Region copies. If you request a cross-Region copy using a transfer acceleration endpoint, you get a 400 <code>Bad Request</code> error. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/transfer-acceleration.html\">Transfer Acceleration</a>.</p> </important> <p> <b>Metadata</b> </p> <p>When copying an object, you can preserve all metadata (default) or specify new metadata. However, the ACL is not preserved and is set to private for the user making the request. To override the default ACL setting, specify a new ACL when generating a copy request. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/S3_ACLs_UsingACLs.html\">Using ACLs</a>. </p> <p>To specify whether you want the object metadata copied from the source object or replaced with metadata provided in the request, you can optionally add the <code>x-amz-metadata-directive</code> header. When you grant permissions, you can use the <code>s3:x-amz-metadata-directive</code> condition key to enforce certain metadata behavior when objects are uploaded. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/amazon-s3-policy-keys.html\">Specifying Conditions in a Policy</a> in the <i>Amazon S3 User Guide</i>. For a complete list of Amazon S3-specific condition keys, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/list_amazons3.html\">Actions, Resources, and Condition Keys for Amazon S3</a>.</p> <p> <b> <code>x-amz-copy-source-if</code> Headers</b> </p> <p>To only copy an object under certain conditions, such as whether the <code>Etag</code> matches or whether the object was modified before or after a specified date, use the following request parameters:</p> <ul> <li> <p> <code>x-amz-copy-source-if-match</code> </p> </li> <li> <p> <code>x-amz-copy-source-if-none-match</code> </p> </li> <li> <p> <code>x-amz-copy-source-if-unmodified-since</code> </p> </li> <li> <p> <code>x-amz-copy-source-if-modified-since</code> </p> </li> </ul> <p> If both the <code>x-amz-copy-source-if-match</code> and <code>x-amz-copy-source-if-unmodified-since</code> headers are present in the request and evaluate as follows, Amazon S3 returns <code>200 OK</code> and copies the data:</p> <ul> <li> <p> <code>x-amz-copy-source-if-match</code> condition evaluates to true</p> </li> <li> <p> <code>x-amz-copy-source-if-unmodified-since</code> condition evaluates to false</p> </li> </ul> <p>If both the <code>x-amz-copy-source-if-none-match</code> and <code>x-amz-copy-source-if-modified-since</code> headers are present in the request and evaluate as follows, Amazon S3 returns the <code>412 Precondition Failed</code> response code:</p> <ul> <li> <p> <code>x-amz-copy-source-if-none-match</code> condition evaluates to false</p> </li> <li> <p> <code>x-amz-copy-source-if-modified-since</code> condition evaluates to true</p> </li> </ul> <note> <p>All headers with the <code>x-amz-</code> prefix, including <code>x-amz-copy-source</code>, must be signed.</p> </note> <p> <b>Server-side encryption</b> </p> <p>When you perform a CopyObject operation, you can optionally use the appropriate encryption-related headers to encrypt the object using server-side encryption with AWS managed encryption keys (SSE-S3 or SSE-KMS) or a customer-provided encryption key. With server-side encryption, Amazon S3 encrypts your data as it writes it to disks in its data centers and decrypts the data when you access it. For more information about server-side encryption, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/serv-side-encryption.html\">Using Server-Side Encryption</a>.</p> <p>If a target object uses SSE-KMS, you can enable an S3 Bucket Key for the object. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/bucket-key.html\">Amazon S3 Bucket Keys</a> in the <i>Amazon S3 User Guide</i>.</p> <p> <b>Access Control List (ACL)-Specific Request Headers</b> </p> <p>When copying an object, you can optionally use headers to grant ACL-based permissions. By default, all objects are private. Only the owner has full access control. When adding a new object, you can grant permissions to individual AWS accounts or to predefined groups defined by Amazon S3. These permissions are then added to the ACL on the object. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html\">Access Control List (ACL) Overview</a> and <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-using-rest-api.html\">Managing ACLs Using the REST API</a>. </p> <p> <b>Storage Class Options</b> </p> <p>You can use the <code>CopyObject</code> action to change the storage class of an object that is already stored in Amazon S3 using the <code>StorageClass</code> parameter. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/storage-class-intro.html\">Storage Classes</a> in the <i>Amazon S3 User Guide</i>.</p> <p> <b>Versioning</b> </p> <p>By default, <code>x-amz-copy-source</code> identifies the current version of an object to copy. If the current version is a delete marker, Amazon S3 behaves as if the object was deleted. To copy a different version, use the <code>versionId</code> subresource.</p> <p>If you enable versioning on the target bucket, Amazon S3 generates a unique version ID for the object being copied. This version ID is different from the version ID of the source object. Amazon S3 returns the version ID of the copied object in the <code>x-amz-version-id</code> response header in the response.</p> <p>If you do not enable versioning or suspend it on the target bucket, the version ID that Amazon S3 generates is always null.</p> <p>If the source object's storage class is GLACIER, you must restore a copy of this object before you can use it as a source object for the copy operation. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_RestoreObject.html\">RestoreObject</a>.</p> <p>The following operations are related to <code>CopyObject</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html\">PutObject</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html\">GetObject</a> </p> </li> </ul> <p>For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/CopyingObjectsExamples.html\">Copying Objects</a>.</p>",
- "alias":"PutObjectCopy"
- },
- "CreateBucket":{
- "name":"CreateBucket",
- "http":{
- "method":"PUT",
- "requestUri":"/{Bucket}"
- },
- "input":{"shape":"CreateBucketRequest"},
- "output":{"shape":"CreateBucketOutput"},
- "errors":[
- {"shape":"BucketAlreadyExists"},
- {"shape":"BucketAlreadyOwnedByYou"}
- ],
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketPUT.html",
+ "alias":"PutObjectCopy"
+ },
+ "CreateBucket":{
+ "name":"CreateBucket",
+ "http":{
+ "method":"PUT",
+ "requestUri":"/{Bucket}"
+ },
+ "input":{"shape":"CreateBucketRequest"},
+ "output":{"shape":"CreateBucketOutput"},
+ "errors":[
+ {"shape":"BucketAlreadyExists"},
+ {"shape":"BucketAlreadyOwnedByYou"}
+ ],
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketPUT.html",
"documentation":"<p>Creates a new S3 bucket. To create a bucket, you must register with Amazon S3 and have a valid AWS Access Key ID to authenticate requests. Anonymous requests are never allowed to create buckets. By creating the bucket, you become the bucket owner.</p> <p>Not every string is an acceptable bucket name. For information about bucket naming restrictions, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html\">Bucket naming rules</a>.</p> <p>If you want to create an Amazon S3 on Outposts bucket, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_control_CreateBucket.html\">Create Bucket</a>. </p> <p>By default, the bucket is created in the US East (N. Virginia) Region. You can optionally specify a Region in the request body. You might choose a Region to optimize latency, minimize costs, or address regulatory requirements. For example, if you reside in Europe, you will probably find it advantageous to create buckets in the Europe (Ireland) Region. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html#access-bucket-intro\">Accessing a bucket</a>.</p> <note> <p>If you send your create bucket request to the <code>s3.amazonaws.com</code> endpoint, the request goes to the us-east-1 Region. Accordingly, the signature calculations in Signature Version 4 must use us-east-1 as the Region, even if the location constraint in the request specifies another Region where the bucket is to be created. If you create a bucket in a Region other than US East (N. Virginia), your application must be able to handle 307 redirect. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/VirtualHosting.html\">Virtual hosting of buckets</a>.</p> </note> <p>When creating a bucket using this operation, you can optionally specify the accounts or groups that should be granted specific permissions on the bucket. There are two ways to grant the appropriate permissions using the request headers.</p> <ul> <li> <p>Specify a canned ACL using the <code>x-amz-acl</code> request header. Amazon S3 supports a set of predefined ACLs, known as <i>canned ACLs</i>. Each canned ACL has a predefined set of grantees and permissions. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#CannedACL\">Canned ACL</a>.</p> </li> <li> <p>Specify access permissions explicitly using the <code>x-amz-grant-read</code>, <code>x-amz-grant-write</code>, <code>x-amz-grant-read-acp</code>, <code>x-amz-grant-write-acp</code>, and <code>x-amz-grant-full-control</code> headers. These headers map to the set of permissions Amazon S3 supports in an ACL. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html\">Access control list (ACL) overview</a>.</p> <p>You specify each grantee as a type=value pair, where the type is one of the following:</p> <ul> <li> <p> <code>id</code> – if the value specified is the canonical user ID of an AWS account</p> </li> <li> <p> <code>uri</code> – if you are granting permissions to a predefined group</p> </li> <li> <p> <code>emailAddress</code> – if the value specified is the email address of an AWS account</p> <note> <p>Using email addresses to specify a grantee is only supported in the following AWS Regions: </p> <ul> <li> <p>US East (N. Virginia)</p> </li> <li> <p>US West (N. California)</p> </li> <li> <p> US West (Oregon)</p> </li> <li> <p> Asia Pacific (Singapore)</p> </li> <li> <p>Asia Pacific (Sydney)</p> </li> <li> <p>Asia Pacific (Tokyo)</p> </li> <li> <p>Europe (Ireland)</p> </li> <li> <p>South America (São Paulo)</p> </li> </ul> <p>For a list of all the Amazon S3 supported Regions and endpoints, see <a href=\"https://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region\">Regions and Endpoints</a> in the AWS General Reference.</p> </note> </li> </ul> <p>For example, the following <code>x-amz-grant-read</code> header grants the AWS accounts identified by account IDs permissions to read object data and its metadata:</p> <p> <code>x-amz-grant-read: id=\"11112222333\", id=\"444455556666\" </code> </p> </li> </ul> <note> <p>You can use either a canned ACL or specify access permissions explicitly. You cannot do both.</p> </note> <p>The following operations are related to <code>CreateBucket</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html\">PutObject</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucket.html\">DeleteBucket</a> </p> </li> </ul>",
- "alias":"PutBucket"
- },
- "CreateMultipartUpload":{
- "name":"CreateMultipartUpload",
- "http":{
- "method":"POST",
- "requestUri":"/{Bucket}/{Key+}?uploads"
- },
- "input":{"shape":"CreateMultipartUploadRequest"},
- "output":{"shape":"CreateMultipartUploadOutput"},
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/mpUploadInitiate.html",
+ "alias":"PutBucket"
+ },
+ "CreateMultipartUpload":{
+ "name":"CreateMultipartUpload",
+ "http":{
+ "method":"POST",
+ "requestUri":"/{Bucket}/{Key+}?uploads"
+ },
+ "input":{"shape":"CreateMultipartUploadRequest"},
+ "output":{"shape":"CreateMultipartUploadOutput"},
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/mpUploadInitiate.html",
"documentation":"<p>This action initiates a multipart upload and returns an upload ID. This upload ID is used to associate all of the parts in the specific multipart upload. You specify this upload ID in each of your subsequent upload part requests (see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPart.html\">UploadPart</a>). You also include this upload ID in the final request to either complete or abort the multipart upload request.</p> <p>For more information about multipart uploads, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/mpuoverview.html\">Multipart Upload Overview</a>.</p> <p>If you have configured a lifecycle rule to abort incomplete multipart uploads, the upload must complete within the number of days specified in the bucket lifecycle configuration. Otherwise, the incomplete multipart upload becomes eligible for an abort action and Amazon S3 aborts the multipart upload. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/mpuoverview.html#mpu-abort-incomplete-mpu-lifecycle-config\">Aborting Incomplete Multipart Uploads Using a Bucket Lifecycle Policy</a>.</p> <p>For information about the permissions required to use the multipart upload API, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html\">Multipart Upload and Permissions</a>.</p> <p>For request signing, multipart upload is just a series of regular requests. You initiate a multipart upload, send one or more requests to upload parts, and then complete the multipart upload process. You sign each request individually. There is nothing special about signing multipart upload requests. For more information about signing, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html\">Authenticating Requests (AWS Signature Version 4)</a>.</p> <note> <p> After you initiate a multipart upload and upload one or more parts, to stop being charged for storing the uploaded parts, you must either complete or abort the multipart upload. Amazon S3 frees up the space used to store the parts and stop charging you for storing them only after you either complete or abort a multipart upload. </p> </note> <p>You can optionally request server-side encryption. For server-side encryption, Amazon S3 encrypts your data as it writes it to disks in its data centers and decrypts it when you access it. You can provide your own encryption key, or use AWS Key Management Service (AWS KMS) customer master keys (CMKs) or Amazon S3-managed encryption keys. If you choose to provide your own encryption key, the request headers you provide in <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPart.html\">UploadPart</a> and <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPartCopy.html\">UploadPartCopy</a> requests must match the headers you used in the request to initiate the upload by using <code>CreateMultipartUpload</code>. </p> <p>To perform a multipart upload with encryption using an AWS KMS CMK, the requester must have permission to the <code>kms:Decrypt</code> and <code>kms:GenerateDataKey*</code> actions on the key. These permissions are required because Amazon S3 must decrypt and read data from the encrypted file parts before it completes the multipart upload. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/mpuoverview.html#mpuAndPermissions\">Multipart upload API and permissions</a> in the <i>Amazon S3 User Guide</i>.</p> <p>If your AWS Identity and Access Management (IAM) user or role is in the same AWS account as the AWS KMS CMK, then you must have these permissions on the key policy. If your IAM user or role belongs to a different account than the key, then you must have the permissions on both the key policy and your IAM user or role.</p> <p> For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/serv-side-encryption.html\">Protecting Data Using Server-Side Encryption</a>.</p> <dl> <dt>Access Permissions</dt> <dd> <p>When copying an object, you can optionally specify the accounts or groups that should be granted specific permissions on the new object. There are two ways to grant the permissions using the request headers:</p> <ul> <li> <p>Specify a canned ACL with the <code>x-amz-acl</code> request header. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#CannedACL\">Canned ACL</a>.</p> </li> <li> <p>Specify access permissions explicitly with the <code>x-amz-grant-read</code>, <code>x-amz-grant-read-acp</code>, <code>x-amz-grant-write-acp</code>, and <code>x-amz-grant-full-control</code> headers. These parameters map to the set of permissions that Amazon S3 supports in an ACL. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html\">Access Control List (ACL) Overview</a>.</p> </li> </ul> <p>You can use either a canned ACL or specify access permissions explicitly. You cannot do both.</p> </dd> <dt>Server-Side- Encryption-Specific Request Headers</dt> <dd> <p>You can optionally tell Amazon S3 to encrypt data at rest using server-side encryption. Server-side encryption is for data encryption at rest. Amazon S3 encrypts your data as it writes it to disks in its data centers and decrypts it when you access it. The option you use depends on whether you want to use AWS managed encryption keys or provide your own encryption key. </p> <ul> <li> <p>Use encryption keys managed by Amazon S3 or customer master keys (CMKs) stored in AWS Key Management Service (AWS KMS) – If you want AWS to manage the keys used to encrypt data, specify the following headers in the request.</p> <ul> <li> <p>x-amz-server-side-encryption</p> </li> <li> <p>x-amz-server-side-encryption-aws-kms-key-id</p> </li> <li> <p>x-amz-server-side-encryption-context</p> </li> </ul> <note> <p>If you specify <code>x-amz-server-side-encryption:aws:kms</code>, but don't provide <code>x-amz-server-side-encryption-aws-kms-key-id</code>, Amazon S3 uses the AWS managed CMK in AWS KMS to protect the data.</p> </note> <important> <p>All GET and PUT requests for an object protected by AWS KMS fail if you don't make them with SSL or by using SigV4.</p> </important> <p>For more information about server-side encryption with CMKs stored in AWS KMS (SSE-KMS), see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingKMSEncryption.html\">Protecting Data Using Server-Side Encryption with CMKs stored in AWS KMS</a>.</p> </li> <li> <p>Use customer-provided encryption keys – If you want to manage your own encryption keys, provide all the following headers in the request.</p> <ul> <li> <p>x-amz-server-side-encryption-customer-algorithm</p> </li> <li> <p>x-amz-server-side-encryption-customer-key</p> </li> <li> <p>x-amz-server-side-encryption-customer-key-MD5</p> </li> </ul> <p>For more information about server-side encryption with CMKs stored in AWS KMS (SSE-KMS), see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingKMSEncryption.html\">Protecting Data Using Server-Side Encryption with CMKs stored in AWS KMS</a>.</p> </li> </ul> </dd> <dt>Access-Control-List (ACL)-Specific Request Headers</dt> <dd> <p>You also can use the following access control–related headers with this operation. By default, all objects are private. Only the owner has full access control. When adding a new object, you can grant permissions to individual AWS accounts or to predefined groups defined by Amazon S3. These permissions are then added to the access control list (ACL) on the object. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/S3_ACLs_UsingACLs.html\">Using ACLs</a>. With this operation, you can grant access permissions using one of the following two methods:</p> <ul> <li> <p>Specify a canned ACL (<code>x-amz-acl</code>) — Amazon S3 supports a set of predefined ACLs, known as <i>canned ACLs</i>. Each canned ACL has a predefined set of grantees and permissions. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#CannedACL\">Canned ACL</a>.</p> </li> <li> <p>Specify access permissions explicitly — To explicitly grant access permissions to specific AWS accounts or groups, use the following headers. Each header maps to specific permissions that Amazon S3 supports in an ACL. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html\">Access Control List (ACL) Overview</a>. In the header, you specify a list of grantees who get the specific permission. To grant permissions explicitly, use:</p> <ul> <li> <p>x-amz-grant-read</p> </li> <li> <p>x-amz-grant-write</p> </li> <li> <p>x-amz-grant-read-acp</p> </li> <li> <p>x-amz-grant-write-acp</p> </li> <li> <p>x-amz-grant-full-control</p> </li> </ul> <p>You specify each grantee as a type=value pair, where the type is one of the following:</p> <ul> <li> <p> <code>id</code> – if the value specified is the canonical user ID of an AWS account</p> </li> <li> <p> <code>uri</code> – if you are granting permissions to a predefined group</p> </li> <li> <p> <code>emailAddress</code> – if the value specified is the email address of an AWS account</p> <note> <p>Using email addresses to specify a grantee is only supported in the following AWS Regions: </p> <ul> <li> <p>US East (N. Virginia)</p> </li> <li> <p>US West (N. California)</p> </li> <li> <p> US West (Oregon)</p> </li> <li> <p> Asia Pacific (Singapore)</p> </li> <li> <p>Asia Pacific (Sydney)</p> </li> <li> <p>Asia Pacific (Tokyo)</p> </li> <li> <p>Europe (Ireland)</p> </li> <li> <p>South America (São Paulo)</p> </li> </ul> <p>For a list of all the Amazon S3 supported Regions and endpoints, see <a href=\"https://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region\">Regions and Endpoints</a> in the AWS General Reference.</p> </note> </li> </ul> <p>For example, the following <code>x-amz-grant-read</code> header grants the AWS accounts identified by account IDs permissions to read object data and its metadata:</p> <p> <code>x-amz-grant-read: id=\"11112222333\", id=\"444455556666\" </code> </p> </li> </ul> </dd> </dl> <p>The following operations are related to <code>CreateMultipartUpload</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPart.html\">UploadPart</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_CompleteMultipartUpload.html\">CompleteMultipartUpload</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_AbortMultipartUpload.html\">AbortMultipartUpload</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListParts.html\">ListParts</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListMultipartUploads.html\">ListMultipartUploads</a> </p> </li> </ul>",
- "alias":"InitiateMultipartUpload"
- },
- "DeleteBucket":{
- "name":"DeleteBucket",
- "http":{
- "method":"DELETE",
+ "alias":"InitiateMultipartUpload"
+ },
+ "DeleteBucket":{
+ "name":"DeleteBucket",
+ "http":{
+ "method":"DELETE",
"requestUri":"/{Bucket}",
"responseCode":204
- },
- "input":{"shape":"DeleteBucketRequest"},
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketDELETE.html",
+ },
+ "input":{"shape":"DeleteBucketRequest"},
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketDELETE.html",
"documentation":"<p>Deletes the S3 bucket. All objects (including all object versions and delete markers) in the bucket must be deleted before the bucket itself can be deleted.</p> <p class=\"title\"> <b>Related Resources</b> </p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateBucket.html\">CreateBucket</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObject.html\">DeleteObject</a> </p> </li> </ul>"
- },
- "DeleteBucketAnalyticsConfiguration":{
- "name":"DeleteBucketAnalyticsConfiguration",
- "http":{
- "method":"DELETE",
+ },
+ "DeleteBucketAnalyticsConfiguration":{
+ "name":"DeleteBucketAnalyticsConfiguration",
+ "http":{
+ "method":"DELETE",
"requestUri":"/{Bucket}?analytics",
"responseCode":204
- },
- "input":{"shape":"DeleteBucketAnalyticsConfigurationRequest"},
+ },
+ "input":{"shape":"DeleteBucketAnalyticsConfigurationRequest"},
"documentation":"<p>Deletes an analytics configuration for the bucket (specified by the analytics configuration ID).</p> <p>To use this operation, you must have permissions to perform the <code>s3:PutAnalyticsConfiguration</code> action. The bucket owner has this permission by default. The bucket owner can grant this permission to others. For more information about permissions, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-with-s3-actions.html#using-with-s3-actions-related-to-bucket-subresources\">Permissions Related to Bucket Subresource Operations</a> and <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-access-control.html\">Managing Access Permissions to Your Amazon S3 Resources</a>.</p> <p>For information about the Amazon S3 analytics feature, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/analytics-storage-class.html\">Amazon S3 Analytics – Storage Class Analysis</a>. </p> <p>The following operations are related to <code>DeleteBucketAnalyticsConfiguration</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketAnalyticsConfiguration.html\">GetBucketAnalyticsConfiguration</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListBucketAnalyticsConfigurations.html\">ListBucketAnalyticsConfigurations</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketAnalyticsConfiguration.html\">PutBucketAnalyticsConfiguration</a> </p> </li> </ul>"
- },
- "DeleteBucketCors":{
- "name":"DeleteBucketCors",
- "http":{
- "method":"DELETE",
+ },
+ "DeleteBucketCors":{
+ "name":"DeleteBucketCors",
+ "http":{
+ "method":"DELETE",
"requestUri":"/{Bucket}?cors",
"responseCode":204
- },
- "input":{"shape":"DeleteBucketCorsRequest"},
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketDELETEcors.html",
+ },
+ "input":{"shape":"DeleteBucketCorsRequest"},
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketDELETEcors.html",
"documentation":"<p>Deletes the <code>cors</code> configuration information set for the bucket.</p> <p>To use this operation, you must have permission to perform the <code>s3:PutBucketCORS</code> action. The bucket owner has this permission by default and can grant this permission to others. </p> <p>For information about <code>cors</code>, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/cors.html\">Enabling Cross-Origin Resource Sharing</a> in the <i>Amazon S3 User Guide</i>.</p> <p class=\"title\"> <b>Related Resources:</b> </p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketCors.html\">PutBucketCors</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/RESTOPTIONSobject.html\">RESTOPTIONSobject</a> </p> </li> </ul>"
- },
- "DeleteBucketEncryption":{
- "name":"DeleteBucketEncryption",
- "http":{
- "method":"DELETE",
+ },
+ "DeleteBucketEncryption":{
+ "name":"DeleteBucketEncryption",
+ "http":{
+ "method":"DELETE",
"requestUri":"/{Bucket}?encryption",
"responseCode":204
- },
- "input":{"shape":"DeleteBucketEncryptionRequest"},
+ },
+ "input":{"shape":"DeleteBucketEncryptionRequest"},
"documentation":"<p>This implementation of the DELETE action removes default encryption from the bucket. For information about the Amazon S3 default encryption feature, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/bucket-encryption.html\">Amazon S3 Default Bucket Encryption</a> in the <i>Amazon S3 User Guide</i>.</p> <p>To use this operation, you must have permissions to perform the <code>s3:PutEncryptionConfiguration</code> action. The bucket owner has this permission by default. The bucket owner can grant this permission to others. For more information about permissions, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-with-s3-actions.html#using-with-s3-actions-related-to-bucket-subresources\">Permissions Related to Bucket Subresource Operations</a> and <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-access-control.html\">Managing Access Permissions to your Amazon S3 Resources</a> in the <i>Amazon S3 User Guide</i>.</p> <p class=\"title\"> <b>Related Resources</b> </p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketEncryption.html\">PutBucketEncryption</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketEncryption.html\">GetBucketEncryption</a> </p> </li> </ul>"
- },
+ },
"DeleteBucketIntelligentTieringConfiguration":{
"name":"DeleteBucketIntelligentTieringConfiguration",
"http":{
@@ -134,37 +134,37 @@
"input":{"shape":"DeleteBucketIntelligentTieringConfigurationRequest"},
"documentation":"<p>Deletes the S3 Intelligent-Tiering configuration from the specified bucket.</p> <p>The S3 Intelligent-Tiering storage class is designed to optimize storage costs by automatically moving data to the most cost-effective storage access tier, without additional operational overhead. S3 Intelligent-Tiering delivers automatic cost savings by moving data between access tiers, when access patterns change.</p> <p>The S3 Intelligent-Tiering storage class is suitable for objects larger than 128 KB that you plan to store for at least 30 days. If the size of an object is less than 128 KB, it is not eligible for auto-tiering. Smaller objects can be stored, but they are always charged at the frequent access tier rates in the S3 Intelligent-Tiering storage class. </p> <p>If you delete an object before the end of the 30-day minimum storage duration period, you are charged for 30 days. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/storage-class-intro.html#sc-dynamic-data-access\">Storage class for automatically optimizing frequently and infrequently accessed objects</a>.</p> <p>Operations related to <code>DeleteBucketIntelligentTieringConfiguration</code> include: </p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketIntelligentTieringConfiguration.html\">GetBucketIntelligentTieringConfiguration</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketIntelligentTieringConfiguration.html\">PutBucketIntelligentTieringConfiguration</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListBucketIntelligentTieringConfigurations.html\">ListBucketIntelligentTieringConfigurations</a> </p> </li> </ul>"
},
- "DeleteBucketInventoryConfiguration":{
- "name":"DeleteBucketInventoryConfiguration",
- "http":{
- "method":"DELETE",
+ "DeleteBucketInventoryConfiguration":{
+ "name":"DeleteBucketInventoryConfiguration",
+ "http":{
+ "method":"DELETE",
"requestUri":"/{Bucket}?inventory",
"responseCode":204
- },
- "input":{"shape":"DeleteBucketInventoryConfigurationRequest"},
+ },
+ "input":{"shape":"DeleteBucketInventoryConfigurationRequest"},
"documentation":"<p>Deletes an inventory configuration (identified by the inventory ID) from the bucket.</p> <p>To use this operation, you must have permissions to perform the <code>s3:PutInventoryConfiguration</code> action. The bucket owner has this permission by default. The bucket owner can grant this permission to others. For more information about permissions, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-with-s3-actions.html#using-with-s3-actions-related-to-bucket-subresources\">Permissions Related to Bucket Subresource Operations</a> and <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-access-control.html\">Managing Access Permissions to Your Amazon S3 Resources</a>.</p> <p>For information about the Amazon S3 inventory feature, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/storage-inventory.html\">Amazon S3 Inventory</a>.</p> <p>Operations related to <code>DeleteBucketInventoryConfiguration</code> include: </p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketInventoryConfiguration.html\">GetBucketInventoryConfiguration</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketInventoryConfiguration.html\">PutBucketInventoryConfiguration</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListBucketInventoryConfigurations.html\">ListBucketInventoryConfigurations</a> </p> </li> </ul>"
- },
- "DeleteBucketLifecycle":{
- "name":"DeleteBucketLifecycle",
- "http":{
- "method":"DELETE",
+ },
+ "DeleteBucketLifecycle":{
+ "name":"DeleteBucketLifecycle",
+ "http":{
+ "method":"DELETE",
"requestUri":"/{Bucket}?lifecycle",
"responseCode":204
- },
- "input":{"shape":"DeleteBucketLifecycleRequest"},
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketDELETElifecycle.html",
+ },
+ "input":{"shape":"DeleteBucketLifecycleRequest"},
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketDELETElifecycle.html",
"documentation":"<p>Deletes the lifecycle configuration from the specified bucket. Amazon S3 removes all the lifecycle configuration rules in the lifecycle subresource associated with the bucket. Your objects never expire, and Amazon S3 no longer automatically deletes any objects on the basis of rules contained in the deleted lifecycle configuration.</p> <p>To use this operation, you must have permission to perform the <code>s3:PutLifecycleConfiguration</code> action. By default, the bucket owner has this permission and the bucket owner can grant this permission to others.</p> <p>There is usually some time lag before lifecycle configuration deletion is fully propagated to all the Amazon S3 systems.</p> <p>For more information about the object expiration, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/intro-lifecycle-rules.html#intro-lifecycle-rules-actions\">Elements to Describe Lifecycle Actions</a>.</p> <p>Related actions include:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketLifecycleConfiguration.html\">PutBucketLifecycleConfiguration</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketLifecycleConfiguration.html\">GetBucketLifecycleConfiguration</a> </p> </li> </ul>"
- },
- "DeleteBucketMetricsConfiguration":{
- "name":"DeleteBucketMetricsConfiguration",
- "http":{
- "method":"DELETE",
+ },
+ "DeleteBucketMetricsConfiguration":{
+ "name":"DeleteBucketMetricsConfiguration",
+ "http":{
+ "method":"DELETE",
"requestUri":"/{Bucket}?metrics",
"responseCode":204
- },
- "input":{"shape":"DeleteBucketMetricsConfigurationRequest"},
+ },
+ "input":{"shape":"DeleteBucketMetricsConfigurationRequest"},
"documentation":"<p>Deletes a metrics configuration for the Amazon CloudWatch request metrics (specified by the metrics configuration ID) from the bucket. Note that this doesn't include the daily storage metrics.</p> <p> To use this operation, you must have permissions to perform the <code>s3:PutMetricsConfiguration</code> action. The bucket owner has this permission by default. The bucket owner can grant this permission to others. For more information about permissions, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-with-s3-actions.html#using-with-s3-actions-related-to-bucket-subresources\">Permissions Related to Bucket Subresource Operations</a> and <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-access-control.html\">Managing Access Permissions to Your Amazon S3 Resources</a>.</p> <p>For information about CloudWatch request metrics for Amazon S3, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/cloudwatch-monitoring.html\">Monitoring Metrics with Amazon CloudWatch</a>. </p> <p>The following operations are related to <code>DeleteBucketMetricsConfiguration</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketMetricsConfiguration.html\">GetBucketMetricsConfiguration</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketMetricsConfiguration.html\">PutBucketMetricsConfiguration</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListBucketMetricsConfigurations.html\">ListBucketMetricsConfigurations</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/cloudwatch-monitoring.html\">Monitoring Metrics with Amazon CloudWatch</a> </p> </li> </ul>"
- },
+ },
"DeleteBucketOwnershipControls":{
"name":"DeleteBucketOwnershipControls",
"http":{
@@ -175,85 +175,85 @@
"input":{"shape":"DeleteBucketOwnershipControlsRequest"},
"documentation":"<p>Removes <code>OwnershipControls</code> for an Amazon S3 bucket. To use this operation, you must have the <code>s3:PutBucketOwnershipControls</code> permission. For more information about Amazon S3 permissions, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/using-with-s3-actions.html\">Specifying Permissions in a Policy</a>.</p> <p>For information about Amazon S3 Object Ownership, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/about-object-ownership.html\">Using Object Ownership</a>. </p> <p>The following operations are related to <code>DeleteBucketOwnershipControls</code>:</p> <ul> <li> <p> <a>GetBucketOwnershipControls</a> </p> </li> <li> <p> <a>PutBucketOwnershipControls</a> </p> </li> </ul>"
},
- "DeleteBucketPolicy":{
- "name":"DeleteBucketPolicy",
- "http":{
- "method":"DELETE",
+ "DeleteBucketPolicy":{
+ "name":"DeleteBucketPolicy",
+ "http":{
+ "method":"DELETE",
"requestUri":"/{Bucket}?policy",
"responseCode":204
- },
- "input":{"shape":"DeleteBucketPolicyRequest"},
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketDELETEpolicy.html",
+ },
+ "input":{"shape":"DeleteBucketPolicyRequest"},
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketDELETEpolicy.html",
"documentation":"<p>This implementation of the DELETE action uses the policy subresource to delete the policy of a specified bucket. If you are using an identity other than the root user of the AWS account that owns the bucket, the calling identity must have the <code>DeleteBucketPolicy</code> permissions on the specified bucket and belong to the bucket owner's account to use this operation. </p> <p>If you don't have <code>DeleteBucketPolicy</code> permissions, Amazon S3 returns a <code>403 Access Denied</code> error. If you have the correct permissions, but you're not using an identity that belongs to the bucket owner's account, Amazon S3 returns a <code>405 Method Not Allowed</code> error. </p> <important> <p>As a security precaution, the root user of the AWS account that owns a bucket can always use this operation, even if the policy explicitly denies the root user the ability to perform this action.</p> </important> <p>For more information about bucket policies, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/using-iam-policies.html\">Using Bucket Policies and UserPolicies</a>. </p> <p>The following operations are related to <code>DeleteBucketPolicy</code> </p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateBucket.html\">CreateBucket</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObject.html\">DeleteObject</a> </p> </li> </ul>"
- },
- "DeleteBucketReplication":{
- "name":"DeleteBucketReplication",
- "http":{
- "method":"DELETE",
+ },
+ "DeleteBucketReplication":{
+ "name":"DeleteBucketReplication",
+ "http":{
+ "method":"DELETE",
"requestUri":"/{Bucket}?replication",
"responseCode":204
- },
- "input":{"shape":"DeleteBucketReplicationRequest"},
+ },
+ "input":{"shape":"DeleteBucketReplicationRequest"},
"documentation":"<p> Deletes the replication configuration from the bucket.</p> <p>To use this operation, you must have permissions to perform the <code>s3:PutReplicationConfiguration</code> action. The bucket owner has these permissions by default and can grant it to others. For more information about permissions, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-with-s3-actions.html#using-with-s3-actions-related-to-bucket-subresources\">Permissions Related to Bucket Subresource Operations</a> and <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-access-control.html\">Managing Access Permissions to Your Amazon S3 Resources</a>. </p> <note> <p>It can take a while for the deletion of a replication configuration to fully propagate.</p> </note> <p> For information about replication configuration, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/replication.html\">Replication</a> in the <i>Amazon S3 User Guide</i>.</p> <p>The following operations are related to <code>DeleteBucketReplication</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketReplication.html\">PutBucketReplication</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketReplication.html\">GetBucketReplication</a> </p> </li> </ul>"
- },
- "DeleteBucketTagging":{
- "name":"DeleteBucketTagging",
- "http":{
- "method":"DELETE",
+ },
+ "DeleteBucketTagging":{
+ "name":"DeleteBucketTagging",
+ "http":{
+ "method":"DELETE",
"requestUri":"/{Bucket}?tagging",
"responseCode":204
- },
- "input":{"shape":"DeleteBucketTaggingRequest"},
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketDELETEtagging.html",
+ },
+ "input":{"shape":"DeleteBucketTaggingRequest"},
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketDELETEtagging.html",
"documentation":"<p>Deletes the tags from the bucket.</p> <p>To use this operation, you must have permission to perform the <code>s3:PutBucketTagging</code> action. By default, the bucket owner has this permission and can grant this permission to others. </p> <p>The following operations are related to <code>DeleteBucketTagging</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketTagging.html\">GetBucketTagging</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketTagging.html\">PutBucketTagging</a> </p> </li> </ul>"
- },
- "DeleteBucketWebsite":{
- "name":"DeleteBucketWebsite",
- "http":{
- "method":"DELETE",
+ },
+ "DeleteBucketWebsite":{
+ "name":"DeleteBucketWebsite",
+ "http":{
+ "method":"DELETE",
"requestUri":"/{Bucket}?website",
"responseCode":204
- },
- "input":{"shape":"DeleteBucketWebsiteRequest"},
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketDELETEwebsite.html",
+ },
+ "input":{"shape":"DeleteBucketWebsiteRequest"},
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketDELETEwebsite.html",
"documentation":"<p>This action removes the website configuration for a bucket. Amazon S3 returns a <code>200 OK</code> response upon successfully deleting a website configuration on the specified bucket. You will get a <code>200 OK</code> response if the website configuration you are trying to delete does not exist on the bucket. Amazon S3 returns a <code>404</code> response if the bucket specified in the request does not exist.</p> <p>This DELETE action requires the <code>S3:DeleteBucketWebsite</code> permission. By default, only the bucket owner can delete the website configuration attached to a bucket. However, bucket owners can grant other users permission to delete the website configuration by writing a bucket policy granting them the <code>S3:DeleteBucketWebsite</code> permission. </p> <p>For more information about hosting websites, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/WebsiteHosting.html\">Hosting Websites on Amazon S3</a>. </p> <p>The following operations are related to <code>DeleteBucketWebsite</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketWebsite.html\">GetBucketWebsite</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketWebsite.html\">PutBucketWebsite</a> </p> </li> </ul>"
- },
- "DeleteObject":{
- "name":"DeleteObject",
- "http":{
- "method":"DELETE",
+ },
+ "DeleteObject":{
+ "name":"DeleteObject",
+ "http":{
+ "method":"DELETE",
"requestUri":"/{Bucket}/{Key+}",
"responseCode":204
- },
- "input":{"shape":"DeleteObjectRequest"},
- "output":{"shape":"DeleteObjectOutput"},
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectDELETE.html",
+ },
+ "input":{"shape":"DeleteObjectRequest"},
+ "output":{"shape":"DeleteObjectOutput"},
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectDELETE.html",
"documentation":"<p>Removes the null version (if there is one) of an object and inserts a delete marker, which becomes the latest version of the object. If there isn't a null version, Amazon S3 does not remove any objects but will still respond that the command was successful.</p> <p>To remove a specific version, you must be the bucket owner and you must use the version Id subresource. Using this subresource permanently deletes the version. If the object deleted is a delete marker, Amazon S3 sets the response header, <code>x-amz-delete-marker</code>, to true. </p> <p>If the object you want to delete is in a bucket where the bucket versioning configuration is MFA Delete enabled, you must include the <code>x-amz-mfa</code> request header in the DELETE <code>versionId</code> request. Requests that include <code>x-amz-mfa</code> must use HTTPS. </p> <p> For more information about MFA Delete, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMFADelete.html\">Using MFA Delete</a>. To see sample requests that use versioning, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectDELETE.html#ExampleVersionObjectDelete\">Sample Request</a>. </p> <p>You can delete objects by explicitly calling DELETE Object or configure its lifecycle (<a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketLifecycle.html\">PutBucketLifecycle</a>) to enable Amazon S3 to remove them for you. If you want to block users or accounts from removing or deleting objects from your bucket, you must deny them the <code>s3:DeleteObject</code>, <code>s3:DeleteObjectVersion</code>, and <code>s3:PutLifeCycleConfiguration</code> actions. </p> <p>The following action is related to <code>DeleteObject</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html\">PutObject</a> </p> </li> </ul>"
- },
- "DeleteObjectTagging":{
- "name":"DeleteObjectTagging",
- "http":{
- "method":"DELETE",
+ },
+ "DeleteObjectTagging":{
+ "name":"DeleteObjectTagging",
+ "http":{
+ "method":"DELETE",
"requestUri":"/{Bucket}/{Key+}?tagging",
"responseCode":204
- },
- "input":{"shape":"DeleteObjectTaggingRequest"},
- "output":{"shape":"DeleteObjectTaggingOutput"},
+ },
+ "input":{"shape":"DeleteObjectTaggingRequest"},
+ "output":{"shape":"DeleteObjectTaggingOutput"},
"documentation":"<p>Removes the entire tag set from the specified object. For more information about managing object tags, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/object-tagging.html\"> Object Tagging</a>.</p> <p>To use this operation, you must have permission to perform the <code>s3:DeleteObjectTagging</code> action.</p> <p>To delete tags of a specific object version, add the <code>versionId</code> query parameter in the request. You will need permission for the <code>s3:DeleteObjectVersionTagging</code> action.</p> <p>The following operations are related to <code>DeleteBucketMetricsConfiguration</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObjectTagging.html\">PutObjectTagging</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectTagging.html\">GetObjectTagging</a> </p> </li> </ul>"
- },
- "DeleteObjects":{
- "name":"DeleteObjects",
- "http":{
- "method":"POST",
- "requestUri":"/{Bucket}?delete"
- },
- "input":{"shape":"DeleteObjectsRequest"},
- "output":{"shape":"DeleteObjectsOutput"},
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/multiobjectdeleteapi.html",
+ },
+ "DeleteObjects":{
+ "name":"DeleteObjects",
+ "http":{
+ "method":"POST",
+ "requestUri":"/{Bucket}?delete"
+ },
+ "input":{"shape":"DeleteObjectsRequest"},
+ "output":{"shape":"DeleteObjectsOutput"},
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/multiobjectdeleteapi.html",
"documentation":"<p>This action enables you to delete multiple objects from a bucket using a single HTTP request. If you know the object keys that you want to delete, then this action provides a suitable alternative to sending individual delete requests, reducing per-request overhead.</p> <p>The request contains a list of up to 1000 keys that you want to delete. In the XML, you provide the object key names, and optionally, version IDs if you want to delete a specific version of the object from a versioning-enabled bucket. For each key, Amazon S3 performs a delete action and returns the result of that delete, success, or failure, in the response. Note that if the object specified in the request is not found, Amazon S3 returns the result as deleted.</p> <p> The action supports two modes for the response: verbose and quiet. By default, the action uses verbose mode in which the response includes the result of deletion of each key in your request. In quiet mode the response includes only keys where the delete action encountered an error. For a successful deletion, the action does not return any information about the delete in the response body.</p> <p>When performing this action on an MFA Delete enabled bucket, that attempts to delete any versioned objects, you must include an MFA token. If you do not provide one, the entire request will fail, even if there are non-versioned objects you are trying to delete. If you provide an invalid token, whether there are versioned keys in the request or not, the entire Multi-Object Delete request will fail. For information about MFA Delete, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/Versioning.html#MultiFactorAuthenticationDelete\"> MFA Delete</a>.</p> <p>Finally, the Content-MD5 header is required for all Multi-Object Delete requests. Amazon S3 uses the header value to ensure that your request body has not been altered in transit.</p> <p>The following operations are related to <code>DeleteObjects</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateMultipartUpload.html\">CreateMultipartUpload</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPart.html\">UploadPart</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_CompleteMultipartUpload.html\">CompleteMultipartUpload</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListParts.html\">ListParts</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_AbortMultipartUpload.html\">AbortMultipartUpload</a> </p> </li> </ul>",
"alias":"DeleteMultipleObjects",
"httpChecksumRequired":true
- },
+ },
"DeletePublicAccessBlock":{
"name":"DeletePublicAccessBlock",
"http":{
@@ -264,58 +264,58 @@
"input":{"shape":"DeletePublicAccessBlockRequest"},
"documentation":"<p>Removes the <code>PublicAccessBlock</code> configuration for an Amazon S3 bucket. To use this operation, you must have the <code>s3:PutBucketPublicAccessBlock</code> permission. For more information about permissions, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-with-s3-actions.html#using-with-s3-actions-related-to-bucket-subresources\">Permissions Related to Bucket Subresource Operations</a> and <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-access-control.html\">Managing Access Permissions to Your Amazon S3 Resources</a>.</p> <p>The following operations are related to <code>DeletePublicAccessBlock</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/access-control-block-public-access.html\">Using Amazon S3 Block Public Access</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetPublicAccessBlock.html\">GetPublicAccessBlock</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutPublicAccessBlock.html\">PutPublicAccessBlock</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketPolicyStatus.html\">GetBucketPolicyStatus</a> </p> </li> </ul>"
},
- "GetBucketAccelerateConfiguration":{
- "name":"GetBucketAccelerateConfiguration",
- "http":{
- "method":"GET",
- "requestUri":"/{Bucket}?accelerate"
- },
- "input":{"shape":"GetBucketAccelerateConfigurationRequest"},
- "output":{"shape":"GetBucketAccelerateConfigurationOutput"},
+ "GetBucketAccelerateConfiguration":{
+ "name":"GetBucketAccelerateConfiguration",
+ "http":{
+ "method":"GET",
+ "requestUri":"/{Bucket}?accelerate"
+ },
+ "input":{"shape":"GetBucketAccelerateConfigurationRequest"},
+ "output":{"shape":"GetBucketAccelerateConfigurationOutput"},
"documentation":"<p>This implementation of the GET action uses the <code>accelerate</code> subresource to return the Transfer Acceleration state of a bucket, which is either <code>Enabled</code> or <code>Suspended</code>. Amazon S3 Transfer Acceleration is a bucket-level feature that enables you to perform faster data transfers to and from Amazon S3.</p> <p>To use this operation, you must have permission to perform the <code>s3:GetAccelerateConfiguration</code> action. The bucket owner has this permission by default. The bucket owner can grant this permission to others. For more information about permissions, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-with-s3-actions.html#using-with-s3-actions-related-to-bucket-subresources\">Permissions Related to Bucket Subresource Operations</a> and <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-access-control.html\">Managing Access Permissions to your Amazon S3 Resources</a> in the <i>Amazon S3 User Guide</i>.</p> <p>You set the Transfer Acceleration state of an existing bucket to <code>Enabled</code> or <code>Suspended</code> by using the <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketAccelerateConfiguration.html\">PutBucketAccelerateConfiguration</a> operation. </p> <p>A GET <code>accelerate</code> request does not return a state value for a bucket that has no transfer acceleration state. A bucket has no Transfer Acceleration state if a state has never been set on the bucket. </p> <p>For more information about transfer acceleration, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/transfer-acceleration.html\">Transfer Acceleration</a> in the Amazon S3 User Guide.</p> <p class=\"title\"> <b>Related Resources</b> </p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketAccelerateConfiguration.html\">PutBucketAccelerateConfiguration</a> </p> </li> </ul>"
- },
- "GetBucketAcl":{
- "name":"GetBucketAcl",
- "http":{
- "method":"GET",
- "requestUri":"/{Bucket}?acl"
- },
- "input":{"shape":"GetBucketAclRequest"},
- "output":{"shape":"GetBucketAclOutput"},
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketGETacl.html",
+ },
+ "GetBucketAcl":{
+ "name":"GetBucketAcl",
+ "http":{
+ "method":"GET",
+ "requestUri":"/{Bucket}?acl"
+ },
+ "input":{"shape":"GetBucketAclRequest"},
+ "output":{"shape":"GetBucketAclOutput"},
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketGETacl.html",
"documentation":"<p>This implementation of the <code>GET</code> action uses the <code>acl</code> subresource to return the access control list (ACL) of a bucket. To use <code>GET</code> to return the ACL of the bucket, you must have <code>READ_ACP</code> access to the bucket. If <code>READ_ACP</code> permission is granted to the anonymous user, you can return the ACL of the bucket without using an authorization header.</p> <p class=\"title\"> <b>Related Resources</b> </p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjects.html\">ListObjects</a> </p> </li> </ul>"
- },
- "GetBucketAnalyticsConfiguration":{
- "name":"GetBucketAnalyticsConfiguration",
- "http":{
- "method":"GET",
- "requestUri":"/{Bucket}?analytics"
- },
- "input":{"shape":"GetBucketAnalyticsConfigurationRequest"},
- "output":{"shape":"GetBucketAnalyticsConfigurationOutput"},
+ },
+ "GetBucketAnalyticsConfiguration":{
+ "name":"GetBucketAnalyticsConfiguration",
+ "http":{
+ "method":"GET",
+ "requestUri":"/{Bucket}?analytics"
+ },
+ "input":{"shape":"GetBucketAnalyticsConfigurationRequest"},
+ "output":{"shape":"GetBucketAnalyticsConfigurationOutput"},
"documentation":"<p>This implementation of the GET action returns an analytics configuration (identified by the analytics configuration ID) from the bucket.</p> <p>To use this operation, you must have permissions to perform the <code>s3:GetAnalyticsConfiguration</code> action. The bucket owner has this permission by default. The bucket owner can grant this permission to others. For more information about permissions, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-with-s3-actions.html#using-with-s3-actions-related-to-bucket-subresources\"> Permissions Related to Bucket Subresource Operations</a> and <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-access-control.html\">Managing Access Permissions to Your Amazon S3 Resources</a> in the <i>Amazon S3 User Guide</i>. </p> <p>For information about Amazon S3 analytics feature, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/analytics-storage-class.html\">Amazon S3 Analytics – Storage Class Analysis</a> in the <i>Amazon S3 User Guide</i>.</p> <p class=\"title\"> <b>Related Resources</b> </p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketAnalyticsConfiguration.html\">DeleteBucketAnalyticsConfiguration</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListBucketAnalyticsConfigurations.html\">ListBucketAnalyticsConfigurations</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketAnalyticsConfiguration.html\">PutBucketAnalyticsConfiguration</a> </p> </li> </ul>"
- },
- "GetBucketCors":{
- "name":"GetBucketCors",
- "http":{
- "method":"GET",
- "requestUri":"/{Bucket}?cors"
- },
- "input":{"shape":"GetBucketCorsRequest"},
- "output":{"shape":"GetBucketCorsOutput"},
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketGETcors.html",
+ },
+ "GetBucketCors":{
+ "name":"GetBucketCors",
+ "http":{
+ "method":"GET",
+ "requestUri":"/{Bucket}?cors"
+ },
+ "input":{"shape":"GetBucketCorsRequest"},
+ "output":{"shape":"GetBucketCorsOutput"},
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketGETcors.html",
"documentation":"<p>Returns the cors configuration information set for the bucket.</p> <p> To use this operation, you must have permission to perform the s3:GetBucketCORS action. By default, the bucket owner has this permission and can grant it to others.</p> <p> For more information about cors, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/cors.html\"> Enabling Cross-Origin Resource Sharing</a>.</p> <p>The following operations are related to <code>GetBucketCors</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketCors.html\">PutBucketCors</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketCors.html\">DeleteBucketCors</a> </p> </li> </ul>"
- },
- "GetBucketEncryption":{
- "name":"GetBucketEncryption",
- "http":{
- "method":"GET",
- "requestUri":"/{Bucket}?encryption"
- },
- "input":{"shape":"GetBucketEncryptionRequest"},
- "output":{"shape":"GetBucketEncryptionOutput"},
+ },
+ "GetBucketEncryption":{
+ "name":"GetBucketEncryption",
+ "http":{
+ "method":"GET",
+ "requestUri":"/{Bucket}?encryption"
+ },
+ "input":{"shape":"GetBucketEncryptionRequest"},
+ "output":{"shape":"GetBucketEncryptionOutput"},
"documentation":"<p>Returns the default encryption configuration for an Amazon S3 bucket. If the bucket does not have a default encryption configuration, GetBucketEncryption returns <code>ServerSideEncryptionConfigurationNotFoundError</code>. </p> <p>For information about the Amazon S3 default encryption feature, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/bucket-encryption.html\">Amazon S3 Default Bucket Encryption</a>.</p> <p> To use this operation, you must have permission to perform the <code>s3:GetEncryptionConfiguration</code> action. The bucket owner has this permission by default. The bucket owner can grant this permission to others. For more information about permissions, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-with-s3-actions.html#using-with-s3-actions-related-to-bucket-subresources\">Permissions Related to Bucket Subresource Operations</a> and <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-access-control.html\">Managing Access Permissions to Your Amazon S3 Resources</a>.</p> <p>The following operations are related to <code>GetBucketEncryption</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketEncryption.html\">PutBucketEncryption</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketEncryption.html\">DeleteBucketEncryption</a> </p> </li> </ul>"
- },
+ },
"GetBucketIntelligentTieringConfiguration":{
"name":"GetBucketIntelligentTieringConfiguration",
"http":{
@@ -326,92 +326,92 @@
"output":{"shape":"GetBucketIntelligentTieringConfigurationOutput"},
"documentation":"<p>Gets the S3 Intelligent-Tiering configuration from the specified bucket.</p> <p>The S3 Intelligent-Tiering storage class is designed to optimize storage costs by automatically moving data to the most cost-effective storage access tier, without additional operational overhead. S3 Intelligent-Tiering delivers automatic cost savings by moving data between access tiers, when access patterns change.</p> <p>The S3 Intelligent-Tiering storage class is suitable for objects larger than 128 KB that you plan to store for at least 30 days. If the size of an object is less than 128 KB, it is not eligible for auto-tiering. Smaller objects can be stored, but they are always charged at the frequent access tier rates in the S3 Intelligent-Tiering storage class. </p> <p>If you delete an object before the end of the 30-day minimum storage duration period, you are charged for 30 days. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/storage-class-intro.html#sc-dynamic-data-access\">Storage class for automatically optimizing frequently and infrequently accessed objects</a>.</p> <p>Operations related to <code>GetBucketIntelligentTieringConfiguration</code> include: </p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketIntelligentTieringConfiguration.html\">DeleteBucketIntelligentTieringConfiguration</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketIntelligentTieringConfiguration.html\">PutBucketIntelligentTieringConfiguration</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListBucketIntelligentTieringConfigurations.html\">ListBucketIntelligentTieringConfigurations</a> </p> </li> </ul>"
},
- "GetBucketInventoryConfiguration":{
- "name":"GetBucketInventoryConfiguration",
- "http":{
- "method":"GET",
- "requestUri":"/{Bucket}?inventory"
- },
- "input":{"shape":"GetBucketInventoryConfigurationRequest"},
- "output":{"shape":"GetBucketInventoryConfigurationOutput"},
+ "GetBucketInventoryConfiguration":{
+ "name":"GetBucketInventoryConfiguration",
+ "http":{
+ "method":"GET",
+ "requestUri":"/{Bucket}?inventory"
+ },
+ "input":{"shape":"GetBucketInventoryConfigurationRequest"},
+ "output":{"shape":"GetBucketInventoryConfigurationOutput"},
"documentation":"<p>Returns an inventory configuration (identified by the inventory configuration ID) from the bucket.</p> <p>To use this operation, you must have permissions to perform the <code>s3:GetInventoryConfiguration</code> action. The bucket owner has this permission by default and can grant this permission to others. For more information about permissions, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-with-s3-actions.html#using-with-s3-actions-related-to-bucket-subresources\">Permissions Related to Bucket Subresource Operations</a> and <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-access-control.html\">Managing Access Permissions to Your Amazon S3 Resources</a>.</p> <p>For information about the Amazon S3 inventory feature, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/storage-inventory.html\">Amazon S3 Inventory</a>.</p> <p>The following operations are related to <code>GetBucketInventoryConfiguration</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketInventoryConfiguration.html\">DeleteBucketInventoryConfiguration</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListBucketInventoryConfigurations.html\">ListBucketInventoryConfigurations</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketInventoryConfiguration.html\">PutBucketInventoryConfiguration</a> </p> </li> </ul>"
- },
- "GetBucketLifecycle":{
- "name":"GetBucketLifecycle",
- "http":{
- "method":"GET",
- "requestUri":"/{Bucket}?lifecycle"
- },
- "input":{"shape":"GetBucketLifecycleRequest"},
- "output":{"shape":"GetBucketLifecycleOutput"},
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketGETlifecycle.html",
+ },
+ "GetBucketLifecycle":{
+ "name":"GetBucketLifecycle",
+ "http":{
+ "method":"GET",
+ "requestUri":"/{Bucket}?lifecycle"
+ },
+ "input":{"shape":"GetBucketLifecycleRequest"},
+ "output":{"shape":"GetBucketLifecycleOutput"},
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketGETlifecycle.html",
"documentation":"<important> <p>For an updated version of this API, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketLifecycleConfiguration.html\">GetBucketLifecycleConfiguration</a>. If you configured a bucket lifecycle using the <code>filter</code> element, you should see the updated version of this topic. This topic is provided for backward compatibility.</p> </important> <p>Returns the lifecycle configuration information set on the bucket. For information about lifecycle configuration, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/object-lifecycle-mgmt.html\">Object Lifecycle Management</a>.</p> <p> To use this operation, you must have permission to perform the <code>s3:GetLifecycleConfiguration</code> action. The bucket owner has this permission by default. The bucket owner can grant this permission to others. For more information about permissions, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-with-s3-actions.html#using-with-s3-actions-related-to-bucket-subresources\">Permissions Related to Bucket Subresource Operations</a> and <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-access-control.html\">Managing Access Permissions to Your Amazon S3 Resources</a>.</p> <p> <code>GetBucketLifecycle</code> has the following special error:</p> <ul> <li> <p>Error code: <code>NoSuchLifecycleConfiguration</code> </p> <ul> <li> <p>Description: The lifecycle configuration does not exist.</p> </li> <li> <p>HTTP Status Code: 404 Not Found</p> </li> <li> <p>SOAP Fault Code Prefix: Client</p> </li> </ul> </li> </ul> <p>The following operations are related to <code>GetBucketLifecycle</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketLifecycleConfiguration.html\">GetBucketLifecycleConfiguration</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketLifecycle.html\">PutBucketLifecycle</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketLifecycle.html\">DeleteBucketLifecycle</a> </p> </li> </ul>",
- "deprecated":true
- },
- "GetBucketLifecycleConfiguration":{
- "name":"GetBucketLifecycleConfiguration",
- "http":{
- "method":"GET",
- "requestUri":"/{Bucket}?lifecycle"
- },
- "input":{"shape":"GetBucketLifecycleConfigurationRequest"},
- "output":{"shape":"GetBucketLifecycleConfigurationOutput"},
+ "deprecated":true
+ },
+ "GetBucketLifecycleConfiguration":{
+ "name":"GetBucketLifecycleConfiguration",
+ "http":{
+ "method":"GET",
+ "requestUri":"/{Bucket}?lifecycle"
+ },
+ "input":{"shape":"GetBucketLifecycleConfigurationRequest"},
+ "output":{"shape":"GetBucketLifecycleConfigurationOutput"},
"documentation":"<note> <p>Bucket lifecycle configuration now supports specifying a lifecycle rule using an object key name prefix, one or more object tags, or a combination of both. Accordingly, this section describes the latest API. The response describes the new filter element that you can use to specify a filter to select a subset of objects to which the rule applies. If you are using a previous version of the lifecycle configuration, it still works. For the earlier action, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketLifecycle.html\">GetBucketLifecycle</a>.</p> </note> <p>Returns the lifecycle configuration information set on the bucket. For information about lifecycle configuration, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/object-lifecycle-mgmt.html\">Object Lifecycle Management</a>.</p> <p>To use this operation, you must have permission to perform the <code>s3:GetLifecycleConfiguration</code> action. The bucket owner has this permission, by default. The bucket owner can grant this permission to others. For more information about permissions, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-with-s3-actions.html#using-with-s3-actions-related-to-bucket-subresources\">Permissions Related to Bucket Subresource Operations</a> and <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-access-control.html\">Managing Access Permissions to Your Amazon S3 Resources</a>.</p> <p> <code>GetBucketLifecycleConfiguration</code> has the following special error:</p> <ul> <li> <p>Error code: <code>NoSuchLifecycleConfiguration</code> </p> <ul> <li> <p>Description: The lifecycle configuration does not exist.</p> </li> <li> <p>HTTP Status Code: 404 Not Found</p> </li> <li> <p>SOAP Fault Code Prefix: Client</p> </li> </ul> </li> </ul> <p>The following operations are related to <code>GetBucketLifecycleConfiguration</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketLifecycle.html\">GetBucketLifecycle</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketLifecycle.html\">PutBucketLifecycle</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketLifecycle.html\">DeleteBucketLifecycle</a> </p> </li> </ul>"
- },
- "GetBucketLocation":{
- "name":"GetBucketLocation",
- "http":{
- "method":"GET",
- "requestUri":"/{Bucket}?location"
- },
- "input":{"shape":"GetBucketLocationRequest"},
- "output":{"shape":"GetBucketLocationOutput"},
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketGETlocation.html",
+ },
+ "GetBucketLocation":{
+ "name":"GetBucketLocation",
+ "http":{
+ "method":"GET",
+ "requestUri":"/{Bucket}?location"
+ },
+ "input":{"shape":"GetBucketLocationRequest"},
+ "output":{"shape":"GetBucketLocationOutput"},
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketGETlocation.html",
"documentation":"<p>Returns the Region the bucket resides in. You set the bucket's Region using the <code>LocationConstraint</code> request parameter in a <code>CreateBucket</code> request. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateBucket.html\">CreateBucket</a>.</p> <p> To use this implementation of the operation, you must be the bucket owner.</p> <p>The following operations are related to <code>GetBucketLocation</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html\">GetObject</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateBucket.html\">CreateBucket</a> </p> </li> </ul>"
- },
- "GetBucketLogging":{
- "name":"GetBucketLogging",
- "http":{
- "method":"GET",
- "requestUri":"/{Bucket}?logging"
- },
- "input":{"shape":"GetBucketLoggingRequest"},
- "output":{"shape":"GetBucketLoggingOutput"},
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketGETlogging.html",
+ },
+ "GetBucketLogging":{
+ "name":"GetBucketLogging",
+ "http":{
+ "method":"GET",
+ "requestUri":"/{Bucket}?logging"
+ },
+ "input":{"shape":"GetBucketLoggingRequest"},
+ "output":{"shape":"GetBucketLoggingOutput"},
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketGETlogging.html",
"documentation":"<p>Returns the logging status of a bucket and the permissions users have to view and modify that status. To use GET, you must be the bucket owner.</p> <p>The following operations are related to <code>GetBucketLogging</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateBucket.html\">CreateBucket</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketLogging.html\">PutBucketLogging</a> </p> </li> </ul>"
- },
- "GetBucketMetricsConfiguration":{
- "name":"GetBucketMetricsConfiguration",
- "http":{
- "method":"GET",
- "requestUri":"/{Bucket}?metrics"
- },
- "input":{"shape":"GetBucketMetricsConfigurationRequest"},
- "output":{"shape":"GetBucketMetricsConfigurationOutput"},
+ },
+ "GetBucketMetricsConfiguration":{
+ "name":"GetBucketMetricsConfiguration",
+ "http":{
+ "method":"GET",
+ "requestUri":"/{Bucket}?metrics"
+ },
+ "input":{"shape":"GetBucketMetricsConfigurationRequest"},
+ "output":{"shape":"GetBucketMetricsConfigurationOutput"},
"documentation":"<p>Gets a metrics configuration (specified by the metrics configuration ID) from the bucket. Note that this doesn't include the daily storage metrics.</p> <p> To use this operation, you must have permissions to perform the <code>s3:GetMetricsConfiguration</code> action. The bucket owner has this permission by default. The bucket owner can grant this permission to others. For more information about permissions, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-with-s3-actions.html#using-with-s3-actions-related-to-bucket-subresources\">Permissions Related to Bucket Subresource Operations</a> and <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-access-control.html\">Managing Access Permissions to Your Amazon S3 Resources</a>.</p> <p> For information about CloudWatch request metrics for Amazon S3, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/cloudwatch-monitoring.html\">Monitoring Metrics with Amazon CloudWatch</a>.</p> <p>The following operations are related to <code>GetBucketMetricsConfiguration</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketMetricsConfiguration.html\">PutBucketMetricsConfiguration</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketMetricsConfiguration.html\">DeleteBucketMetricsConfiguration</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListBucketMetricsConfigurations.html\">ListBucketMetricsConfigurations</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/cloudwatch-monitoring.html\">Monitoring Metrics with Amazon CloudWatch</a> </p> </li> </ul>"
- },
- "GetBucketNotification":{
- "name":"GetBucketNotification",
- "http":{
- "method":"GET",
- "requestUri":"/{Bucket}?notification"
- },
- "input":{"shape":"GetBucketNotificationConfigurationRequest"},
- "output":{"shape":"NotificationConfigurationDeprecated"},
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketGETnotification.html",
+ },
+ "GetBucketNotification":{
+ "name":"GetBucketNotification",
+ "http":{
+ "method":"GET",
+ "requestUri":"/{Bucket}?notification"
+ },
+ "input":{"shape":"GetBucketNotificationConfigurationRequest"},
+ "output":{"shape":"NotificationConfigurationDeprecated"},
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketGETnotification.html",
"documentation":"<p> No longer used, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketNotificationConfiguration.html\">GetBucketNotificationConfiguration</a>.</p>",
- "deprecated":true
- },
- "GetBucketNotificationConfiguration":{
- "name":"GetBucketNotificationConfiguration",
- "http":{
- "method":"GET",
- "requestUri":"/{Bucket}?notification"
- },
- "input":{"shape":"GetBucketNotificationConfigurationRequest"},
- "output":{"shape":"NotificationConfiguration"},
+ "deprecated":true
+ },
+ "GetBucketNotificationConfiguration":{
+ "name":"GetBucketNotificationConfiguration",
+ "http":{
+ "method":"GET",
+ "requestUri":"/{Bucket}?notification"
+ },
+ "input":{"shape":"GetBucketNotificationConfigurationRequest"},
+ "output":{"shape":"NotificationConfiguration"},
"documentation":"<p>Returns the notification configuration of a bucket.</p> <p>If notifications are not enabled on the bucket, the action returns an empty <code>NotificationConfiguration</code> element.</p> <p>By default, you must be the bucket owner to read the notification configuration of a bucket. However, the bucket owner can use a bucket policy to grant permission to other users to read this configuration with the <code>s3:GetBucketNotification</code> permission.</p> <p>For more information about setting and reading the notification configuration on a bucket, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/NotificationHowTo.html\">Setting Up Notification of Bucket Events</a>. For more information about bucket policies, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/using-iam-policies.html\">Using Bucket Policies</a>.</p> <p>The following action is related to <code>GetBucketNotification</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketNotification.html\">PutBucketNotification</a> </p> </li> </ul>"
- },
+ },
"GetBucketOwnershipControls":{
"name":"GetBucketOwnershipControls",
"http":{
@@ -422,17 +422,17 @@
"output":{"shape":"GetBucketOwnershipControlsOutput"},
"documentation":"<p>Retrieves <code>OwnershipControls</code> for an Amazon S3 bucket. To use this operation, you must have the <code>s3:GetBucketOwnershipControls</code> permission. For more information about Amazon S3 permissions, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/using-with-s3-actions.html\">Specifying Permissions in a Policy</a>. </p> <p>For information about Amazon S3 Object Ownership, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/about-object-ownership.html\">Using Object Ownership</a>. </p> <p>The following operations are related to <code>GetBucketOwnershipControls</code>:</p> <ul> <li> <p> <a>PutBucketOwnershipControls</a> </p> </li> <li> <p> <a>DeleteBucketOwnershipControls</a> </p> </li> </ul>"
},
- "GetBucketPolicy":{
- "name":"GetBucketPolicy",
- "http":{
- "method":"GET",
- "requestUri":"/{Bucket}?policy"
- },
- "input":{"shape":"GetBucketPolicyRequest"},
- "output":{"shape":"GetBucketPolicyOutput"},
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketGETpolicy.html",
+ "GetBucketPolicy":{
+ "name":"GetBucketPolicy",
+ "http":{
+ "method":"GET",
+ "requestUri":"/{Bucket}?policy"
+ },
+ "input":{"shape":"GetBucketPolicyRequest"},
+ "output":{"shape":"GetBucketPolicyOutput"},
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketGETpolicy.html",
"documentation":"<p>Returns the policy of a specified bucket. If you are using an identity other than the root user of the AWS account that owns the bucket, the calling identity must have the <code>GetBucketPolicy</code> permissions on the specified bucket and belong to the bucket owner's account in order to use this operation.</p> <p>If you don't have <code>GetBucketPolicy</code> permissions, Amazon S3 returns a <code>403 Access Denied</code> error. If you have the correct permissions, but you're not using an identity that belongs to the bucket owner's account, Amazon S3 returns a <code>405 Method Not Allowed</code> error.</p> <important> <p>As a security precaution, the root user of the AWS account that owns a bucket can always use this operation, even if the policy explicitly denies the root user the ability to perform this action.</p> </important> <p>For more information about bucket policies, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/using-iam-policies.html\">Using Bucket Policies and User Policies</a>.</p> <p>The following action is related to <code>GetBucketPolicy</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html\">GetObject</a> </p> </li> </ul>"
- },
+ },
"GetBucketPolicyStatus":{
"name":"GetBucketPolicyStatus",
"http":{
@@ -443,89 +443,89 @@
"output":{"shape":"GetBucketPolicyStatusOutput"},
"documentation":"<p>Retrieves the policy status for an Amazon S3 bucket, indicating whether the bucket is public. In order to use this operation, you must have the <code>s3:GetBucketPolicyStatus</code> permission. For more information about Amazon S3 permissions, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/using-with-s3-actions.html\">Specifying Permissions in a Policy</a>.</p> <p> For more information about when Amazon S3 considers a bucket public, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/access-control-block-public-access.html#access-control-block-public-access-policy-status\">The Meaning of \"Public\"</a>. </p> <p>The following operations are related to <code>GetBucketPolicyStatus</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/access-control-block-public-access.html\">Using Amazon S3 Block Public Access</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetPublicAccessBlock.html\">GetPublicAccessBlock</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutPublicAccessBlock.html\">PutPublicAccessBlock</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeletePublicAccessBlock.html\">DeletePublicAccessBlock</a> </p> </li> </ul>"
},
- "GetBucketReplication":{
- "name":"GetBucketReplication",
- "http":{
- "method":"GET",
- "requestUri":"/{Bucket}?replication"
- },
- "input":{"shape":"GetBucketReplicationRequest"},
- "output":{"shape":"GetBucketReplicationOutput"},
+ "GetBucketReplication":{
+ "name":"GetBucketReplication",
+ "http":{
+ "method":"GET",
+ "requestUri":"/{Bucket}?replication"
+ },
+ "input":{"shape":"GetBucketReplicationRequest"},
+ "output":{"shape":"GetBucketReplicationOutput"},
"documentation":"<p>Returns the replication configuration of a bucket.</p> <note> <p> It can take a while to propagate the put or delete a replication configuration to all Amazon S3 systems. Therefore, a get request soon after put or delete can return a wrong result. </p> </note> <p> For information about replication configuration, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/replication.html\">Replication</a> in the <i>Amazon S3 User Guide</i>.</p> <p>This action requires permissions for the <code>s3:GetReplicationConfiguration</code> action. For more information about permissions, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/using-iam-policies.html\">Using Bucket Policies and User Policies</a>.</p> <p>If you include the <code>Filter</code> element in a replication configuration, you must also include the <code>DeleteMarkerReplication</code> and <code>Priority</code> elements. The response also returns those elements.</p> <p>For information about <code>GetBucketReplication</code> errors, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html#ReplicationErrorCodeList\">List of replication-related error codes</a> </p> <p>The following operations are related to <code>GetBucketReplication</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketReplication.html\">PutBucketReplication</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketReplication.html\">DeleteBucketReplication</a> </p> </li> </ul>"
- },
- "GetBucketRequestPayment":{
- "name":"GetBucketRequestPayment",
- "http":{
- "method":"GET",
- "requestUri":"/{Bucket}?requestPayment"
- },
- "input":{"shape":"GetBucketRequestPaymentRequest"},
- "output":{"shape":"GetBucketRequestPaymentOutput"},
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTrequestPaymentGET.html",
+ },
+ "GetBucketRequestPayment":{
+ "name":"GetBucketRequestPayment",
+ "http":{
+ "method":"GET",
+ "requestUri":"/{Bucket}?requestPayment"
+ },
+ "input":{"shape":"GetBucketRequestPaymentRequest"},
+ "output":{"shape":"GetBucketRequestPaymentOutput"},
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTrequestPaymentGET.html",
"documentation":"<p>Returns the request payment configuration of a bucket. To use this version of the operation, you must be the bucket owner. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/RequesterPaysBuckets.html\">Requester Pays Buckets</a>.</p> <p>The following operations are related to <code>GetBucketRequestPayment</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjects.html\">ListObjects</a> </p> </li> </ul>"
- },
- "GetBucketTagging":{
- "name":"GetBucketTagging",
- "http":{
- "method":"GET",
- "requestUri":"/{Bucket}?tagging"
- },
- "input":{"shape":"GetBucketTaggingRequest"},
- "output":{"shape":"GetBucketTaggingOutput"},
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketGETtagging.html",
+ },
+ "GetBucketTagging":{
+ "name":"GetBucketTagging",
+ "http":{
+ "method":"GET",
+ "requestUri":"/{Bucket}?tagging"
+ },
+ "input":{"shape":"GetBucketTaggingRequest"},
+ "output":{"shape":"GetBucketTaggingOutput"},
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketGETtagging.html",
"documentation":"<p>Returns the tag set associated with the bucket.</p> <p>To use this operation, you must have permission to perform the <code>s3:GetBucketTagging</code> action. By default, the bucket owner has this permission and can grant this permission to others.</p> <p> <code>GetBucketTagging</code> has the following special error:</p> <ul> <li> <p>Error code: <code>NoSuchTagSetError</code> </p> <ul> <li> <p>Description: There is no tag set associated with the bucket.</p> </li> </ul> </li> </ul> <p>The following operations are related to <code>GetBucketTagging</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketTagging.html\">PutBucketTagging</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketTagging.html\">DeleteBucketTagging</a> </p> </li> </ul>"
- },
- "GetBucketVersioning":{
- "name":"GetBucketVersioning",
- "http":{
- "method":"GET",
- "requestUri":"/{Bucket}?versioning"
- },
- "input":{"shape":"GetBucketVersioningRequest"},
- "output":{"shape":"GetBucketVersioningOutput"},
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketGETversioningStatus.html",
+ },
+ "GetBucketVersioning":{
+ "name":"GetBucketVersioning",
+ "http":{
+ "method":"GET",
+ "requestUri":"/{Bucket}?versioning"
+ },
+ "input":{"shape":"GetBucketVersioningRequest"},
+ "output":{"shape":"GetBucketVersioningOutput"},
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketGETversioningStatus.html",
"documentation":"<p>Returns the versioning state of a bucket.</p> <p>To retrieve the versioning state of a bucket, you must be the bucket owner.</p> <p>This implementation also returns the MFA Delete status of the versioning state. If the MFA Delete status is <code>enabled</code>, the bucket owner must use an authentication device to change the versioning state of the bucket.</p> <p>The following operations are related to <code>GetBucketVersioning</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html\">GetObject</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html\">PutObject</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObject.html\">DeleteObject</a> </p> </li> </ul>"
- },
- "GetBucketWebsite":{
- "name":"GetBucketWebsite",
- "http":{
- "method":"GET",
- "requestUri":"/{Bucket}?website"
- },
- "input":{"shape":"GetBucketWebsiteRequest"},
- "output":{"shape":"GetBucketWebsiteOutput"},
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketGETwebsite.html",
+ },
+ "GetBucketWebsite":{
+ "name":"GetBucketWebsite",
+ "http":{
+ "method":"GET",
+ "requestUri":"/{Bucket}?website"
+ },
+ "input":{"shape":"GetBucketWebsiteRequest"},
+ "output":{"shape":"GetBucketWebsiteOutput"},
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketGETwebsite.html",
"documentation":"<p>Returns the website configuration for a bucket. To host website on Amazon S3, you can configure a bucket as website by adding a website configuration. For more information about hosting websites, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/WebsiteHosting.html\">Hosting Websites on Amazon S3</a>. </p> <p>This GET action requires the <code>S3:GetBucketWebsite</code> permission. By default, only the bucket owner can read the bucket website configuration. However, bucket owners can allow other users to read the website configuration by writing a bucket policy granting them the <code>S3:GetBucketWebsite</code> permission.</p> <p>The following operations are related to <code>DeleteBucketWebsite</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketWebsite.html\">DeleteBucketWebsite</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketWebsite.html\">PutBucketWebsite</a> </p> </li> </ul>"
- },
- "GetObject":{
- "name":"GetObject",
- "http":{
- "method":"GET",
- "requestUri":"/{Bucket}/{Key+}"
- },
- "input":{"shape":"GetObjectRequest"},
- "output":{"shape":"GetObjectOutput"},
- "errors":[
+ },
+ "GetObject":{
+ "name":"GetObject",
+ "http":{
+ "method":"GET",
+ "requestUri":"/{Bucket}/{Key+}"
+ },
+ "input":{"shape":"GetObjectRequest"},
+ "output":{"shape":"GetObjectOutput"},
+ "errors":[
{"shape":"NoSuchKey"},
{"shape":"InvalidObjectState"}
- ],
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectGET.html",
+ ],
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectGET.html",
"documentation":"<p>Retrieves objects from Amazon S3. To use <code>GET</code>, you must have <code>READ</code> access to the object. If you grant <code>READ</code> access to the anonymous user, you can return the object without using an authorization header.</p> <p>An Amazon S3 bucket has no directory hierarchy such as you would find in a typical computer file system. You can, however, create a logical hierarchy by using object key names that imply a folder structure. For example, instead of naming an object <code>sample.jpg</code>, you can name it <code>photos/2006/February/sample.jpg</code>.</p> <p>To get an object from such a logical hierarchy, specify the full key name for the object in the <code>GET</code> operation. For a virtual hosted-style request example, if you have the object <code>photos/2006/February/sample.jpg</code>, specify the resource as <code>/photos/2006/February/sample.jpg</code>. For a path-style request example, if you have the object <code>photos/2006/February/sample.jpg</code> in the bucket named <code>examplebucket</code>, specify the resource as <code>/examplebucket/photos/2006/February/sample.jpg</code>. For more information about request types, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/VirtualHosting.html#VirtualHostingSpecifyBucket\">HTTP Host Header Bucket Specification</a>.</p> <p>To distribute large files to many people, you can save bandwidth costs by using BitTorrent. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/S3Torrent.html\">Amazon S3 Torrent</a>. For more information about returning the ACL of an object, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectAcl.html\">GetObjectAcl</a>.</p> <p>If the object you are retrieving is stored in the S3 Glacier or S3 Glacier Deep Archive storage class, or S3 Intelligent-Tiering Archive or S3 Intelligent-Tiering Deep Archive tiers, before you can retrieve the object you must first restore a copy using <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_RestoreObject.html\">RestoreObject</a>. Otherwise, this action returns an <code>InvalidObjectStateError</code> error. For information about restoring archived objects, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/restoring-objects.html\">Restoring Archived Objects</a>.</p> <p>Encryption request headers, like <code>x-amz-server-side-encryption</code>, should not be sent for GET requests if your object uses server-side encryption with CMKs stored in AWS KMS (SSE-KMS) or server-side encryption with Amazon S3–managed encryption keys (SSE-S3). If your object does use these types of keys, you’ll get an HTTP 400 BadRequest error.</p> <p>If you encrypt an object by using server-side encryption with customer-provided encryption keys (SSE-C) when you store the object in Amazon S3, then when you GET the object, you must use the following headers:</p> <ul> <li> <p>x-amz-server-side-encryption-customer-algorithm</p> </li> <li> <p>x-amz-server-side-encryption-customer-key</p> </li> <li> <p>x-amz-server-side-encryption-customer-key-MD5</p> </li> </ul> <p>For more information about SSE-C, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html\">Server-Side Encryption (Using Customer-Provided Encryption Keys)</a>.</p> <p>Assuming you have permission to read object tags (permission for the <code>s3:GetObjectVersionTagging</code> action), the response also returns the <code>x-amz-tagging-count</code> header that provides the count of number of tags associated with the object. You can use <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectTagging.html\">GetObjectTagging</a> to retrieve the tag set associated with an object.</p> <p> <b>Permissions</b> </p> <p>You need the <code>s3:GetObject</code> permission for this operation. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/using-with-s3-actions.html\">Specifying Permissions in a Policy</a>. If the object you request does not exist, the error Amazon S3 returns depends on whether you also have the <code>s3:ListBucket</code> permission.</p> <ul> <li> <p>If you have the <code>s3:ListBucket</code> permission on the bucket, Amazon S3 will return an HTTP status code 404 (\"no such key\") error.</p> </li> <li> <p>If you don’t have the <code>s3:ListBucket</code> permission, Amazon S3 will return an HTTP status code 403 (\"access denied\") error.</p> </li> </ul> <p> <b>Versioning</b> </p> <p>By default, the GET action returns the current version of an object. To return a different version, use the <code>versionId</code> subresource.</p> <note> <p>If the current version of the object is a delete marker, Amazon S3 behaves as if the object was deleted and includes <code>x-amz-delete-marker: true</code> in the response.</p> </note> <p>For more information about versioning, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketVersioning.html\">PutBucketVersioning</a>. </p> <p> <b>Overriding Response Header Values</b> </p> <p>There are times when you want to override certain response header values in a GET response. For example, you might override the Content-Disposition response header value in your GET request.</p> <p>You can override values for a set of response headers using the following query parameters. These response header values are sent only on a successful request, that is, when status code 200 OK is returned. The set of headers you can override using these parameters is a subset of the headers that Amazon S3 accepts when you create an object. The response headers that you can override for the GET response are <code>Content-Type</code>, <code>Content-Language</code>, <code>Expires</code>, <code>Cache-Control</code>, <code>Content-Disposition</code>, and <code>Content-Encoding</code>. To override these header values in the GET response, you use the following request parameters.</p> <note> <p>You must sign the request, either using an Authorization header or a presigned URL, when using these parameters. They cannot be used with an unsigned (anonymous) request.</p> </note> <ul> <li> <p> <code>response-content-type</code> </p> </li> <li> <p> <code>response-content-language</code> </p> </li> <li> <p> <code>response-expires</code> </p> </li> <li> <p> <code>response-cache-control</code> </p> </li> <li> <p> <code>response-content-disposition</code> </p> </li> <li> <p> <code>response-content-encoding</code> </p> </li> </ul> <p> <b>Additional Considerations about Request Headers</b> </p> <p>If both of the <code>If-Match</code> and <code>If-Unmodified-Since</code> headers are present in the request as follows: <code>If-Match</code> condition evaluates to <code>true</code>, and; <code>If-Unmodified-Since</code> condition evaluates to <code>false</code>; then, S3 returns 200 OK and the data requested. </p> <p>If both of the <code>If-None-Match</code> and <code>If-Modified-Since</code> headers are present in the request as follows:<code> If-None-Match</code> condition evaluates to <code>false</code>, and; <code>If-Modified-Since</code> condition evaluates to <code>true</code>; then, S3 returns 304 Not Modified response code.</p> <p>For more information about conditional requests, see <a href=\"https://tools.ietf.org/html/rfc7232\">RFC 7232</a>.</p> <p>The following operations are related to <code>GetObject</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListBuckets.html\">ListBuckets</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectAcl.html\">GetObjectAcl</a> </p> </li> </ul>"
- },
- "GetObjectAcl":{
- "name":"GetObjectAcl",
- "http":{
- "method":"GET",
- "requestUri":"/{Bucket}/{Key+}?acl"
- },
- "input":{"shape":"GetObjectAclRequest"},
- "output":{"shape":"GetObjectAclOutput"},
- "errors":[
- {"shape":"NoSuchKey"}
- ],
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectGETacl.html",
+ },
+ "GetObjectAcl":{
+ "name":"GetObjectAcl",
+ "http":{
+ "method":"GET",
+ "requestUri":"/{Bucket}/{Key+}?acl"
+ },
+ "input":{"shape":"GetObjectAclRequest"},
+ "output":{"shape":"GetObjectAclOutput"},
+ "errors":[
+ {"shape":"NoSuchKey"}
+ ],
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectGETacl.html",
"documentation":"<p>Returns the access control list (ACL) of an object. To use this operation, you must have <code>READ_ACP</code> access to the object.</p> <p>This action is not supported by Amazon S3 on Outposts.</p> <p> <b>Versioning</b> </p> <p>By default, GET returns ACL information about the current version of an object. To return ACL information about a different version, use the versionId subresource.</p> <p>The following operations are related to <code>GetObjectAcl</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html\">GetObject</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObject.html\">DeleteObject</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html\">PutObject</a> </p> </li> </ul>"
- },
+ },
"GetObjectLegalHold":{
"name":"GetObjectLegalHold",
"http":{
@@ -556,27 +556,27 @@
"output":{"shape":"GetObjectRetentionOutput"},
"documentation":"<p>Retrieves an object's retention settings. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/object-lock.html\">Locking Objects</a>.</p> <p>This action is not supported by Amazon S3 on Outposts.</p>"
},
- "GetObjectTagging":{
- "name":"GetObjectTagging",
- "http":{
- "method":"GET",
- "requestUri":"/{Bucket}/{Key+}?tagging"
- },
- "input":{"shape":"GetObjectTaggingRequest"},
- "output":{"shape":"GetObjectTaggingOutput"},
+ "GetObjectTagging":{
+ "name":"GetObjectTagging",
+ "http":{
+ "method":"GET",
+ "requestUri":"/{Bucket}/{Key+}?tagging"
+ },
+ "input":{"shape":"GetObjectTaggingRequest"},
+ "output":{"shape":"GetObjectTaggingOutput"},
"documentation":"<p>Returns the tag-set of an object. You send the GET request against the tagging subresource associated with the object.</p> <p>To use this operation, you must have permission to perform the <code>s3:GetObjectTagging</code> action. By default, the GET action returns information about current version of an object. For a versioned bucket, you can have multiple versions of an object in your bucket. To retrieve tags of any other version, use the versionId query parameter. You also need permission for the <code>s3:GetObjectVersionTagging</code> action.</p> <p> By default, the bucket owner has this permission and can grant this permission to others.</p> <p> For information about the Amazon S3 object tagging feature, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/object-tagging.html\">Object Tagging</a>.</p> <p>The following action is related to <code>GetObjectTagging</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObjectTagging.html\">PutObjectTagging</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObjectTagging.html\">DeleteObjectTagging</a> </p> </li> </ul>"
- },
- "GetObjectTorrent":{
- "name":"GetObjectTorrent",
- "http":{
- "method":"GET",
- "requestUri":"/{Bucket}/{Key+}?torrent"
- },
- "input":{"shape":"GetObjectTorrentRequest"},
- "output":{"shape":"GetObjectTorrentOutput"},
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectGETtorrent.html",
+ },
+ "GetObjectTorrent":{
+ "name":"GetObjectTorrent",
+ "http":{
+ "method":"GET",
+ "requestUri":"/{Bucket}/{Key+}?torrent"
+ },
+ "input":{"shape":"GetObjectTorrentRequest"},
+ "output":{"shape":"GetObjectTorrentOutput"},
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectGETtorrent.html",
"documentation":"<p>Returns torrent files from a bucket. BitTorrent can save you bandwidth when you're distributing large files. For more information about BitTorrent, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/S3Torrent.html\">Using BitTorrent with Amazon S3</a>.</p> <note> <p>You can get torrent only for objects that are less than 5 GB in size, and that are not encrypted using server-side encryption with a customer-provided encryption key.</p> </note> <p>To use GET, you must have READ access to the object.</p> <p>This action is not supported by Amazon S3 on Outposts.</p> <p>The following action is related to <code>GetObjectTorrent</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html\">GetObject</a> </p> </li> </ul>"
- },
+ },
"GetPublicAccessBlock":{
"name":"GetPublicAccessBlock",
"http":{
@@ -587,43 +587,43 @@
"output":{"shape":"GetPublicAccessBlockOutput"},
"documentation":"<p>Retrieves the <code>PublicAccessBlock</code> configuration for an Amazon S3 bucket. To use this operation, you must have the <code>s3:GetBucketPublicAccessBlock</code> permission. For more information about Amazon S3 permissions, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/using-with-s3-actions.html\">Specifying Permissions in a Policy</a>.</p> <important> <p>When Amazon S3 evaluates the <code>PublicAccessBlock</code> configuration for a bucket or an object, it checks the <code>PublicAccessBlock</code> configuration for both the bucket (or the bucket that contains the object) and the bucket owner's account. If the <code>PublicAccessBlock</code> settings are different between the bucket and the account, Amazon S3 uses the most restrictive combination of the bucket-level and account-level settings.</p> </important> <p>For more information about when Amazon S3 considers a bucket or an object public, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/access-control-block-public-access.html#access-control-block-public-access-policy-status\">The Meaning of \"Public\"</a>.</p> <p>The following operations are related to <code>GetPublicAccessBlock</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/access-control-block-public-access.html\">Using Amazon S3 Block Public Access</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutPublicAccessBlock.html\">PutPublicAccessBlock</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetPublicAccessBlock.html\">GetPublicAccessBlock</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeletePublicAccessBlock.html\">DeletePublicAccessBlock</a> </p> </li> </ul>"
},
- "HeadBucket":{
- "name":"HeadBucket",
- "http":{
- "method":"HEAD",
- "requestUri":"/{Bucket}"
- },
- "input":{"shape":"HeadBucketRequest"},
- "errors":[
- {"shape":"NoSuchBucket"}
- ],
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketHEAD.html",
+ "HeadBucket":{
+ "name":"HeadBucket",
+ "http":{
+ "method":"HEAD",
+ "requestUri":"/{Bucket}"
+ },
+ "input":{"shape":"HeadBucketRequest"},
+ "errors":[
+ {"shape":"NoSuchBucket"}
+ ],
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketHEAD.html",
"documentation":"<p>This action is useful to determine if a bucket exists and you have permission to access it. The action returns a <code>200 OK</code> if the bucket exists and you have permission to access it.</p> <p>If the bucket does not exist or you do not have permission to access it, the <code>HEAD</code> request returns a generic <code>404 Not Found</code> or <code>403 Forbidden</code> code. A message body is not included, so you cannot determine the exception beyond these error codes.</p> <p>To use this operation, you must have permissions to perform the <code>s3:ListBucket</code> action. The bucket owner has this permission by default and can grant this permission to others. For more information about permissions, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-with-s3-actions.html#using-with-s3-actions-related-to-bucket-subresources\">Permissions Related to Bucket Subresource Operations</a> and <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-access-control.html\">Managing Access Permissions to Your Amazon S3 Resources</a>.</p>"
- },
- "HeadObject":{
- "name":"HeadObject",
- "http":{
- "method":"HEAD",
- "requestUri":"/{Bucket}/{Key+}"
- },
- "input":{"shape":"HeadObjectRequest"},
- "output":{"shape":"HeadObjectOutput"},
- "errors":[
- {"shape":"NoSuchKey"}
- ],
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectHEAD.html",
+ },
+ "HeadObject":{
+ "name":"HeadObject",
+ "http":{
+ "method":"HEAD",
+ "requestUri":"/{Bucket}/{Key+}"
+ },
+ "input":{"shape":"HeadObjectRequest"},
+ "output":{"shape":"HeadObjectOutput"},
+ "errors":[
+ {"shape":"NoSuchKey"}
+ ],
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectHEAD.html",
"documentation":"<p>The HEAD action retrieves metadata from an object without returning the object itself. This action is useful if you're only interested in an object's metadata. To use HEAD, you must have READ access to the object.</p> <p>A <code>HEAD</code> request has the same options as a <code>GET</code> action on an object. The response is identical to the <code>GET</code> response except that there is no response body. Because of this, if the <code>HEAD</code> request generates an error, it returns a generic <code>404 Not Found</code> or <code>403 Forbidden</code> code. It is not possible to retrieve the exact exception beyond these error codes.</p> <p>If you encrypt an object by using server-side encryption with customer-provided encryption keys (SSE-C) when you store the object in Amazon S3, then when you retrieve the metadata from the object, you must use the following headers:</p> <ul> <li> <p>x-amz-server-side-encryption-customer-algorithm</p> </li> <li> <p>x-amz-server-side-encryption-customer-key</p> </li> <li> <p>x-amz-server-side-encryption-customer-key-MD5</p> </li> </ul> <p>For more information about SSE-C, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html\">Server-Side Encryption (Using Customer-Provided Encryption Keys)</a>.</p> <note> <ul> <li> <p>Encryption request headers, like <code>x-amz-server-side-encryption</code>, should not be sent for GET requests if your object uses server-side encryption with CMKs stored in AWS KMS (SSE-KMS) or server-side encryption with Amazon S3–managed encryption keys (SSE-S3). If your object does use these types of keys, you’ll get an HTTP 400 BadRequest error.</p> </li> <li> <p> The last modified property in this case is the creation date of the object.</p> </li> </ul> </note> <p>Request headers are limited to 8 KB in size. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/RESTCommonRequestHeaders.html\">Common Request Headers</a>.</p> <p>Consider the following when using request headers:</p> <ul> <li> <p> Consideration 1 – If both of the <code>If-Match</code> and <code>If-Unmodified-Since</code> headers are present in the request as follows:</p> <ul> <li> <p> <code>If-Match</code> condition evaluates to <code>true</code>, and;</p> </li> <li> <p> <code>If-Unmodified-Since</code> condition evaluates to <code>false</code>;</p> </li> </ul> <p>Then Amazon S3 returns <code>200 OK</code> and the data requested.</p> </li> <li> <p> Consideration 2 – If both of the <code>If-None-Match</code> and <code>If-Modified-Since</code> headers are present in the request as follows:</p> <ul> <li> <p> <code>If-None-Match</code> condition evaluates to <code>false</code>, and;</p> </li> <li> <p> <code>If-Modified-Since</code> condition evaluates to <code>true</code>;</p> </li> </ul> <p>Then Amazon S3 returns the <code>304 Not Modified</code> response code.</p> </li> </ul> <p>For more information about conditional requests, see <a href=\"https://tools.ietf.org/html/rfc7232\">RFC 7232</a>.</p> <p> <b>Permissions</b> </p> <p>You need the <code>s3:GetObject</code> permission for this operation. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/using-with-s3-actions.html\">Specifying Permissions in a Policy</a>. If the object you request does not exist, the error Amazon S3 returns depends on whether you also have the s3:ListBucket permission.</p> <ul> <li> <p>If you have the <code>s3:ListBucket</code> permission on the bucket, Amazon S3 returns an HTTP status code 404 (\"no such key\") error.</p> </li> <li> <p>If you don’t have the <code>s3:ListBucket</code> permission, Amazon S3 returns an HTTP status code 403 (\"access denied\") error.</p> </li> </ul> <p>The following action is related to <code>HeadObject</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html\">GetObject</a> </p> </li> </ul>"
- },
- "ListBucketAnalyticsConfigurations":{
- "name":"ListBucketAnalyticsConfigurations",
- "http":{
- "method":"GET",
- "requestUri":"/{Bucket}?analytics"
- },
- "input":{"shape":"ListBucketAnalyticsConfigurationsRequest"},
- "output":{"shape":"ListBucketAnalyticsConfigurationsOutput"},
+ },
+ "ListBucketAnalyticsConfigurations":{
+ "name":"ListBucketAnalyticsConfigurations",
+ "http":{
+ "method":"GET",
+ "requestUri":"/{Bucket}?analytics"
+ },
+ "input":{"shape":"ListBucketAnalyticsConfigurationsRequest"},
+ "output":{"shape":"ListBucketAnalyticsConfigurationsOutput"},
"documentation":"<p>Lists the analytics configurations for the bucket. You can have up to 1,000 analytics configurations per bucket.</p> <p>This action supports list pagination and does not return more than 100 configurations at a time. You should always check the <code>IsTruncated</code> element in the response. If there are no more configurations to list, <code>IsTruncated</code> is set to false. If there are more configurations to list, <code>IsTruncated</code> is set to true, and there will be a value in <code>NextContinuationToken</code>. You use the <code>NextContinuationToken</code> value to continue the pagination of the list by passing the value in continuation-token in the request to <code>GET</code> the next page.</p> <p>To use this operation, you must have permissions to perform the <code>s3:GetAnalyticsConfiguration</code> action. The bucket owner has this permission by default. The bucket owner can grant this permission to others. For more information about permissions, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-with-s3-actions.html#using-with-s3-actions-related-to-bucket-subresources\">Permissions Related to Bucket Subresource Operations</a> and <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-access-control.html\">Managing Access Permissions to Your Amazon S3 Resources</a>.</p> <p>For information about Amazon S3 analytics feature, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/analytics-storage-class.html\">Amazon S3 Analytics – Storage Class Analysis</a>. </p> <p>The following operations are related to <code>ListBucketAnalyticsConfigurations</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketAnalyticsConfiguration.html\">GetBucketAnalyticsConfiguration</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketAnalyticsConfiguration.html\">DeleteBucketAnalyticsConfiguration</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketAnalyticsConfiguration.html\">PutBucketAnalyticsConfiguration</a> </p> </li> </ul>"
- },
+ },
"ListBucketIntelligentTieringConfigurations":{
"name":"ListBucketIntelligentTieringConfigurations",
"http":{
@@ -634,88 +634,88 @@
"output":{"shape":"ListBucketIntelligentTieringConfigurationsOutput"},
"documentation":"<p>Lists the S3 Intelligent-Tiering configuration from the specified bucket.</p> <p>The S3 Intelligent-Tiering storage class is designed to optimize storage costs by automatically moving data to the most cost-effective storage access tier, without additional operational overhead. S3 Intelligent-Tiering delivers automatic cost savings by moving data between access tiers, when access patterns change.</p> <p>The S3 Intelligent-Tiering storage class is suitable for objects larger than 128 KB that you plan to store for at least 30 days. If the size of an object is less than 128 KB, it is not eligible for auto-tiering. Smaller objects can be stored, but they are always charged at the frequent access tier rates in the S3 Intelligent-Tiering storage class. </p> <p>If you delete an object before the end of the 30-day minimum storage duration period, you are charged for 30 days. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/storage-class-intro.html#sc-dynamic-data-access\">Storage class for automatically optimizing frequently and infrequently accessed objects</a>.</p> <p>Operations related to <code>ListBucketIntelligentTieringConfigurations</code> include: </p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketIntelligentTieringConfiguration.html\">DeleteBucketIntelligentTieringConfiguration</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketIntelligentTieringConfiguration.html\">PutBucketIntelligentTieringConfiguration</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketIntelligentTieringConfiguration.html\">GetBucketIntelligentTieringConfiguration</a> </p> </li> </ul>"
},
- "ListBucketInventoryConfigurations":{
- "name":"ListBucketInventoryConfigurations",
- "http":{
- "method":"GET",
- "requestUri":"/{Bucket}?inventory"
- },
- "input":{"shape":"ListBucketInventoryConfigurationsRequest"},
- "output":{"shape":"ListBucketInventoryConfigurationsOutput"},
+ "ListBucketInventoryConfigurations":{
+ "name":"ListBucketInventoryConfigurations",
+ "http":{
+ "method":"GET",
+ "requestUri":"/{Bucket}?inventory"
+ },
+ "input":{"shape":"ListBucketInventoryConfigurationsRequest"},
+ "output":{"shape":"ListBucketInventoryConfigurationsOutput"},
"documentation":"<p>Returns a list of inventory configurations for the bucket. You can have up to 1,000 analytics configurations per bucket.</p> <p>This action supports list pagination and does not return more than 100 configurations at a time. Always check the <code>IsTruncated</code> element in the response. If there are no more configurations to list, <code>IsTruncated</code> is set to false. If there are more configurations to list, <code>IsTruncated</code> is set to true, and there is a value in <code>NextContinuationToken</code>. You use the <code>NextContinuationToken</code> value to continue the pagination of the list by passing the value in continuation-token in the request to <code>GET</code> the next page.</p> <p> To use this operation, you must have permissions to perform the <code>s3:GetInventoryConfiguration</code> action. The bucket owner has this permission by default. The bucket owner can grant this permission to others. For more information about permissions, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-with-s3-actions.html#using-with-s3-actions-related-to-bucket-subresources\">Permissions Related to Bucket Subresource Operations</a> and <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-access-control.html\">Managing Access Permissions to Your Amazon S3 Resources</a>.</p> <p>For information about the Amazon S3 inventory feature, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/storage-inventory.html\">Amazon S3 Inventory</a> </p> <p>The following operations are related to <code>ListBucketInventoryConfigurations</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketInventoryConfiguration.html\">GetBucketInventoryConfiguration</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketInventoryConfiguration.html\">DeleteBucketInventoryConfiguration</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketInventoryConfiguration.html\">PutBucketInventoryConfiguration</a> </p> </li> </ul>"
- },
- "ListBucketMetricsConfigurations":{
- "name":"ListBucketMetricsConfigurations",
- "http":{
- "method":"GET",
- "requestUri":"/{Bucket}?metrics"
- },
- "input":{"shape":"ListBucketMetricsConfigurationsRequest"},
- "output":{"shape":"ListBucketMetricsConfigurationsOutput"},
+ },
+ "ListBucketMetricsConfigurations":{
+ "name":"ListBucketMetricsConfigurations",
+ "http":{
+ "method":"GET",
+ "requestUri":"/{Bucket}?metrics"
+ },
+ "input":{"shape":"ListBucketMetricsConfigurationsRequest"},
+ "output":{"shape":"ListBucketMetricsConfigurationsOutput"},
"documentation":"<p>Lists the metrics configurations for the bucket. The metrics configurations are only for the request metrics of the bucket and do not provide information on daily storage metrics. You can have up to 1,000 configurations per bucket.</p> <p>This action supports list pagination and does not return more than 100 configurations at a time. Always check the <code>IsTruncated</code> element in the response. If there are no more configurations to list, <code>IsTruncated</code> is set to false. If there are more configurations to list, <code>IsTruncated</code> is set to true, and there is a value in <code>NextContinuationToken</code>. You use the <code>NextContinuationToken</code> value to continue the pagination of the list by passing the value in <code>continuation-token</code> in the request to <code>GET</code> the next page.</p> <p>To use this operation, you must have permissions to perform the <code>s3:GetMetricsConfiguration</code> action. The bucket owner has this permission by default. The bucket owner can grant this permission to others. For more information about permissions, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-with-s3-actions.html#using-with-s3-actions-related-to-bucket-subresources\">Permissions Related to Bucket Subresource Operations</a> and <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-access-control.html\">Managing Access Permissions to Your Amazon S3 Resources</a>.</p> <p>For more information about metrics configurations and CloudWatch request metrics, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/cloudwatch-monitoring.html\">Monitoring Metrics with Amazon CloudWatch</a>.</p> <p>The following operations are related to <code>ListBucketMetricsConfigurations</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketMetricsConfiguration.html\">PutBucketMetricsConfiguration</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketMetricsConfiguration.html\">GetBucketMetricsConfiguration</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketMetricsConfiguration.html\">DeleteBucketMetricsConfiguration</a> </p> </li> </ul>"
- },
- "ListBuckets":{
- "name":"ListBuckets",
- "http":{
- "method":"GET",
- "requestUri":"/"
- },
- "output":{"shape":"ListBucketsOutput"},
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTServiceGET.html",
+ },
+ "ListBuckets":{
+ "name":"ListBuckets",
+ "http":{
+ "method":"GET",
+ "requestUri":"/"
+ },
+ "output":{"shape":"ListBucketsOutput"},
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTServiceGET.html",
"documentation":"<p>Returns a list of all buckets owned by the authenticated sender of the request.</p>",
- "alias":"GetService"
- },
- "ListMultipartUploads":{
- "name":"ListMultipartUploads",
- "http":{
- "method":"GET",
- "requestUri":"/{Bucket}?uploads"
- },
- "input":{"shape":"ListMultipartUploadsRequest"},
- "output":{"shape":"ListMultipartUploadsOutput"},
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/mpUploadListMPUpload.html",
+ "alias":"GetService"
+ },
+ "ListMultipartUploads":{
+ "name":"ListMultipartUploads",
+ "http":{
+ "method":"GET",
+ "requestUri":"/{Bucket}?uploads"
+ },
+ "input":{"shape":"ListMultipartUploadsRequest"},
+ "output":{"shape":"ListMultipartUploadsOutput"},
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/mpUploadListMPUpload.html",
"documentation":"<p>This action lists in-progress multipart uploads. An in-progress multipart upload is a multipart upload that has been initiated using the Initiate Multipart Upload request, but has not yet been completed or aborted.</p> <p>This action returns at most 1,000 multipart uploads in the response. 1,000 multipart uploads is the maximum number of uploads a response can include, which is also the default value. You can further limit the number of uploads in a response by specifying the <code>max-uploads</code> parameter in the response. If additional multipart uploads satisfy the list criteria, the response will contain an <code>IsTruncated</code> element with the value true. To list the additional multipart uploads, use the <code>key-marker</code> and <code>upload-id-marker</code> request parameters.</p> <p>In the response, the uploads are sorted by key. If your application has initiated more than one multipart upload using the same object key, then uploads in the response are first sorted by key. Additionally, uploads are sorted in ascending order within each key by the upload initiation time.</p> <p>For more information on multipart uploads, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/uploadobjusingmpu.html\">Uploading Objects Using Multipart Upload</a>.</p> <p>For information on permissions required to use the multipart upload API, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html\">Multipart Upload and Permissions</a>.</p> <p>The following operations are related to <code>ListMultipartUploads</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateMultipartUpload.html\">CreateMultipartUpload</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPart.html\">UploadPart</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_CompleteMultipartUpload.html\">CompleteMultipartUpload</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListParts.html\">ListParts</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_AbortMultipartUpload.html\">AbortMultipartUpload</a> </p> </li> </ul>"
- },
- "ListObjectVersions":{
- "name":"ListObjectVersions",
- "http":{
- "method":"GET",
- "requestUri":"/{Bucket}?versions"
- },
- "input":{"shape":"ListObjectVersionsRequest"},
- "output":{"shape":"ListObjectVersionsOutput"},
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketGETVersion.html",
+ },
+ "ListObjectVersions":{
+ "name":"ListObjectVersions",
+ "http":{
+ "method":"GET",
+ "requestUri":"/{Bucket}?versions"
+ },
+ "input":{"shape":"ListObjectVersionsRequest"},
+ "output":{"shape":"ListObjectVersionsOutput"},
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketGETVersion.html",
"documentation":"<p>Returns metadata about all versions of the objects in a bucket. You can also use request parameters as selection criteria to return metadata about a subset of all the object versions.</p> <important> <p> To use this operation, you must have permissions to perform the <code>s3:ListBucketVersions</code> action. Be aware of the name difference. </p> </important> <note> <p> A 200 OK response can contain valid or invalid XML. Make sure to design your application to parse the contents of the response and handle it appropriately.</p> </note> <p>To use this operation, you must have READ access to the bucket.</p> <p>This action is not supported by Amazon S3 on Outposts.</p> <p>The following operations are related to <code>ListObjectVersions</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjectsV2.html\">ListObjectsV2</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html\">GetObject</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html\">PutObject</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObject.html\">DeleteObject</a> </p> </li> </ul>",
- "alias":"GetBucketObjectVersions"
- },
- "ListObjects":{
- "name":"ListObjects",
- "http":{
- "method":"GET",
- "requestUri":"/{Bucket}"
- },
- "input":{"shape":"ListObjectsRequest"},
- "output":{"shape":"ListObjectsOutput"},
- "errors":[
- {"shape":"NoSuchBucket"}
- ],
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketGET.html",
+ "alias":"GetBucketObjectVersions"
+ },
+ "ListObjects":{
+ "name":"ListObjects",
+ "http":{
+ "method":"GET",
+ "requestUri":"/{Bucket}"
+ },
+ "input":{"shape":"ListObjectsRequest"},
+ "output":{"shape":"ListObjectsOutput"},
+ "errors":[
+ {"shape":"NoSuchBucket"}
+ ],
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketGET.html",
"documentation":"<p>Returns some or all (up to 1,000) of the objects in a bucket. You can use the request parameters as selection criteria to return a subset of the objects in a bucket. A 200 OK response can contain valid or invalid XML. Be sure to design your application to parse the contents of the response and handle it appropriately.</p> <important> <p>This action has been revised. We recommend that you use the newer version, <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjectsV2.html\">ListObjectsV2</a>, when developing applications. For backward compatibility, Amazon S3 continues to support <code>ListObjects</code>.</p> </important> <p>The following operations are related to <code>ListObjects</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjectsV2.html\">ListObjectsV2</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html\">GetObject</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html\">PutObject</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateBucket.html\">CreateBucket</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListBuckets.html\">ListBuckets</a> </p> </li> </ul>",
- "alias":"GetBucket"
- },
- "ListObjectsV2":{
- "name":"ListObjectsV2",
- "http":{
- "method":"GET",
- "requestUri":"/{Bucket}?list-type=2"
- },
- "input":{"shape":"ListObjectsV2Request"},
- "output":{"shape":"ListObjectsV2Output"},
- "errors":[
- {"shape":"NoSuchBucket"}
- ],
+ "alias":"GetBucket"
+ },
+ "ListObjectsV2":{
+ "name":"ListObjectsV2",
+ "http":{
+ "method":"GET",
+ "requestUri":"/{Bucket}?list-type=2"
+ },
+ "input":{"shape":"ListObjectsV2Request"},
+ "output":{"shape":"ListObjectsV2Output"},
+ "errors":[
+ {"shape":"NoSuchBucket"}
+ ],
"documentation":"<p>Returns some or all (up to 1,000) of the objects in a bucket with each request. You can use the request parameters as selection criteria to return a subset of the objects in a bucket. A <code>200 OK</code> response can contain valid or invalid XML. Make sure to design your application to parse the contents of the response and handle it appropriately. Objects are returned sorted in an ascending order of the respective key names in the list. For more information about listing objects, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/ListingKeysUsingAPIs.html\">Listing object keys programmatically</a> </p> <p>To use this operation, you must have READ access to the bucket.</p> <p>To use this action in an AWS Identity and Access Management (IAM) policy, you must have permissions to perform the <code>s3:ListBucket</code> action. The bucket owner has this permission by default and can grant this permission to others. For more information about permissions, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-with-s3-actions.html#using-with-s3-actions-related-to-bucket-subresources\">Permissions Related to Bucket Subresource Operations</a> and <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-access-control.html\">Managing Access Permissions to Your Amazon S3 Resources</a>.</p> <important> <p>This section describes the latest revision of this action. We recommend that you use this revised API for application development. For backward compatibility, Amazon S3 continues to support the prior version of this API, <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjects.html\">ListObjects</a>.</p> </important> <p>To get a list of your buckets, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListBuckets.html\">ListBuckets</a>.</p> <p>The following operations are related to <code>ListObjectsV2</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html\">GetObject</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html\">PutObject</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateBucket.html\">CreateBucket</a> </p> </li> </ul>"
- },
+ },
"ListObjectsV1Ext":{
"name":"ListObjectsV1Ext",
"http":{
@@ -729,67 +729,67 @@
],
"documentation":"<p>Yandex S3-specific extended listing method. Same as V2, but includes user metadata for each object. The rest of the parameters are exactly the same as in ListObjectsV2.</p>"
},
- "ListParts":{
- "name":"ListParts",
- "http":{
- "method":"GET",
- "requestUri":"/{Bucket}/{Key+}"
- },
- "input":{"shape":"ListPartsRequest"},
- "output":{"shape":"ListPartsOutput"},
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/mpUploadListParts.html",
+ "ListParts":{
+ "name":"ListParts",
+ "http":{
+ "method":"GET",
+ "requestUri":"/{Bucket}/{Key+}"
+ },
+ "input":{"shape":"ListPartsRequest"},
+ "output":{"shape":"ListPartsOutput"},
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/mpUploadListParts.html",
"documentation":"<p>Lists the parts that have been uploaded for a specific multipart upload. This operation must include the upload ID, which you obtain by sending the initiate multipart upload request (see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateMultipartUpload.html\">CreateMultipartUpload</a>). This request returns a maximum of 1,000 uploaded parts. The default number of parts returned is 1,000 parts. You can restrict the number of parts returned by specifying the <code>max-parts</code> request parameter. If your multipart upload consists of more than 1,000 parts, the response returns an <code>IsTruncated</code> field with the value of true, and a <code>NextPartNumberMarker</code> element. In subsequent <code>ListParts</code> requests you can include the part-number-marker query string parameter and set its value to the <code>NextPartNumberMarker</code> field value from the previous response.</p> <p>For more information on multipart uploads, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/uploadobjusingmpu.html\">Uploading Objects Using Multipart Upload</a>.</p> <p>For information on permissions required to use the multipart upload API, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html\">Multipart Upload and Permissions</a>.</p> <p>The following operations are related to <code>ListParts</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateMultipartUpload.html\">CreateMultipartUpload</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPart.html\">UploadPart</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_CompleteMultipartUpload.html\">CompleteMultipartUpload</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_AbortMultipartUpload.html\">AbortMultipartUpload</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListMultipartUploads.html\">ListMultipartUploads</a> </p> </li> </ul>"
- },
- "PutBucketAccelerateConfiguration":{
- "name":"PutBucketAccelerateConfiguration",
- "http":{
- "method":"PUT",
- "requestUri":"/{Bucket}?accelerate"
- },
- "input":{"shape":"PutBucketAccelerateConfigurationRequest"},
+ },
+ "PutBucketAccelerateConfiguration":{
+ "name":"PutBucketAccelerateConfiguration",
+ "http":{
+ "method":"PUT",
+ "requestUri":"/{Bucket}?accelerate"
+ },
+ "input":{"shape":"PutBucketAccelerateConfigurationRequest"},
"documentation":"<p>Sets the accelerate configuration of an existing bucket. Amazon S3 Transfer Acceleration is a bucket-level feature that enables you to perform faster data transfers to Amazon S3.</p> <p> To use this operation, you must have permission to perform the s3:PutAccelerateConfiguration action. The bucket owner has this permission by default. The bucket owner can grant this permission to others. For more information about permissions, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-with-s3-actions.html#using-with-s3-actions-related-to-bucket-subresources\">Permissions Related to Bucket Subresource Operations</a> and <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-access-control.html\">Managing Access Permissions to Your Amazon S3 Resources</a>.</p> <p> The Transfer Acceleration state of a bucket can be set to one of the following two values:</p> <ul> <li> <p> Enabled – Enables accelerated data transfers to the bucket.</p> </li> <li> <p> Suspended – Disables accelerated data transfers to the bucket.</p> </li> </ul> <p>The <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketAccelerateConfiguration.html\">GetBucketAccelerateConfiguration</a> action returns the transfer acceleration state of a bucket.</p> <p>After setting the Transfer Acceleration state of a bucket to Enabled, it might take up to thirty minutes before the data transfer rates to the bucket increase.</p> <p> The name of the bucket used for Transfer Acceleration must be DNS-compliant and must not contain periods (\".\").</p> <p> For more information about transfer acceleration, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/transfer-acceleration.html\">Transfer Acceleration</a>.</p> <p>The following operations are related to <code>PutBucketAccelerateConfiguration</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketAccelerateConfiguration.html\">GetBucketAccelerateConfiguration</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateBucket.html\">CreateBucket</a> </p> </li> </ul>"
- },
- "PutBucketAcl":{
- "name":"PutBucketAcl",
- "http":{
- "method":"PUT",
- "requestUri":"/{Bucket}?acl"
- },
- "input":{"shape":"PutBucketAclRequest"},
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketPUTacl.html",
+ },
+ "PutBucketAcl":{
+ "name":"PutBucketAcl",
+ "http":{
+ "method":"PUT",
+ "requestUri":"/{Bucket}?acl"
+ },
+ "input":{"shape":"PutBucketAclRequest"},
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketPUTacl.html",
"documentation":"<p>Sets the permissions on an existing bucket using access control lists (ACL). For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/S3_ACLs_UsingACLs.html\">Using ACLs</a>. To set the ACL of a bucket, you must have <code>WRITE_ACP</code> permission.</p> <p>You can use one of the following two ways to set a bucket's permissions:</p> <ul> <li> <p>Specify the ACL in the request body</p> </li> <li> <p>Specify permissions using request headers</p> </li> </ul> <note> <p>You cannot specify access permission using both the body and the request headers.</p> </note> <p>Depending on your application needs, you may choose to set the ACL on a bucket using either the request body or the headers. For example, if you have an existing application that updates a bucket ACL using the request body, then you can continue to use that approach.</p> <p> <b>Access Permissions</b> </p> <p>You can set access permissions using one of the following methods:</p> <ul> <li> <p>Specify a canned ACL with the <code>x-amz-acl</code> request header. Amazon S3 supports a set of predefined ACLs, known as <i>canned ACLs</i>. Each canned ACL has a predefined set of grantees and permissions. Specify the canned ACL name as the value of <code>x-amz-acl</code>. If you use this header, you cannot use other access control-specific headers in your request. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#CannedACL\">Canned ACL</a>.</p> </li> <li> <p>Specify access permissions explicitly with the <code>x-amz-grant-read</code>, <code>x-amz-grant-read-acp</code>, <code>x-amz-grant-write-acp</code>, and <code>x-amz-grant-full-control</code> headers. When using these headers, you specify explicit access permissions and grantees (AWS accounts or Amazon S3 groups) who will receive the permission. If you use these ACL-specific headers, you cannot use the <code>x-amz-acl</code> header to set a canned ACL. These parameters map to the set of permissions that Amazon S3 supports in an ACL. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html\">Access Control List (ACL) Overview</a>.</p> <p>You specify each grantee as a type=value pair, where the type is one of the following:</p> <ul> <li> <p> <code>id</code> – if the value specified is the canonical user ID of an AWS account</p> </li> <li> <p> <code>uri</code> – if you are granting permissions to a predefined group</p> </li> <li> <p> <code>emailAddress</code> – if the value specified is the email address of an AWS account</p> <note> <p>Using email addresses to specify a grantee is only supported in the following AWS Regions: </p> <ul> <li> <p>US East (N. Virginia)</p> </li> <li> <p>US West (N. California)</p> </li> <li> <p> US West (Oregon)</p> </li> <li> <p> Asia Pacific (Singapore)</p> </li> <li> <p>Asia Pacific (Sydney)</p> </li> <li> <p>Asia Pacific (Tokyo)</p> </li> <li> <p>Europe (Ireland)</p> </li> <li> <p>South America (São Paulo)</p> </li> </ul> <p>For a list of all the Amazon S3 supported Regions and endpoints, see <a href=\"https://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region\">Regions and Endpoints</a> in the AWS General Reference.</p> </note> </li> </ul> <p>For example, the following <code>x-amz-grant-write</code> header grants create, overwrite, and delete objects permission to LogDelivery group predefined by Amazon S3 and two AWS accounts identified by their email addresses.</p> <p> <code>x-amz-grant-write: uri=\"http://acs.amazonaws.com/groups/s3/LogDelivery\", id=\"111122223333\", id=\"555566667777\" </code> </p> </li> </ul> <p>You can use either a canned ACL or specify access permissions explicitly. You cannot do both.</p> <p> <b>Grantee Values</b> </p> <p>You can specify the person (grantee) to whom you're assigning access rights (using request elements) in the following ways:</p> <ul> <li> <p>By the person's ID:</p> <p> <code>&lt;Grantee xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"CanonicalUser\"&gt;&lt;ID&gt;&lt;&gt;ID&lt;&gt;&lt;/ID&gt;&lt;DisplayName&gt;&lt;&gt;GranteesEmail&lt;&gt;&lt;/DisplayName&gt; &lt;/Grantee&gt;</code> </p> <p>DisplayName is optional and ignored in the request</p> </li> <li> <p>By URI:</p> <p> <code>&lt;Grantee xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"Group\"&gt;&lt;URI&gt;&lt;&gt;http://acs.amazonaws.com/groups/global/AuthenticatedUsers&lt;&gt;&lt;/URI&gt;&lt;/Grantee&gt;</code> </p> </li> <li> <p>By Email address:</p> <p> <code>&lt;Grantee xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"AmazonCustomerByEmail\"&gt;&lt;EmailAddress&gt;&lt;&gt;Grantees@email.com&lt;&gt;&lt;/EmailAddress&gt;lt;/Grantee&gt;</code> </p> <p>The grantee is resolved to the CanonicalUser and, in a response to a GET Object acl request, appears as the CanonicalUser. </p> <note> <p>Using email addresses to specify a grantee is only supported in the following AWS Regions: </p> <ul> <li> <p>US East (N. Virginia)</p> </li> <li> <p>US West (N. California)</p> </li> <li> <p> US West (Oregon)</p> </li> <li> <p> Asia Pacific (Singapore)</p> </li> <li> <p>Asia Pacific (Sydney)</p> </li> <li> <p>Asia Pacific (Tokyo)</p> </li> <li> <p>Europe (Ireland)</p> </li> <li> <p>South America (São Paulo)</p> </li> </ul> <p>For a list of all the Amazon S3 supported Regions and endpoints, see <a href=\"https://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region\">Regions and Endpoints</a> in the AWS General Reference.</p> </note> </li> </ul> <p class=\"title\"> <b>Related Resources</b> </p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateBucket.html\">CreateBucket</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucket.html\">DeleteBucket</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectAcl.html\">GetObjectAcl</a> </p> </li> </ul>",
"httpChecksumRequired":true
- },
- "PutBucketAnalyticsConfiguration":{
- "name":"PutBucketAnalyticsConfiguration",
- "http":{
- "method":"PUT",
- "requestUri":"/{Bucket}?analytics"
- },
- "input":{"shape":"PutBucketAnalyticsConfigurationRequest"},
+ },
+ "PutBucketAnalyticsConfiguration":{
+ "name":"PutBucketAnalyticsConfiguration",
+ "http":{
+ "method":"PUT",
+ "requestUri":"/{Bucket}?analytics"
+ },
+ "input":{"shape":"PutBucketAnalyticsConfigurationRequest"},
"documentation":"<p>Sets an analytics configuration for the bucket (specified by the analytics configuration ID). You can have up to 1,000 analytics configurations per bucket.</p> <p>You can choose to have storage class analysis export analysis reports sent to a comma-separated values (CSV) flat file. See the <code>DataExport</code> request element. Reports are updated daily and are based on the object filters that you configure. When selecting data export, you specify a destination bucket and an optional destination prefix where the file is written. You can export the data to a destination bucket in a different account. However, the destination bucket must be in the same Region as the bucket that you are making the PUT analytics configuration to. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/analytics-storage-class.html\">Amazon S3 Analytics – Storage Class Analysis</a>. </p> <important> <p>You must create a bucket policy on the destination bucket where the exported file is written to grant permissions to Amazon S3 to write objects to the bucket. For an example policy, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/example-bucket-policies.html#example-bucket-policies-use-case-9\">Granting Permissions for Amazon S3 Inventory and Storage Class Analysis</a>.</p> </important> <p>To use this operation, you must have permissions to perform the <code>s3:PutAnalyticsConfiguration</code> action. The bucket owner has this permission by default. The bucket owner can grant this permission to others. For more information about permissions, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-with-s3-actions.html#using-with-s3-actions-related-to-bucket-subresources\">Permissions Related to Bucket Subresource Operations</a> and <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-access-control.html\">Managing Access Permissions to Your Amazon S3 Resources</a>.</p> <p class=\"title\"> <b>Special Errors</b> </p> <ul> <li> <ul> <li> <p> <i>HTTP Error: HTTP 400 Bad Request</i> </p> </li> <li> <p> <i>Code: InvalidArgument</i> </p> </li> <li> <p> <i>Cause: Invalid argument.</i> </p> </li> </ul> </li> <li> <ul> <li> <p> <i>HTTP Error: HTTP 400 Bad Request</i> </p> </li> <li> <p> <i>Code: TooManyConfigurations</i> </p> </li> <li> <p> <i>Cause: You are attempting to create a new configuration but have already reached the 1,000-configuration limit.</i> </p> </li> </ul> </li> <li> <ul> <li> <p> <i>HTTP Error: HTTP 403 Forbidden</i> </p> </li> <li> <p> <i>Code: AccessDenied</i> </p> </li> <li> <p> <i>Cause: You are not the owner of the specified bucket, or you do not have the s3:PutAnalyticsConfiguration bucket permission to set the configuration on the bucket.</i> </p> </li> </ul> </li> </ul> <p class=\"title\"> <b>Related Resources</b> </p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketAnalyticsConfiguration.html\">GetBucketAnalyticsConfiguration</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketAnalyticsConfiguration.html\">DeleteBucketAnalyticsConfiguration</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListBucketAnalyticsConfigurations.html\">ListBucketAnalyticsConfigurations</a> </p> </li> </ul>"
- },
- "PutBucketCors":{
- "name":"PutBucketCors",
- "http":{
- "method":"PUT",
- "requestUri":"/{Bucket}?cors"
- },
- "input":{"shape":"PutBucketCorsRequest"},
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketPUTcors.html",
+ },
+ "PutBucketCors":{
+ "name":"PutBucketCors",
+ "http":{
+ "method":"PUT",
+ "requestUri":"/{Bucket}?cors"
+ },
+ "input":{"shape":"PutBucketCorsRequest"},
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketPUTcors.html",
"documentation":"<p>Sets the <code>cors</code> configuration for your bucket. If the configuration exists, Amazon S3 replaces it.</p> <p>To use this operation, you must be allowed to perform the <code>s3:PutBucketCORS</code> action. By default, the bucket owner has this permission and can grant it to others.</p> <p>You set this configuration on a bucket so that the bucket can service cross-origin requests. For example, you might want to enable a request whose origin is <code>http://www.example.com</code> to access your Amazon S3 bucket at <code>my.example.bucket.com</code> by using the browser's <code>XMLHttpRequest</code> capability.</p> <p>To enable cross-origin resource sharing (CORS) on a bucket, you add the <code>cors</code> subresource to the bucket. The <code>cors</code> subresource is an XML document in which you configure rules that identify origins and the HTTP methods that can be executed on your bucket. The document is limited to 64 KB in size. </p> <p>When Amazon S3 receives a cross-origin request (or a pre-flight OPTIONS request) against a bucket, it evaluates the <code>cors</code> configuration on the bucket and uses the first <code>CORSRule</code> rule that matches the incoming browser request to enable a cross-origin request. For a rule to match, the following conditions must be met:</p> <ul> <li> <p>The request's <code>Origin</code> header must match <code>AllowedOrigin</code> elements.</p> </li> <li> <p>The request method (for example, GET, PUT, HEAD, and so on) or the <code>Access-Control-Request-Method</code> header in case of a pre-flight <code>OPTIONS</code> request must be one of the <code>AllowedMethod</code> elements. </p> </li> <li> <p>Every header specified in the <code>Access-Control-Request-Headers</code> request header of a pre-flight request must match an <code>AllowedHeader</code> element. </p> </li> </ul> <p> For more information about CORS, go to <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/cors.html\">Enabling Cross-Origin Resource Sharing</a> in the <i>Amazon S3 User Guide</i>.</p> <p class=\"title\"> <b>Related Resources</b> </p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketCors.html\">GetBucketCors</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketCors.html\">DeleteBucketCors</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/RESTOPTIONSobject.html\">RESTOPTIONSobject</a> </p> </li> </ul>",
"httpChecksumRequired":true
- },
- "PutBucketEncryption":{
- "name":"PutBucketEncryption",
- "http":{
- "method":"PUT",
- "requestUri":"/{Bucket}?encryption"
- },
- "input":{"shape":"PutBucketEncryptionRequest"},
+ },
+ "PutBucketEncryption":{
+ "name":"PutBucketEncryption",
+ "http":{
+ "method":"PUT",
+ "requestUri":"/{Bucket}?encryption"
+ },
+ "input":{"shape":"PutBucketEncryptionRequest"},
"documentation":"<p>This action uses the <code>encryption</code> subresource to configure default encryption and Amazon S3 Bucket Key for an existing bucket.</p> <p>Default encryption for a bucket can use server-side encryption with Amazon S3-managed keys (SSE-S3) or AWS KMS customer master keys (SSE-KMS). If you specify default encryption using SSE-KMS, you can also configure Amazon S3 Bucket Key. For information about default encryption, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/bucket-encryption.html\">Amazon S3 default bucket encryption</a> in the <i>Amazon S3 User Guide</i>. For more information about S3 Bucket Keys, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/bucket-key.html\">Amazon S3 Bucket Keys</a> in the <i>Amazon S3 User Guide</i>.</p> <important> <p>This action requires AWS Signature Version 4. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html\"> Authenticating Requests (AWS Signature Version 4)</a>. </p> </important> <p>To use this operation, you must have permissions to perform the <code>s3:PutEncryptionConfiguration</code> action. The bucket owner has this permission by default. The bucket owner can grant this permission to others. For more information about permissions, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-with-s3-actions.html#using-with-s3-actions-related-to-bucket-subresources\">Permissions Related to Bucket Subresource Operations</a> and <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-access-control.html\">Managing Access Permissions to Your Amazon S3 Resources</a> in the Amazon S3 User Guide. </p> <p class=\"title\"> <b>Related Resources</b> </p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketEncryption.html\">GetBucketEncryption</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketEncryption.html\">DeleteBucketEncryption</a> </p> </li> </ul>",
"httpChecksumRequired":true
- },
+ },
"PutBucketIntelligentTieringConfiguration":{
"name":"PutBucketIntelligentTieringConfiguration",
"http":{
@@ -799,78 +799,78 @@
"input":{"shape":"PutBucketIntelligentTieringConfigurationRequest"},
"documentation":"<p>Puts a S3 Intelligent-Tiering configuration to the specified bucket. You can have up to 1,000 S3 Intelligent-Tiering configurations per bucket.</p> <p>The S3 Intelligent-Tiering storage class is designed to optimize storage costs by automatically moving data to the most cost-effective storage access tier, without additional operational overhead. S3 Intelligent-Tiering delivers automatic cost savings by moving data between access tiers, when access patterns change.</p> <p>The S3 Intelligent-Tiering storage class is suitable for objects larger than 128 KB that you plan to store for at least 30 days. If the size of an object is less than 128 KB, it is not eligible for auto-tiering. Smaller objects can be stored, but they are always charged at the frequent access tier rates in the S3 Intelligent-Tiering storage class. </p> <p>If you delete an object before the end of the 30-day minimum storage duration period, you are charged for 30 days. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/storage-class-intro.html#sc-dynamic-data-access\">Storage class for automatically optimizing frequently and infrequently accessed objects</a>.</p> <p>Operations related to <code>PutBucketIntelligentTieringConfiguration</code> include: </p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketIntelligentTieringConfiguration.html\">DeleteBucketIntelligentTieringConfiguration</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketIntelligentTieringConfiguration.html\">GetBucketIntelligentTieringConfiguration</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListBucketIntelligentTieringConfigurations.html\">ListBucketIntelligentTieringConfigurations</a> </p> </li> </ul> <note> <p>You only need S3 Intelligent-Tiering enabled on a bucket if you want to automatically move objects stored in the S3 Intelligent-Tiering storage class to the Archive Access or Deep Archive Access tier.</p> </note> <p class=\"title\"> <b>Special Errors</b> </p> <ul> <li> <p class=\"title\"> <b>HTTP 400 Bad Request Error</b> </p> <ul> <li> <p> <i>Code:</i> InvalidArgument</p> </li> <li> <p> <i>Cause:</i> Invalid Argument</p> </li> </ul> </li> <li> <p class=\"title\"> <b>HTTP 400 Bad Request Error</b> </p> <ul> <li> <p> <i>Code:</i> TooManyConfigurations</p> </li> <li> <p> <i>Cause:</i> You are attempting to create a new configuration but have already reached the 1,000-configuration limit. </p> </li> </ul> </li> <li> <p class=\"title\"> <b>HTTP 403 Forbidden Error</b> </p> <ul> <li> <p> <i>Code:</i> AccessDenied</p> </li> <li> <p> <i>Cause:</i> You are not the owner of the specified bucket, or you do not have the <code>s3:PutIntelligentTieringConfiguration</code> bucket permission to set the configuration on the bucket. </p> </li> </ul> </li> </ul>"
},
- "PutBucketInventoryConfiguration":{
- "name":"PutBucketInventoryConfiguration",
- "http":{
- "method":"PUT",
- "requestUri":"/{Bucket}?inventory"
- },
- "input":{"shape":"PutBucketInventoryConfigurationRequest"},
+ "PutBucketInventoryConfiguration":{
+ "name":"PutBucketInventoryConfiguration",
+ "http":{
+ "method":"PUT",
+ "requestUri":"/{Bucket}?inventory"
+ },
+ "input":{"shape":"PutBucketInventoryConfigurationRequest"},
"documentation":"<p>This implementation of the <code>PUT</code> action adds an inventory configuration (identified by the inventory ID) to the bucket. You can have up to 1,000 inventory configurations per bucket. </p> <p>Amazon S3 inventory generates inventories of the objects in the bucket on a daily or weekly basis, and the results are published to a flat file. The bucket that is inventoried is called the <i>source</i> bucket, and the bucket where the inventory flat file is stored is called the <i>destination</i> bucket. The <i>destination</i> bucket must be in the same AWS Region as the <i>source</i> bucket. </p> <p>When you configure an inventory for a <i>source</i> bucket, you specify the <i>destination</i> bucket where you want the inventory to be stored, and whether to generate the inventory daily or weekly. You can also configure what object metadata to include and whether to inventory all object versions or only current versions. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/storage-inventory.html\">Amazon S3 Inventory</a> in the Amazon S3 User Guide.</p> <important> <p>You must create a bucket policy on the <i>destination</i> bucket to grant permissions to Amazon S3 to write objects to the bucket in the defined location. For an example policy, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/example-bucket-policies.html#example-bucket-policies-use-case-9\"> Granting Permissions for Amazon S3 Inventory and Storage Class Analysis</a>.</p> </important> <p>To use this operation, you must have permissions to perform the <code>s3:PutInventoryConfiguration</code> action. The bucket owner has this permission by default and can grant this permission to others. For more information about permissions, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-with-s3-actions.html#using-with-s3-actions-related-to-bucket-subresources\">Permissions Related to Bucket Subresource Operations</a> and <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-access-control.html\">Managing Access Permissions to Your Amazon S3 Resources</a> in the Amazon S3 User Guide.</p> <p class=\"title\"> <b>Special Errors</b> </p> <ul> <li> <p class=\"title\"> <b>HTTP 400 Bad Request Error</b> </p> <ul> <li> <p> <i>Code:</i> InvalidArgument</p> </li> <li> <p> <i>Cause:</i> Invalid Argument</p> </li> </ul> </li> <li> <p class=\"title\"> <b>HTTP 400 Bad Request Error</b> </p> <ul> <li> <p> <i>Code:</i> TooManyConfigurations</p> </li> <li> <p> <i>Cause:</i> You are attempting to create a new configuration but have already reached the 1,000-configuration limit. </p> </li> </ul> </li> <li> <p class=\"title\"> <b>HTTP 403 Forbidden Error</b> </p> <ul> <li> <p> <i>Code:</i> AccessDenied</p> </li> <li> <p> <i>Cause:</i> You are not the owner of the specified bucket, or you do not have the <code>s3:PutInventoryConfiguration</code> bucket permission to set the configuration on the bucket. </p> </li> </ul> </li> </ul> <p class=\"title\"> <b>Related Resources</b> </p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketInventoryConfiguration.html\">GetBucketInventoryConfiguration</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketInventoryConfiguration.html\">DeleteBucketInventoryConfiguration</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListBucketInventoryConfigurations.html\">ListBucketInventoryConfigurations</a> </p> </li> </ul>"
- },
- "PutBucketLifecycle":{
- "name":"PutBucketLifecycle",
- "http":{
- "method":"PUT",
- "requestUri":"/{Bucket}?lifecycle"
- },
- "input":{"shape":"PutBucketLifecycleRequest"},
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketPUTlifecycle.html",
+ },
+ "PutBucketLifecycle":{
+ "name":"PutBucketLifecycle",
+ "http":{
+ "method":"PUT",
+ "requestUri":"/{Bucket}?lifecycle"
+ },
+ "input":{"shape":"PutBucketLifecycleRequest"},
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketPUTlifecycle.html",
"documentation":"<important> <p>For an updated version of this API, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketLifecycleConfiguration.html\">PutBucketLifecycleConfiguration</a>. This version has been deprecated. Existing lifecycle configurations will work. For new lifecycle configurations, use the updated API. </p> </important> <p>Creates a new lifecycle configuration for the bucket or replaces an existing lifecycle configuration. For information about lifecycle configuration, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/object-lifecycle-mgmt.html\">Object Lifecycle Management</a> in the <i>Amazon S3 User Guide</i>. </p> <p>By default, all Amazon S3 resources, including buckets, objects, and related subresources (for example, lifecycle configuration and website configuration) are private. Only the resource owner, the AWS account that created the resource, can access it. The resource owner can optionally grant access permissions to others by writing an access policy. For this operation, users must get the <code>s3:PutLifecycleConfiguration</code> permission.</p> <p>You can also explicitly deny permissions. Explicit denial also supersedes any other permissions. If you want to prevent users or accounts from removing or deleting objects from your bucket, you must deny them permissions for the following actions: </p> <ul> <li> <p> <code>s3:DeleteObject</code> </p> </li> <li> <p> <code>s3:DeleteObjectVersion</code> </p> </li> <li> <p> <code>s3:PutLifecycleConfiguration</code> </p> </li> </ul> <p>For more information about permissions, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-access-control.html\">Managing Access Permissions to your Amazon S3 Resources</a> in the <i>Amazon S3 User Guide</i>.</p> <p>For more examples of transitioning objects to storage classes such as STANDARD_IA or ONEZONE_IA, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/intro-lifecycle-rules.html#lifecycle-configuration-examples\">Examples of Lifecycle Configuration</a>.</p> <p class=\"title\"> <b>Related Resources</b> </p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketLifecycle.html\">GetBucketLifecycle</a>(Deprecated)</p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketLifecycleConfiguration.html\">GetBucketLifecycleConfiguration</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_RestoreObject.html\">RestoreObject</a> </p> </li> <li> <p>By default, a resource owner—in this case, a bucket owner, which is the AWS account that created the bucket—can perform any of the operations. A resource owner can also grant others permission to perform the operation. For more information, see the following topics in the Amazon S3 User Guide: </p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/using-with-s3-actions.html\">Specifying Permissions in a Policy</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-access-control.html\">Managing Access Permissions to your Amazon S3 Resources</a> </p> </li> </ul> </li> </ul>",
"deprecated":true,
"httpChecksumRequired":true
- },
- "PutBucketLifecycleConfiguration":{
- "name":"PutBucketLifecycleConfiguration",
- "http":{
- "method":"PUT",
- "requestUri":"/{Bucket}?lifecycle"
- },
- "input":{"shape":"PutBucketLifecycleConfigurationRequest"},
+ },
+ "PutBucketLifecycleConfiguration":{
+ "name":"PutBucketLifecycleConfiguration",
+ "http":{
+ "method":"PUT",
+ "requestUri":"/{Bucket}?lifecycle"
+ },
+ "input":{"shape":"PutBucketLifecycleConfigurationRequest"},
"documentation":"<p>Creates a new lifecycle configuration for the bucket or replaces an existing lifecycle configuration. For information about lifecycle configuration, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lifecycle-mgmt.html\">Managing your storage lifecycle</a>.</p> <note> <p>Bucket lifecycle configuration now supports specifying a lifecycle rule using an object key name prefix, one or more object tags, or a combination of both. Accordingly, this section describes the latest API. The previous version of the API supported filtering based only on an object key name prefix, which is supported for backward compatibility. For the related API description, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketLifecycle.html\">PutBucketLifecycle</a>.</p> </note> <p> <b>Rules</b> </p> <p>You specify the lifecycle configuration in your request body. The lifecycle configuration is specified as XML consisting of one or more rules. Each rule consists of the following:</p> <ul> <li> <p>Filter identifying a subset of objects to which the rule applies. The filter can be based on a key name prefix, object tags, or a combination of both.</p> </li> <li> <p>Status whether the rule is in effect.</p> </li> <li> <p>One or more lifecycle transition and expiration actions that you want Amazon S3 to perform on the objects identified by the filter. If the state of your bucket is versioning-enabled or versioning-suspended, you can have many versions of the same object (one current version and zero or more noncurrent versions). Amazon S3 provides predefined actions that you can specify for current and noncurrent object versions.</p> </li> </ul> <p>For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/object-lifecycle-mgmt.html\">Object Lifecycle Management</a> and <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/intro-lifecycle-rules.html\">Lifecycle Configuration Elements</a>.</p> <p> <b>Permissions</b> </p> <p>By default, all Amazon S3 resources are private, including buckets, objects, and related subresources (for example, lifecycle configuration and website configuration). Only the resource owner (that is, the AWS account that created it) can access the resource. The resource owner can optionally grant access permissions to others by writing an access policy. For this operation, a user must get the s3:PutLifecycleConfiguration permission.</p> <p>You can also explicitly deny permissions. Explicit deny also supersedes any other permissions. If you want to block users or accounts from removing or deleting objects from your bucket, you must deny them permissions for the following actions:</p> <ul> <li> <p>s3:DeleteObject</p> </li> <li> <p>s3:DeleteObjectVersion</p> </li> <li> <p>s3:PutLifecycleConfiguration</p> </li> </ul> <p>For more information about permissions, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-access-control.html\">Managing Access Permissions to Your Amazon S3 Resources</a>.</p> <p>The following are related to <code>PutBucketLifecycleConfiguration</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/lifecycle-configuration-examples.html\">Examples of Lifecycle Configuration</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketLifecycleConfiguration.html\">GetBucketLifecycleConfiguration</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketLifecycle.html\">DeleteBucketLifecycle</a> </p> </li> </ul>",
"httpChecksumRequired":true
- },
- "PutBucketLogging":{
- "name":"PutBucketLogging",
- "http":{
- "method":"PUT",
- "requestUri":"/{Bucket}?logging"
- },
- "input":{"shape":"PutBucketLoggingRequest"},
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketPUTlogging.html",
+ },
+ "PutBucketLogging":{
+ "name":"PutBucketLogging",
+ "http":{
+ "method":"PUT",
+ "requestUri":"/{Bucket}?logging"
+ },
+ "input":{"shape":"PutBucketLoggingRequest"},
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketPUTlogging.html",
"documentation":"<p>Set the logging parameters for a bucket and to specify permissions for who can view and modify the logging parameters. All logs are saved to buckets in the same AWS Region as the source bucket. To set the logging status of a bucket, you must be the bucket owner.</p> <p>The bucket owner is automatically granted FULL_CONTROL to all logs. You use the <code>Grantee</code> request element to grant access to other people. The <code>Permissions</code> request element specifies the kind of access the grantee has to the logs.</p> <p> <b>Grantee Values</b> </p> <p>You can specify the person (grantee) to whom you're assigning access rights (using request elements) in the following ways:</p> <ul> <li> <p>By the person's ID:</p> <p> <code>&lt;Grantee xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"CanonicalUser\"&gt;&lt;ID&gt;&lt;&gt;ID&lt;&gt;&lt;/ID&gt;&lt;DisplayName&gt;&lt;&gt;GranteesEmail&lt;&gt;&lt;/DisplayName&gt; &lt;/Grantee&gt;</code> </p> <p>DisplayName is optional and ignored in the request.</p> </li> <li> <p>By Email address:</p> <p> <code> &lt;Grantee xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"AmazonCustomerByEmail\"&gt;&lt;EmailAddress&gt;&lt;&gt;Grantees@email.com&lt;&gt;&lt;/EmailAddress&gt;&lt;/Grantee&gt;</code> </p> <p>The grantee is resolved to the CanonicalUser and, in a response to a GET Object acl request, appears as the CanonicalUser.</p> </li> <li> <p>By URI:</p> <p> <code>&lt;Grantee xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"Group\"&gt;&lt;URI&gt;&lt;&gt;http://acs.amazonaws.com/groups/global/AuthenticatedUsers&lt;&gt;&lt;/URI&gt;&lt;/Grantee&gt;</code> </p> </li> </ul> <p>To enable logging, you use LoggingEnabled and its children request elements. To disable logging, you use an empty BucketLoggingStatus request element:</p> <p> <code>&lt;BucketLoggingStatus xmlns=\"http://doc.s3.amazonaws.com/2006-03-01\" /&gt;</code> </p> <p>For more information about server access logging, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerLogs.html\">Server Access Logging</a>. </p> <p>For more information about creating a bucket, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateBucket.html\">CreateBucket</a>. For more information about returning the logging status of a bucket, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketLogging.html\">GetBucketLogging</a>.</p> <p>The following operations are related to <code>PutBucketLogging</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html\">PutObject</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucket.html\">DeleteBucket</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateBucket.html\">CreateBucket</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketLogging.html\">GetBucketLogging</a> </p> </li> </ul>",
"httpChecksumRequired":true
- },
- "PutBucketMetricsConfiguration":{
- "name":"PutBucketMetricsConfiguration",
- "http":{
- "method":"PUT",
- "requestUri":"/{Bucket}?metrics"
- },
- "input":{"shape":"PutBucketMetricsConfigurationRequest"},
+ },
+ "PutBucketMetricsConfiguration":{
+ "name":"PutBucketMetricsConfiguration",
+ "http":{
+ "method":"PUT",
+ "requestUri":"/{Bucket}?metrics"
+ },
+ "input":{"shape":"PutBucketMetricsConfigurationRequest"},
"documentation":"<p>Sets a metrics configuration (specified by the metrics configuration ID) for the bucket. You can have up to 1,000 metrics configurations per bucket. If you're updating an existing metrics configuration, note that this is a full replacement of the existing metrics configuration. If you don't include the elements you want to keep, they are erased.</p> <p>To use this operation, you must have permissions to perform the <code>s3:PutMetricsConfiguration</code> action. The bucket owner has this permission by default. The bucket owner can grant this permission to others. For more information about permissions, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-with-s3-actions.html#using-with-s3-actions-related-to-bucket-subresources\">Permissions Related to Bucket Subresource Operations</a> and <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-access-control.html\">Managing Access Permissions to Your Amazon S3 Resources</a>.</p> <p>For information about CloudWatch request metrics for Amazon S3, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/cloudwatch-monitoring.html\">Monitoring Metrics with Amazon CloudWatch</a>.</p> <p>The following operations are related to <code>PutBucketMetricsConfiguration</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketMetricsConfiguration.html\">DeleteBucketMetricsConfiguration</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketMetricsConfiguration.html\">PutBucketMetricsConfiguration</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListBucketMetricsConfigurations.html\">ListBucketMetricsConfigurations</a> </p> </li> </ul> <p> <code>GetBucketLifecycle</code> has the following special error:</p> <ul> <li> <p>Error code: <code>TooManyConfigurations</code> </p> <ul> <li> <p>Description: You are attempting to create a new configuration but have already reached the 1,000-configuration limit.</p> </li> <li> <p>HTTP Status Code: HTTP 400 Bad Request</p> </li> </ul> </li> </ul>"
- },
- "PutBucketNotification":{
- "name":"PutBucketNotification",
- "http":{
- "method":"PUT",
- "requestUri":"/{Bucket}?notification"
- },
- "input":{"shape":"PutBucketNotificationRequest"},
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketPUTnotification.html",
+ },
+ "PutBucketNotification":{
+ "name":"PutBucketNotification",
+ "http":{
+ "method":"PUT",
+ "requestUri":"/{Bucket}?notification"
+ },
+ "input":{"shape":"PutBucketNotificationRequest"},
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketPUTnotification.html",
"documentation":"<p> No longer used, see the <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketNotificationConfiguration.html\">PutBucketNotificationConfiguration</a> operation.</p>",
"deprecated":true,
"httpChecksumRequired":true
- },
- "PutBucketNotificationConfiguration":{
- "name":"PutBucketNotificationConfiguration",
- "http":{
- "method":"PUT",
- "requestUri":"/{Bucket}?notification"
- },
- "input":{"shape":"PutBucketNotificationConfigurationRequest"},
+ },
+ "PutBucketNotificationConfiguration":{
+ "name":"PutBucketNotificationConfiguration",
+ "http":{
+ "method":"PUT",
+ "requestUri":"/{Bucket}?notification"
+ },
+ "input":{"shape":"PutBucketNotificationConfigurationRequest"},
"documentation":"<p>Enables notifications of specified events for a bucket. For more information about event notifications, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/NotificationHowTo.html\">Configuring Event Notifications</a>.</p> <p>Using this API, you can replace an existing notification configuration. The configuration is an XML file that defines the event types that you want Amazon S3 to publish and the destination where you want Amazon S3 to publish an event notification when it detects an event of the specified type.</p> <p>By default, your bucket has no event notifications configured. That is, the notification configuration will be an empty <code>NotificationConfiguration</code>.</p> <p> <code>&lt;NotificationConfiguration&gt;</code> </p> <p> <code>&lt;/NotificationConfiguration&gt;</code> </p> <p>This action replaces the existing notification configuration with the configuration you include in the request body.</p> <p>After Amazon S3 receives this request, it first verifies that any Amazon Simple Notification Service (Amazon SNS) or Amazon Simple Queue Service (Amazon SQS) destination exists, and that the bucket owner has permission to publish to it by sending a test notification. In the case of AWS Lambda destinations, Amazon S3 verifies that the Lambda function permissions grant Amazon S3 permission to invoke the function from the Amazon S3 bucket. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/NotificationHowTo.html\">Configuring Notifications for Amazon S3 Events</a>.</p> <p>You can disable notifications by adding the empty NotificationConfiguration element.</p> <p>By default, only the bucket owner can configure notifications on a bucket. However, bucket owners can use a bucket policy to grant permission to other users to set this configuration with <code>s3:PutBucketNotification</code> permission.</p> <note> <p>The PUT notification is an atomic operation. For example, suppose your notification configuration includes SNS topic, SQS queue, and Lambda function configurations. When you send a PUT request with this configuration, Amazon S3 sends test messages to your SNS topic. If the message fails, the entire PUT action will fail, and Amazon S3 will not add the configuration to your bucket.</p> </note> <p> <b>Responses</b> </p> <p>If the configuration in the request body includes only one <code>TopicConfiguration</code> specifying only the <code>s3:ReducedRedundancyLostObject</code> event type, the response will also include the <code>x-amz-sns-test-message-id</code> header containing the message ID of the test notification sent to the topic.</p> <p>The following action is related to <code>PutBucketNotificationConfiguration</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketNotificationConfiguration.html\">GetBucketNotificationConfiguration</a> </p> </li> </ul>"
- },
+ },
"PutBucketOwnershipControls":{
"name":"PutBucketOwnershipControls",
"http":{
@@ -881,97 +881,97 @@
"documentation":"<p>Creates or modifies <code>OwnershipControls</code> for an Amazon S3 bucket. To use this operation, you must have the <code>s3:PutBucketOwnershipControls</code> permission. For more information about Amazon S3 permissions, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/using-with-s3-actions.html\">Specifying Permissions in a Policy</a>. </p> <p>For information about Amazon S3 Object Ownership, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/about-object-ownership.html\">Using Object Ownership</a>. </p> <p>The following operations are related to <code>PutBucketOwnershipControls</code>:</p> <ul> <li> <p> <a>GetBucketOwnershipControls</a> </p> </li> <li> <p> <a>DeleteBucketOwnershipControls</a> </p> </li> </ul>",
"httpChecksumRequired":true
},
- "PutBucketPolicy":{
- "name":"PutBucketPolicy",
- "http":{
- "method":"PUT",
- "requestUri":"/{Bucket}?policy"
- },
- "input":{"shape":"PutBucketPolicyRequest"},
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketPUTpolicy.html",
+ "PutBucketPolicy":{
+ "name":"PutBucketPolicy",
+ "http":{
+ "method":"PUT",
+ "requestUri":"/{Bucket}?policy"
+ },
+ "input":{"shape":"PutBucketPolicyRequest"},
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketPUTpolicy.html",
"documentation":"<p>Applies an Amazon S3 bucket policy to an Amazon S3 bucket. If you are using an identity other than the root user of the AWS account that owns the bucket, the calling identity must have the <code>PutBucketPolicy</code> permissions on the specified bucket and belong to the bucket owner's account in order to use this operation.</p> <p>If you don't have <code>PutBucketPolicy</code> permissions, Amazon S3 returns a <code>403 Access Denied</code> error. If you have the correct permissions, but you're not using an identity that belongs to the bucket owner's account, Amazon S3 returns a <code>405 Method Not Allowed</code> error.</p> <important> <p> As a security precaution, the root user of the AWS account that owns a bucket can always use this operation, even if the policy explicitly denies the root user the ability to perform this action. </p> </important> <p>For more information about bucket policies, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/using-iam-policies.html\">Using Bucket Policies and User Policies</a>.</p> <p>The following operations are related to <code>PutBucketPolicy</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateBucket.html\">CreateBucket</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucket.html\">DeleteBucket</a> </p> </li> </ul>",
"httpChecksumRequired":true
- },
- "PutBucketReplication":{
- "name":"PutBucketReplication",
- "http":{
- "method":"PUT",
- "requestUri":"/{Bucket}?replication"
- },
- "input":{"shape":"PutBucketReplicationRequest"},
+ },
+ "PutBucketReplication":{
+ "name":"PutBucketReplication",
+ "http":{
+ "method":"PUT",
+ "requestUri":"/{Bucket}?replication"
+ },
+ "input":{"shape":"PutBucketReplicationRequest"},
"documentation":"<p> Creates a replication configuration or replaces an existing one. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/replication.html\">Replication</a> in the <i>Amazon S3 User Guide</i>. </p> <note> <p>To perform this operation, the user or role performing the action must have the <a href=\"https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_passrole.html\">iam:PassRole</a> permission.</p> </note> <p>Specify the replication configuration in the request body. In the replication configuration, you provide the name of the destination bucket or buckets where you want Amazon S3 to replicate objects, the IAM role that Amazon S3 can assume to replicate objects on your behalf, and other relevant information.</p> <p>A replication configuration must include at least one rule, and can contain a maximum of 1,000. Each rule identifies a subset of objects to replicate by filtering the objects in the source bucket. To choose additional subsets of objects to replicate, add a rule for each subset.</p> <p>To specify a subset of the objects in the source bucket to apply a replication rule to, add the Filter element as a child of the Rule element. You can filter objects based on an object key prefix, one or more object tags, or both. When you add the Filter element in the configuration, you must also add the following elements: <code>DeleteMarkerReplication</code>, <code>Status</code>, and <code>Priority</code>.</p> <note> <p>If you are using an earlier version of the replication configuration, Amazon S3 handles replication of delete markers differently. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/replication-add-config.html#replication-backward-compat-considerations\">Backward Compatibility</a>.</p> </note> <p>For information about enabling versioning on a bucket, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/Versioning.html\">Using Versioning</a>.</p> <p>By default, a resource owner, in this case the AWS account that created the bucket, can perform this operation. The resource owner can also grant others permissions to perform the operation. For more information about permissions, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/using-with-s3-actions.html\">Specifying Permissions in a Policy</a> and <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-access-control.html\">Managing Access Permissions to Your Amazon S3 Resources</a>.</p> <p> <b>Handling Replication of Encrypted Objects</b> </p> <p>By default, Amazon S3 doesn't replicate objects that are stored at rest using server-side encryption with CMKs stored in AWS KMS. To replicate AWS KMS-encrypted objects, add the following: <code>SourceSelectionCriteria</code>, <code>SseKmsEncryptedObjects</code>, <code>Status</code>, <code>EncryptionConfiguration</code>, and <code>ReplicaKmsKeyID</code>. For information about replication configuration, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/replication-config-for-kms-objects.html\">Replicating Objects Created with SSE Using CMKs stored in AWS KMS</a>.</p> <p>For information on <code>PutBucketReplication</code> errors, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html#ReplicationErrorCodeList\">List of replication-related error codes</a> </p> <p>The following operations are related to <code>PutBucketReplication</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketReplication.html\">GetBucketReplication</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketReplication.html\">DeleteBucketReplication</a> </p> </li> </ul>",
"httpChecksumRequired":true
- },
- "PutBucketRequestPayment":{
- "name":"PutBucketRequestPayment",
- "http":{
- "method":"PUT",
- "requestUri":"/{Bucket}?requestPayment"
- },
- "input":{"shape":"PutBucketRequestPaymentRequest"},
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTrequestPaymentPUT.html",
+ },
+ "PutBucketRequestPayment":{
+ "name":"PutBucketRequestPayment",
+ "http":{
+ "method":"PUT",
+ "requestUri":"/{Bucket}?requestPayment"
+ },
+ "input":{"shape":"PutBucketRequestPaymentRequest"},
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTrequestPaymentPUT.html",
"documentation":"<p>Sets the request payment configuration for a bucket. By default, the bucket owner pays for downloads from the bucket. This configuration parameter enables the bucket owner (only) to specify that the person requesting the download will be charged for the download. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/RequesterPaysBuckets.html\">Requester Pays Buckets</a>.</p> <p>The following operations are related to <code>PutBucketRequestPayment</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateBucket.html\">CreateBucket</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketRequestPayment.html\">GetBucketRequestPayment</a> </p> </li> </ul>",
"httpChecksumRequired":true
- },
- "PutBucketTagging":{
- "name":"PutBucketTagging",
- "http":{
- "method":"PUT",
- "requestUri":"/{Bucket}?tagging"
- },
- "input":{"shape":"PutBucketTaggingRequest"},
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketPUTtagging.html",
+ },
+ "PutBucketTagging":{
+ "name":"PutBucketTagging",
+ "http":{
+ "method":"PUT",
+ "requestUri":"/{Bucket}?tagging"
+ },
+ "input":{"shape":"PutBucketTaggingRequest"},
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketPUTtagging.html",
"documentation":"<p>Sets the tags for a bucket.</p> <p>Use tags to organize your AWS bill to reflect your own cost structure. To do this, sign up to get your AWS account bill with tag key values included. Then, to see the cost of combined resources, organize your billing information according to resources with the same tag key values. For example, you can tag several resources with a specific application name, and then organize your billing information to see the total cost of that application across several services. For more information, see <a href=\"https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/cost-alloc-tags.html\">Cost Allocation and Tagging</a> and <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/CostAllocTagging.html\">Using Cost Allocation in Amazon S3 Bucket Tags</a>.</p> <note> <p> When this operation sets the tags for a bucket, it will overwrite any current tags the bucket already has. You cannot use this operation to add tags to an existing list of tags.</p> </note> <p>To use this operation, you must have permissions to perform the <code>s3:PutBucketTagging</code> action. The bucket owner has this permission by default and can grant this permission to others. For more information about permissions, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-with-s3-actions.html#using-with-s3-actions-related-to-bucket-subresources\">Permissions Related to Bucket Subresource Operations</a> and <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-access-control.html\">Managing Access Permissions to Your Amazon S3 Resources</a>.</p> <p> <code>PutBucketTagging</code> has the following special errors:</p> <ul> <li> <p>Error code: <code>InvalidTagError</code> </p> <ul> <li> <p>Description: The tag provided was not a valid tag. This error can occur if the tag did not pass input validation. For information about tag restrictions, see <a href=\"https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/allocation-tag-restrictions.html\">User-Defined Tag Restrictions</a> and <a href=\"https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/aws-tag-restrictions.html\">AWS-Generated Cost Allocation Tag Restrictions</a>.</p> </li> </ul> </li> <li> <p>Error code: <code>MalformedXMLError</code> </p> <ul> <li> <p>Description: The XML provided does not match the schema.</p> </li> </ul> </li> <li> <p>Error code: <code>OperationAbortedError </code> </p> <ul> <li> <p>Description: A conflicting conditional action is currently in progress against this resource. Please try again.</p> </li> </ul> </li> <li> <p>Error code: <code>InternalError</code> </p> <ul> <li> <p>Description: The service was unable to apply the provided tag to the bucket.</p> </li> </ul> </li> </ul> <p>The following operations are related to <code>PutBucketTagging</code>:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketTagging.html\">GetBucketTagging</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketTagging.html\">DeleteBucketTagging</a> </p> </li> </ul>",
"httpChecksumRequired":true
- },
- "PutBucketVersioning":{
- "name":"PutBucketVersioning",
- "http":{
- "method":"PUT",
- "requestUri":"/{Bucket}?versioning"
- },
- "input":{"shape":"PutBucketVersioningRequest"},
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketPUTVersioningStatus.html",
+ },
+ "PutBucketVersioning":{
+ "name":"PutBucketVersioning",
+ "http":{
+ "method":"PUT",
+ "requestUri":"/{Bucket}?versioning"
+ },
+ "input":{"shape":"PutBucketVersioningRequest"},
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketPUTVersioningStatus.html",
"documentation":"<p>Sets the versioning state of an existing bucket. To set the versioning state, you must be the bucket owner.</p> <p>You can set the versioning state with one of the following values:</p> <p> <b>Enabled</b>—Enables versioning for the objects in the bucket. All objects added to the bucket receive a unique version ID.</p> <p> <b>Suspended</b>—Disables versioning for the objects in the bucket. All objects added to the bucket receive the version ID null.</p> <p>If the versioning state has never been set on a bucket, it has no versioning state; a <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketVersioning.html\">GetBucketVersioning</a> request does not return a versioning state value.</p> <p>If the bucket owner enables MFA Delete in the bucket versioning configuration, the bucket owner must include the <code>x-amz-mfa request</code> header and the <code>Status</code> and the <code>MfaDelete</code> request elements in a request to set the versioning state of the bucket.</p> <important> <p>If you have an object expiration lifecycle policy in your non-versioned bucket and you want to maintain the same permanent delete behavior when you enable versioning, you must add a noncurrent expiration policy. The noncurrent expiration lifecycle policy will manage the deletes of the noncurrent object versions in the version-enabled bucket. (A version-enabled bucket maintains one current and zero or more noncurrent object versions.) For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/object-lifecycle-mgmt.html#lifecycle-and-other-bucket-config\">Lifecycle and Versioning</a>.</p> </important> <p class=\"title\"> <b>Related Resources</b> </p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateBucket.html\">CreateBucket</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucket.html\">DeleteBucket</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketVersioning.html\">GetBucketVersioning</a> </p> </li> </ul>",
"httpChecksumRequired":true
- },
- "PutBucketWebsite":{
- "name":"PutBucketWebsite",
- "http":{
- "method":"PUT",
- "requestUri":"/{Bucket}?website"
- },
- "input":{"shape":"PutBucketWebsiteRequest"},
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketPUTwebsite.html",
+ },
+ "PutBucketWebsite":{
+ "name":"PutBucketWebsite",
+ "http":{
+ "method":"PUT",
+ "requestUri":"/{Bucket}?website"
+ },
+ "input":{"shape":"PutBucketWebsiteRequest"},
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketPUTwebsite.html",
"documentation":"<p>Sets the configuration of the website that is specified in the <code>website</code> subresource. To configure a bucket as a website, you can add this subresource on the bucket with website configuration information such as the file name of the index document and any redirect rules. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/WebsiteHosting.html\">Hosting Websites on Amazon S3</a>.</p> <p>This PUT action requires the <code>S3:PutBucketWebsite</code> permission. By default, only the bucket owner can configure the website attached to a bucket; however, bucket owners can allow other users to set the website configuration by writing a bucket policy that grants them the <code>S3:PutBucketWebsite</code> permission.</p> <p>To redirect all website requests sent to the bucket's website endpoint, you add a website configuration with the following elements. Because all requests are sent to another website, you don't need to provide index document name for the bucket.</p> <ul> <li> <p> <code>WebsiteConfiguration</code> </p> </li> <li> <p> <code>RedirectAllRequestsTo</code> </p> </li> <li> <p> <code>HostName</code> </p> </li> <li> <p> <code>Protocol</code> </p> </li> </ul> <p>If you want granular control over redirects, you can use the following elements to add routing rules that describe conditions for redirecting requests and information about the redirect destination. In this case, the website configuration must provide an index document for the bucket, because some requests might not be redirected. </p> <ul> <li> <p> <code>WebsiteConfiguration</code> </p> </li> <li> <p> <code>IndexDocument</code> </p> </li> <li> <p> <code>Suffix</code> </p> </li> <li> <p> <code>ErrorDocument</code> </p> </li> <li> <p> <code>Key</code> </p> </li> <li> <p> <code>RoutingRules</code> </p> </li> <li> <p> <code>RoutingRule</code> </p> </li> <li> <p> <code>Condition</code> </p> </li> <li> <p> <code>HttpErrorCodeReturnedEquals</code> </p> </li> <li> <p> <code>KeyPrefixEquals</code> </p> </li> <li> <p> <code>Redirect</code> </p> </li> <li> <p> <code>Protocol</code> </p> </li> <li> <p> <code>HostName</code> </p> </li> <li> <p> <code>ReplaceKeyPrefixWith</code> </p> </li> <li> <p> <code>ReplaceKeyWith</code> </p> </li> <li> <p> <code>HttpRedirectCode</code> </p> </li> </ul> <p>Amazon S3 has a limitation of 50 routing rules per website configuration. If you require more than 50 routing rules, you can use object redirect. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/how-to-page-redirect.html\">Configuring an Object Redirect</a> in the <i>Amazon S3 User Guide</i>.</p>",
"httpChecksumRequired":true
- },
- "PutObject":{
- "name":"PutObject",
- "http":{
- "method":"PUT",
- "requestUri":"/{Bucket}/{Key+}"
- },
- "input":{"shape":"PutObjectRequest"},
- "output":{"shape":"PutObjectOutput"},
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectPUT.html",
+ },
+ "PutObject":{
+ "name":"PutObject",
+ "http":{
+ "method":"PUT",
+ "requestUri":"/{Bucket}/{Key+}"
+ },
+ "input":{"shape":"PutObjectRequest"},
+ "output":{"shape":"PutObjectOutput"},
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectPUT.html",
"documentation":"<p>Adds an object to a bucket. You must have WRITE permissions on a bucket to add an object to it.</p> <p>Amazon S3 never adds partial objects; if you receive a success response, Amazon S3 added the entire object to the bucket.</p> <p>Amazon S3 is a distributed system. If it receives multiple write requests for the same object simultaneously, it overwrites all but the last object written. Amazon S3 does not provide object locking; if you need this, make sure to build it into your application layer or use versioning instead.</p> <p>To ensure that data is not corrupted traversing the network, use the <code>Content-MD5</code> header. When you use this header, Amazon S3 checks the object against the provided MD5 value and, if they do not match, returns an error. Additionally, you can calculate the MD5 while putting an object to Amazon S3 and compare the returned ETag to the calculated MD5 value.</p> <note> <p> The <code>Content-MD5</code> header is required for any request to upload an object with a retention period configured using Amazon S3 Object Lock. For more information about Amazon S3 Object Lock, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/object-lock-overview.html\">Amazon S3 Object Lock Overview</a> in the <i>Amazon S3 User Guide</i>. </p> </note> <p> <b>Server-side Encryption</b> </p> <p>You can optionally request server-side encryption. With server-side encryption, Amazon S3 encrypts your data as it writes it to disks in its data centers and decrypts the data when you access it. You have the option to provide your own encryption key or use AWS managed encryption keys (SSE-S3 or SSE-KMS). For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingServerSideEncryption.html\">Using Server-Side Encryption</a>.</p> <p>If you request server-side encryption using AWS Key Management Service (SSE-KMS), you can enable an S3 Bucket Key at the object-level. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/bucket-key.html\">Amazon S3 Bucket Keys</a> in the <i>Amazon S3 User Guide</i>.</p> <p> <b>Access Control List (ACL)-Specific Request Headers</b> </p> <p>You can use headers to grant ACL- based permissions. By default, all objects are private. Only the owner has full access control. When adding a new object, you can grant permissions to individual AWS accounts or to predefined groups defined by Amazon S3. These permissions are then added to the ACL on the object. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html\">Access Control List (ACL) Overview</a> and <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-using-rest-api.html\">Managing ACLs Using the REST API</a>. </p> <p> <b>Storage Class Options</b> </p> <p>By default, Amazon S3 uses the STANDARD Storage Class to store newly created objects. The STANDARD storage class provides high durability and high availability. Depending on performance needs, you can specify a different Storage Class. Amazon S3 on Outposts only uses the OUTPOSTS Storage Class. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/storage-class-intro.html\">Storage Classes</a> in the <i>Amazon S3 User Guide</i>.</p> <p> <b>Versioning</b> </p> <p>If you enable versioning for a bucket, Amazon S3 automatically generates a unique version ID for the object being stored. Amazon S3 returns this ID in the response. When you enable versioning for a bucket, if Amazon S3 receives multiple write requests for the same object simultaneously, it stores all of the objects.</p> <p>For more information about versioning, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/AddingObjectstoVersioningEnabledBuckets.html\">Adding Objects to Versioning Enabled Buckets</a>. For information about returning the versioning state of a bucket, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketVersioning.html\">GetBucketVersioning</a>. </p> <p class=\"title\"> <b>Related Resources</b> </p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_CopyObject.html\">CopyObject</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObject.html\">DeleteObject</a> </p> </li> </ul>"
- },
- "PutObjectAcl":{
- "name":"PutObjectAcl",
- "http":{
- "method":"PUT",
- "requestUri":"/{Bucket}/{Key+}?acl"
- },
- "input":{"shape":"PutObjectAclRequest"},
- "output":{"shape":"PutObjectAclOutput"},
- "errors":[
- {"shape":"NoSuchKey"}
- ],
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectPUTacl.html",
+ },
+ "PutObjectAcl":{
+ "name":"PutObjectAcl",
+ "http":{
+ "method":"PUT",
+ "requestUri":"/{Bucket}/{Key+}?acl"
+ },
+ "input":{"shape":"PutObjectAclRequest"},
+ "output":{"shape":"PutObjectAclOutput"},
+ "errors":[
+ {"shape":"NoSuchKey"}
+ ],
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectPUTacl.html",
"documentation":"<p>Uses the <code>acl</code> subresource to set the access control list (ACL) permissions for a new or existing object in an S3 bucket. You must have <code>WRITE_ACP</code> permission to set the ACL of an object. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#permissions\">What permissions can I grant?</a> in the <i>Amazon S3 User Guide</i>.</p> <p>This action is not supported by Amazon S3 on Outposts.</p> <p>Depending on your application needs, you can choose to set the ACL on an object using either the request body or the headers. For example, if you have an existing application that updates a bucket ACL using the request body, you can continue to use that approach. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html\">Access Control List (ACL) Overview</a> in the <i>Amazon S3 User Guide</i>.</p> <p> <b>Access Permissions</b> </p> <p>You can set access permissions using one of the following methods:</p> <ul> <li> <p>Specify a canned ACL with the <code>x-amz-acl</code> request header. Amazon S3 supports a set of predefined ACLs, known as canned ACLs. Each canned ACL has a predefined set of grantees and permissions. Specify the canned ACL name as the value of <code>x-amz-ac</code>l. If you use this header, you cannot use other access control-specific headers in your request. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#CannedACL\">Canned ACL</a>.</p> </li> <li> <p>Specify access permissions explicitly with the <code>x-amz-grant-read</code>, <code>x-amz-grant-read-acp</code>, <code>x-amz-grant-write-acp</code>, and <code>x-amz-grant-full-control</code> headers. When using these headers, you specify explicit access permissions and grantees (AWS accounts or Amazon S3 groups) who will receive the permission. If you use these ACL-specific headers, you cannot use <code>x-amz-acl</code> header to set a canned ACL. These parameters map to the set of permissions that Amazon S3 supports in an ACL. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html\">Access Control List (ACL) Overview</a>.</p> <p>You specify each grantee as a type=value pair, where the type is one of the following:</p> <ul> <li> <p> <code>id</code> – if the value specified is the canonical user ID of an AWS account</p> </li> <li> <p> <code>uri</code> – if you are granting permissions to a predefined group</p> </li> <li> <p> <code>emailAddress</code> – if the value specified is the email address of an AWS account</p> <note> <p>Using email addresses to specify a grantee is only supported in the following AWS Regions: </p> <ul> <li> <p>US East (N. Virginia)</p> </li> <li> <p>US West (N. California)</p> </li> <li> <p> US West (Oregon)</p> </li> <li> <p> Asia Pacific (Singapore)</p> </li> <li> <p>Asia Pacific (Sydney)</p> </li> <li> <p>Asia Pacific (Tokyo)</p> </li> <li> <p>Europe (Ireland)</p> </li> <li> <p>South America (São Paulo)</p> </li> </ul> <p>For a list of all the Amazon S3 supported Regions and endpoints, see <a href=\"https://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region\">Regions and Endpoints</a> in the AWS General Reference.</p> </note> </li> </ul> <p>For example, the following <code>x-amz-grant-read</code> header grants list objects permission to the two AWS accounts identified by their email addresses.</p> <p> <code>x-amz-grant-read: emailAddress=\"xyz@amazon.com\", emailAddress=\"abc@amazon.com\" </code> </p> </li> </ul> <p>You can use either a canned ACL or specify access permissions explicitly. You cannot do both.</p> <p> <b>Grantee Values</b> </p> <p>You can specify the person (grantee) to whom you're assigning access rights (using request elements) in the following ways:</p> <ul> <li> <p>By the person's ID:</p> <p> <code>&lt;Grantee xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"CanonicalUser\"&gt;&lt;ID&gt;&lt;&gt;ID&lt;&gt;&lt;/ID&gt;&lt;DisplayName&gt;&lt;&gt;GranteesEmail&lt;&gt;&lt;/DisplayName&gt; &lt;/Grantee&gt;</code> </p> <p>DisplayName is optional and ignored in the request.</p> </li> <li> <p>By URI:</p> <p> <code>&lt;Grantee xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"Group\"&gt;&lt;URI&gt;&lt;&gt;http://acs.amazonaws.com/groups/global/AuthenticatedUsers&lt;&gt;&lt;/URI&gt;&lt;/Grantee&gt;</code> </p> </li> <li> <p>By Email address:</p> <p> <code>&lt;Grantee xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"AmazonCustomerByEmail\"&gt;&lt;EmailAddress&gt;&lt;&gt;Grantees@email.com&lt;&gt;&lt;/EmailAddress&gt;lt;/Grantee&gt;</code> </p> <p>The grantee is resolved to the CanonicalUser and, in a response to a GET Object acl request, appears as the CanonicalUser.</p> <note> <p>Using email addresses to specify a grantee is only supported in the following AWS Regions: </p> <ul> <li> <p>US East (N. Virginia)</p> </li> <li> <p>US West (N. California)</p> </li> <li> <p> US West (Oregon)</p> </li> <li> <p> Asia Pacific (Singapore)</p> </li> <li> <p>Asia Pacific (Sydney)</p> </li> <li> <p>Asia Pacific (Tokyo)</p> </li> <li> <p>Europe (Ireland)</p> </li> <li> <p>South America (São Paulo)</p> </li> </ul> <p>For a list of all the Amazon S3 supported Regions and endpoints, see <a href=\"https://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region\">Regions and Endpoints</a> in the AWS General Reference.</p> </note> </li> </ul> <p> <b>Versioning</b> </p> <p>The ACL of an object is set at the object version level. By default, PUT sets the ACL of the current version of an object. To set the ACL of a different version, use the <code>versionId</code> subresource.</p> <p class=\"title\"> <b>Related Resources</b> </p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_CopyObject.html\">CopyObject</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html\">GetObject</a> </p> </li> </ul>",
"httpChecksumRequired":true
- },
+ },
"PutObjectLegalHold":{
"name":"PutObjectLegalHold",
"http":{
@@ -1005,17 +1005,17 @@
"documentation":"<p>Places an Object Retention configuration on an object. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/object-lock.html\">Locking Objects</a>. </p> <p>This action is not supported by Amazon S3 on Outposts.</p>",
"httpChecksumRequired":true
},
- "PutObjectTagging":{
- "name":"PutObjectTagging",
- "http":{
- "method":"PUT",
- "requestUri":"/{Bucket}/{Key+}?tagging"
- },
- "input":{"shape":"PutObjectTaggingRequest"},
- "output":{"shape":"PutObjectTaggingOutput"},
+ "PutObjectTagging":{
+ "name":"PutObjectTagging",
+ "http":{
+ "method":"PUT",
+ "requestUri":"/{Bucket}/{Key+}?tagging"
+ },
+ "input":{"shape":"PutObjectTaggingRequest"},
+ "output":{"shape":"PutObjectTaggingOutput"},
"documentation":"<p>Sets the supplied tag-set to an object that already exists in a bucket.</p> <p>A tag is a key-value pair. You can associate tags with an object by sending a PUT request against the tagging subresource that is associated with the object. You can retrieve tags by sending a GET request. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectTagging.html\">GetObjectTagging</a>.</p> <p>For tagging-related restrictions related to characters and encodings, see <a href=\"https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/allocation-tag-restrictions.html\">Tag Restrictions</a>. Note that Amazon S3 limits the maximum number of tags to 10 tags per object.</p> <p>To use this operation, you must have permission to perform the <code>s3:PutObjectTagging</code> action. By default, the bucket owner has this permission and can grant this permission to others.</p> <p>To put tags of any other version, use the <code>versionId</code> query parameter. You also need permission for the <code>s3:PutObjectVersionTagging</code> action.</p> <p>For information about the Amazon S3 object tagging feature, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/object-tagging.html\">Object Tagging</a>.</p> <p class=\"title\"> <b>Special Errors</b> </p> <ul> <li> <ul> <li> <p> <i>Code: InvalidTagError </i> </p> </li> <li> <p> <i>Cause: The tag provided was not a valid tag. This error can occur if the tag did not pass input validation. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/object-tagging.html\">Object Tagging</a>.</i> </p> </li> </ul> </li> <li> <ul> <li> <p> <i>Code: MalformedXMLError </i> </p> </li> <li> <p> <i>Cause: The XML provided does not match the schema.</i> </p> </li> </ul> </li> <li> <ul> <li> <p> <i>Code: OperationAbortedError </i> </p> </li> <li> <p> <i>Cause: A conflicting conditional action is currently in progress against this resource. Please try again.</i> </p> </li> </ul> </li> <li> <ul> <li> <p> <i>Code: InternalError</i> </p> </li> <li> <p> <i>Cause: The service was unable to apply the provided tag to the object.</i> </p> </li> </ul> </li> </ul> <p class=\"title\"> <b>Related Resources</b> </p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectTagging.html\">GetObjectTagging</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObjectTagging.html\">DeleteObjectTagging</a> </p> </li> </ul>",
"httpChecksumRequired":true
- },
+ },
"PutPublicAccessBlock":{
"name":"PutPublicAccessBlock",
"http":{
@@ -1026,55 +1026,55 @@
"documentation":"<p>Creates or modifies the <code>PublicAccessBlock</code> configuration for an Amazon S3 bucket. To use this operation, you must have the <code>s3:PutBucketPublicAccessBlock</code> permission. For more information about Amazon S3 permissions, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/using-with-s3-actions.html\">Specifying Permissions in a Policy</a>.</p> <important> <p>When Amazon S3 evaluates the <code>PublicAccessBlock</code> configuration for a bucket or an object, it checks the <code>PublicAccessBlock</code> configuration for both the bucket (or the bucket that contains the object) and the bucket owner's account. If the <code>PublicAccessBlock</code> configurations are different between the bucket and the account, Amazon S3 uses the most restrictive combination of the bucket-level and account-level settings.</p> </important> <p>For more information about when Amazon S3 considers a bucket or an object public, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/access-control-block-public-access.html#access-control-block-public-access-policy-status\">The Meaning of \"Public\"</a>.</p> <p class=\"title\"> <b>Related Resources</b> </p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetPublicAccessBlock.html\">GetPublicAccessBlock</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeletePublicAccessBlock.html\">DeletePublicAccessBlock</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketPolicyStatus.html\">GetBucketPolicyStatus</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/access-control-block-public-access.html\">Using Amazon S3 Block Public Access</a> </p> </li> </ul>",
"httpChecksumRequired":true
},
- "RestoreObject":{
- "name":"RestoreObject",
- "http":{
- "method":"POST",
- "requestUri":"/{Bucket}/{Key+}?restore"
- },
- "input":{"shape":"RestoreObjectRequest"},
- "output":{"shape":"RestoreObjectOutput"},
- "errors":[
- {"shape":"ObjectAlreadyInActiveTierError"}
- ],
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectRestore.html",
+ "RestoreObject":{
+ "name":"RestoreObject",
+ "http":{
+ "method":"POST",
+ "requestUri":"/{Bucket}/{Key+}?restore"
+ },
+ "input":{"shape":"RestoreObjectRequest"},
+ "output":{"shape":"RestoreObjectOutput"},
+ "errors":[
+ {"shape":"ObjectAlreadyInActiveTierError"}
+ ],
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectRestore.html",
"documentation":"<p>Restores an archived copy of an object back into Amazon S3</p> <p>This action is not supported by Amazon S3 on Outposts.</p> <p>This action performs the following types of requests: </p> <ul> <li> <p> <code>select</code> - Perform a select query on an archived object</p> </li> <li> <p> <code>restore an archive</code> - Restore an archived object</p> </li> </ul> <p>To use this operation, you must have permissions to perform the <code>s3:RestoreObject</code> action. The bucket owner has this permission by default and can grant this permission to others. For more information about permissions, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-with-s3-actions.html#using-with-s3-actions-related-to-bucket-subresources\">Permissions Related to Bucket Subresource Operations</a> and <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-access-control.html\">Managing Access Permissions to Your Amazon S3 Resources</a> in the <i>Amazon S3 User Guide</i>.</p> <p> <b>Querying Archives with Select Requests</b> </p> <p>You use a select type of request to perform SQL queries on archived objects. The archived objects that are being queried by the select request must be formatted as uncompressed comma-separated values (CSV) files. You can run queries and custom analytics on your archived data without having to restore your data to a hotter Amazon S3 tier. For an overview about select requests, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/querying-glacier-archives.html\">Querying Archived Objects</a> in the <i>Amazon S3 User Guide</i>.</p> <p>When making a select request, do the following:</p> <ul> <li> <p>Define an output location for the select query's output. This must be an Amazon S3 bucket in the same AWS Region as the bucket that contains the archive object that is being queried. The AWS account that initiates the job must have permissions to write to the S3 bucket. You can specify the storage class and encryption for the output objects stored in the bucket. For more information about output, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/querying-glacier-archives.html\">Querying Archived Objects</a> in the <i>Amazon S3 User Guide</i>.</p> <p>For more information about the <code>S3</code> structure in the request body, see the following:</p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html\">PutObject</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/S3_ACLs_UsingACLs.html\">Managing Access with ACLs</a> in the <i>Amazon S3 User Guide</i> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/serv-side-encryption.html\">Protecting Data Using Server-Side Encryption</a> in the <i>Amazon S3 User Guide</i> </p> </li> </ul> </li> <li> <p>Define the SQL expression for the <code>SELECT</code> type of restoration for your query in the request body's <code>SelectParameters</code> structure. You can use expressions like the following examples.</p> <ul> <li> <p>The following expression returns all records from the specified object.</p> <p> <code>SELECT * FROM Object</code> </p> </li> <li> <p>Assuming that you are not using any headers for data stored in the object, you can specify columns with positional headers.</p> <p> <code>SELECT s._1, s._2 FROM Object s WHERE s._3 &gt; 100</code> </p> </li> <li> <p>If you have headers and you set the <code>fileHeaderInfo</code> in the <code>CSV</code> structure in the request body to <code>USE</code>, you can specify headers in the query. (If you set the <code>fileHeaderInfo</code> field to <code>IGNORE</code>, the first row is skipped for the query.) You cannot mix ordinal positions with header column names. </p> <p> <code>SELECT s.Id, s.FirstName, s.SSN FROM S3Object s</code> </p> </li> </ul> </li> </ul> <p>For more information about using SQL with S3 Glacier Select restore, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/s3-glacier-select-sql-reference.html\">SQL Reference for Amazon S3 Select and S3 Glacier Select</a> in the <i>Amazon S3 User Guide</i>. </p> <p>When making a select request, you can also do the following:</p> <ul> <li> <p>To expedite your queries, specify the <code>Expedited</code> tier. For more information about tiers, see \"Restoring Archives,\" later in this topic.</p> </li> <li> <p>Specify details about the data serialization format of both the input object that is being queried and the serialization of the CSV-encoded query results.</p> </li> </ul> <p>The following are additional important facts about the select feature:</p> <ul> <li> <p>The output results are new Amazon S3 objects. Unlike archive retrievals, they are stored until explicitly deleted-manually or through a lifecycle policy.</p> </li> <li> <p>You can issue more than one select request on the same Amazon S3 object. Amazon S3 doesn't deduplicate requests, so avoid issuing duplicate requests.</p> </li> <li> <p> Amazon S3 accepts a select request even if the object has already been restored. A select request doesn’t return error response <code>409</code>.</p> </li> </ul> <p> <b>Restoring objects</b> </p> <p>Objects that you archive to the S3 Glacier or S3 Glacier Deep Archive storage class, and S3 Intelligent-Tiering Archive or S3 Intelligent-Tiering Deep Archive tiers are not accessible in real time. For objects in Archive Access or Deep Archive Access tiers you must first initiate a restore request, and then wait until the object is moved into the Frequent Access tier. For objects in S3 Glacier or S3 Glacier Deep Archive storage classes you must first initiate a restore request, and then wait until a temporary copy of the object is available. To access an archived object, you must restore the object for the duration (number of days) that you specify.</p> <p>To restore a specific object version, you can provide a version ID. If you don't provide a version ID, Amazon S3 restores the current version.</p> <p>When restoring an archived object (or using a select request), you can specify one of the following data access tier options in the <code>Tier</code> element of the request body: </p> <ul> <li> <p> <b> <code>Expedited</code> </b> - Expedited retrievals allow you to quickly access your data stored in the S3 Glacier storage class or S3 Intelligent-Tiering Archive tier when occasional urgent requests for a subset of archives are required. For all but the largest archived objects (250 MB+), data accessed using Expedited retrievals is typically made available within 1–5 minutes. Provisioned capacity ensures that retrieval capacity for Expedited retrievals is available when you need it. Expedited retrievals and provisioned capacity are not available for objects stored in the S3 Glacier Deep Archive storage class or S3 Intelligent-Tiering Deep Archive tier.</p> </li> <li> <p> <b> <code>Standard</code> </b> - Standard retrievals allow you to access any of your archived objects within several hours. This is the default option for retrieval requests that do not specify the retrieval option. Standard retrievals typically finish within 3–5 hours for objects stored in the S3 Glacier storage class or S3 Intelligent-Tiering Archive tier. They typically finish within 12 hours for objects stored in the S3 Glacier Deep Archive storage class or S3 Intelligent-Tiering Deep Archive tier. Standard retrievals are free for objects stored in S3 Intelligent-Tiering.</p> </li> <li> <p> <b> <code>Bulk</code> </b> - Bulk retrievals are the lowest-cost retrieval option in S3 Glacier, enabling you to retrieve large amounts, even petabytes, of data inexpensively. Bulk retrievals typically finish within 5–12 hours for objects stored in the S3 Glacier storage class or S3 Intelligent-Tiering Archive tier. They typically finish within 48 hours for objects stored in the S3 Glacier Deep Archive storage class or S3 Intelligent-Tiering Deep Archive tier. Bulk retrievals are free for objects stored in S3 Intelligent-Tiering.</p> </li> </ul> <p>For more information about archive retrieval options and provisioned capacity for <code>Expedited</code> data access, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/restoring-objects.html\">Restoring Archived Objects</a> in the <i>Amazon S3 User Guide</i>. </p> <p>You can use Amazon S3 restore speed upgrade to change the restore speed to a faster speed while it is in progress. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/restoring-objects.html#restoring-objects-upgrade-tier.title.html\"> Upgrading the speed of an in-progress restore</a> in the <i>Amazon S3 User Guide</i>. </p> <p>To get the status of object restoration, you can send a <code>HEAD</code> request. Operations return the <code>x-amz-restore</code> header, which provides information about the restoration status, in the response. You can use Amazon S3 event notifications to notify you when a restore is initiated or completed. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/NotificationHowTo.html\">Configuring Amazon S3 Event Notifications</a> in the <i>Amazon S3 User Guide</i>.</p> <p>After restoring an archived object, you can update the restoration period by reissuing the request with a new period. Amazon S3 updates the restoration period relative to the current time and charges only for the request-there are no data transfer charges. You cannot update the restoration period when Amazon S3 is actively processing your current restore request for the object.</p> <p>If your bucket has a lifecycle configuration with a rule that includes an expiration action, the object expiration overrides the life span that you specify in a restore request. For example, if you restore an object copy for 10 days, but the object is scheduled to expire in 3 days, Amazon S3 deletes the object in 3 days. For more information about lifecycle configuration, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketLifecycleConfiguration.html\">PutBucketLifecycleConfiguration</a> and <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/object-lifecycle-mgmt.html\">Object Lifecycle Management</a> in <i>Amazon S3 User Guide</i>.</p> <p> <b>Responses</b> </p> <p>A successful action returns either the <code>200 OK</code> or <code>202 Accepted</code> status code. </p> <ul> <li> <p>If the object is not previously restored, then Amazon S3 returns <code>202 Accepted</code> in the response. </p> </li> <li> <p>If the object is previously restored, Amazon S3 returns <code>200 OK</code> in the response. </p> </li> </ul> <p class=\"title\"> <b>Special Errors</b> </p> <ul> <li> <ul> <li> <p> <i>Code: RestoreAlreadyInProgress</i> </p> </li> <li> <p> <i>Cause: Object restore is already in progress. (This error does not apply to SELECT type requests.)</i> </p> </li> <li> <p> <i>HTTP Status Code: 409 Conflict</i> </p> </li> <li> <p> <i>SOAP Fault Code Prefix: Client</i> </p> </li> </ul> </li> <li> <ul> <li> <p> <i>Code: GlacierExpeditedRetrievalNotAvailable</i> </p> </li> <li> <p> <i>Cause: expedited retrievals are currently not available. Try again later. (Returned if there is insufficient capacity to process the Expedited request. This error applies only to Expedited retrievals and not to S3 Standard or Bulk retrievals.)</i> </p> </li> <li> <p> <i>HTTP Status Code: 503</i> </p> </li> <li> <p> <i>SOAP Fault Code Prefix: N/A</i> </p> </li> </ul> </li> </ul> <p class=\"title\"> <b>Related Resources</b> </p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketLifecycleConfiguration.html\">PutBucketLifecycleConfiguration</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketNotificationConfiguration.html\">GetBucketNotificationConfiguration</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/s3-glacier-select-sql-reference.html\">SQL Reference for Amazon S3 Select and S3 Glacier Select </a> in the <i>Amazon S3 User Guide</i> </p> </li> </ul>",
- "alias":"PostObjectRestore"
- },
- "SelectObjectContent":{
- "name":"SelectObjectContent",
- "http":{
- "method":"POST",
- "requestUri":"/{Bucket}/{Key+}?select&select-type=2"
- },
- "input":{
- "shape":"SelectObjectContentRequest",
- "locationName":"SelectObjectContentRequest",
- "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
- },
- "output":{"shape":"SelectObjectContentOutput"},
+ "alias":"PostObjectRestore"
+ },
+ "SelectObjectContent":{
+ "name":"SelectObjectContent",
+ "http":{
+ "method":"POST",
+ "requestUri":"/{Bucket}/{Key+}?select&select-type=2"
+ },
+ "input":{
+ "shape":"SelectObjectContentRequest",
+ "locationName":"SelectObjectContentRequest",
+ "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
+ },
+ "output":{"shape":"SelectObjectContentOutput"},
"documentation":"<p>This action filters the contents of an Amazon S3 object based on a simple structured query language (SQL) statement. In the request, along with the SQL expression, you must also specify a data serialization format (JSON, CSV, or Apache Parquet) of the object. Amazon S3 uses this format to parse object data into records, and returns only records that match the specified SQL expression. You must also specify the data serialization format for the response.</p> <p>This action is not supported by Amazon S3 on Outposts.</p> <p>For more information about Amazon S3 Select, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/selecting-content-from-objects.html\">Selecting Content from Objects</a> in the <i>Amazon S3 User Guide</i>.</p> <p>For more information about using SQL with Amazon S3 Select, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/s3-glacier-select-sql-reference.html\"> SQL Reference for Amazon S3 Select and S3 Glacier Select</a> in the <i>Amazon S3 User Guide</i>.</p> <p/> <p> <b>Permissions</b> </p> <p>You must have <code>s3:GetObject</code> permission for this operation. Amazon S3 Select does not support anonymous access. For more information about permissions, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/using-with-s3-actions.html\">Specifying Permissions in a Policy</a> in the <i>Amazon S3 User Guide</i>.</p> <p/> <p> <i>Object Data Formats</i> </p> <p>You can use Amazon S3 Select to query objects that have the following format properties:</p> <ul> <li> <p> <i>CSV, JSON, and Parquet</i> - Objects must be in CSV, JSON, or Parquet format.</p> </li> <li> <p> <i>UTF-8</i> - UTF-8 is the only encoding type Amazon S3 Select supports.</p> </li> <li> <p> <i>GZIP or BZIP2</i> - CSV and JSON files can be compressed using GZIP or BZIP2. GZIP and BZIP2 are the only compression formats that Amazon S3 Select supports for CSV and JSON files. Amazon S3 Select supports columnar compression for Parquet using GZIP or Snappy. Amazon S3 Select does not support whole-object compression for Parquet objects.</p> </li> <li> <p> <i>Server-side encryption</i> - Amazon S3 Select supports querying objects that are protected with server-side encryption.</p> <p>For objects that are encrypted with customer-provided encryption keys (SSE-C), you must use HTTPS, and you must use the headers that are documented in the <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html\">GetObject</a>. For more information about SSE-C, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html\">Server-Side Encryption (Using Customer-Provided Encryption Keys)</a> in the <i>Amazon S3 User Guide</i>.</p> <p>For objects that are encrypted with Amazon S3 managed encryption keys (SSE-S3) and customer master keys (CMKs) stored in AWS Key Management Service (SSE-KMS), server-side encryption is handled transparently, so you don't need to specify anything. For more information about server-side encryption, including SSE-S3 and SSE-KMS, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/serv-side-encryption.html\">Protecting Data Using Server-Side Encryption</a> in the <i>Amazon S3 User Guide</i>.</p> </li> </ul> <p> <b>Working with the Response Body</b> </p> <p>Given the response size is unknown, Amazon S3 Select streams the response as a series of messages and includes a <code>Transfer-Encoding</code> header with <code>chunked</code> as its value in the response. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/RESTSelectObjectAppendix.html\">Appendix: SelectObjectContent Response</a> .</p> <p/> <p> <b>GetObject Support</b> </p> <p>The <code>SelectObjectContent</code> action does not support the following <code>GetObject</code> functionality. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html\">GetObject</a>.</p> <ul> <li> <p> <code>Range</code>: Although you can specify a scan range for an Amazon S3 Select request (see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_SelectObjectContent.html#AmazonS3-SelectObjectContent-request-ScanRange\">SelectObjectContentRequest - ScanRange</a> in the request parameters), you cannot specify the range of bytes of an object to return. </p> </li> <li> <p>GLACIER, DEEP_ARCHIVE and REDUCED_REDUNDANCY storage classes: You cannot specify the GLACIER, DEEP_ARCHIVE, or <code>REDUCED_REDUNDANCY</code> storage classes. For more information, about storage classes see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html#storage-class-intro\">Storage Classes</a> in the <i>Amazon S3 User Guide</i>.</p> </li> </ul> <p/> <p> <b>Special Errors</b> </p> <p>For a list of special errors for this operation, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html#SelectObjectContentErrorCodeList\">List of SELECT Object Content Error Codes</a> </p> <p class=\"title\"> <b>Related Resources</b> </p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html\">GetObject</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketLifecycleConfiguration.html\">GetBucketLifecycleConfiguration</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketLifecycleConfiguration.html\">PutBucketLifecycleConfiguration</a> </p> </li> </ul>"
- },
- "UploadPart":{
- "name":"UploadPart",
- "http":{
- "method":"PUT",
- "requestUri":"/{Bucket}/{Key+}"
- },
- "input":{"shape":"UploadPartRequest"},
- "output":{"shape":"UploadPartOutput"},
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/mpUploadUploadPart.html",
+ },
+ "UploadPart":{
+ "name":"UploadPart",
+ "http":{
+ "method":"PUT",
+ "requestUri":"/{Bucket}/{Key+}"
+ },
+ "input":{"shape":"UploadPartRequest"},
+ "output":{"shape":"UploadPartOutput"},
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/mpUploadUploadPart.html",
"documentation":"<p>Uploads a part in a multipart upload.</p> <note> <p>In this operation, you provide part data in your request. However, you have an option to specify your existing Amazon S3 object as a data source for the part you are uploading. To upload a part from an existing object, you use the <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPartCopy.html\">UploadPartCopy</a> operation. </p> </note> <p>You must initiate a multipart upload (see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateMultipartUpload.html\">CreateMultipartUpload</a>) before you can upload any part. In response to your initiate request, Amazon S3 returns an upload ID, a unique identifier, that you must include in your upload part request.</p> <p>Part numbers can be any number from 1 to 10,000, inclusive. A part number uniquely identifies a part and also defines its position within the object being created. If you upload a new part using the same part number that was used with a previous part, the previously uploaded part is overwritten. Each part must be at least 5 MB in size, except the last part. There is no size limit on the last part of your multipart upload.</p> <p>To ensure that data is not corrupted when traversing the network, specify the <code>Content-MD5</code> header in the upload part request. Amazon S3 checks the part data against the provided MD5 value. If they do not match, Amazon S3 returns an error. </p> <p>If the upload request is signed with Signature Version 4, then AWS S3 uses the <code>x-amz-content-sha256</code> header as a checksum instead of <code>Content-MD5</code>. For more information see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-auth-using-authorization-header.html\">Authenticating Requests: Using the Authorization Header (AWS Signature Version 4)</a>. </p> <p> <b>Note:</b> After you initiate multipart upload and upload one or more parts, you must either complete or abort multipart upload in order to stop getting charged for storage of the uploaded parts. Only after you either complete or abort multipart upload, Amazon S3 frees up the parts storage and stops charging you for the parts storage.</p> <p>For more information on multipart uploads, go to <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/mpuoverview.html\">Multipart Upload Overview</a> in the <i>Amazon S3 User Guide </i>.</p> <p>For information on the permissions required to use the multipart upload API, go to <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html\">Multipart Upload and Permissions</a> in the <i>Amazon S3 User Guide</i>.</p> <p>You can optionally request server-side encryption where Amazon S3 encrypts your data as it writes it to disks in its data centers and decrypts it for you when you access it. You have the option of providing your own encryption key, or you can use the AWS managed encryption keys. If you choose to provide your own encryption key, the request headers you provide in the request must match the headers you used in the request to initiate the upload by using <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateMultipartUpload.html\">CreateMultipartUpload</a>. For more information, go to <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingServerSideEncryption.html\">Using Server-Side Encryption</a> in the <i>Amazon S3 User Guide</i>.</p> <p>Server-side encryption is supported by the S3 Multipart Upload actions. Unless you are using a customer-provided encryption key, you don't need to specify the encryption parameters in each UploadPart request. Instead, you only need to specify the server-side encryption parameters in the initial Initiate Multipart request. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateMultipartUpload.html\">CreateMultipartUpload</a>.</p> <p>If you requested server-side encryption using a customer-provided encryption key in your initiate multipart upload request, you must provide identical encryption information in each part upload using the following headers.</p> <ul> <li> <p>x-amz-server-side-encryption-customer-algorithm</p> </li> <li> <p>x-amz-server-side-encryption-customer-key</p> </li> <li> <p>x-amz-server-side-encryption-customer-key-MD5</p> </li> </ul> <p class=\"title\"> <b>Special Errors</b> </p> <ul> <li> <ul> <li> <p> <i>Code: NoSuchUpload</i> </p> </li> <li> <p> <i>Cause: The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed.</i> </p> </li> <li> <p> <i> HTTP Status Code: 404 Not Found </i> </p> </li> <li> <p> <i>SOAP Fault Code Prefix: Client</i> </p> </li> </ul> </li> </ul> <p class=\"title\"> <b>Related Resources</b> </p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateMultipartUpload.html\">CreateMultipartUpload</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_CompleteMultipartUpload.html\">CompleteMultipartUpload</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_AbortMultipartUpload.html\">AbortMultipartUpload</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListParts.html\">ListParts</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListMultipartUploads.html\">ListMultipartUploads</a> </p> </li> </ul>"
- },
- "UploadPartCopy":{
- "name":"UploadPartCopy",
- "http":{
- "method":"PUT",
- "requestUri":"/{Bucket}/{Key+}"
- },
- "input":{"shape":"UploadPartCopyRequest"},
- "output":{"shape":"UploadPartCopyOutput"},
- "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/mpUploadUploadPartCopy.html",
+ },
+ "UploadPartCopy":{
+ "name":"UploadPartCopy",
+ "http":{
+ "method":"PUT",
+ "requestUri":"/{Bucket}/{Key+}"
+ },
+ "input":{"shape":"UploadPartCopyRequest"},
+ "output":{"shape":"UploadPartCopyOutput"},
+ "documentationUrl":"http://docs.amazonwebservices.com/AmazonS3/latest/API/mpUploadUploadPartCopy.html",
"documentation":"<p>Uploads a part by copying data from an existing object as data source. You specify the data source by adding the request header <code>x-amz-copy-source</code> in your request and a byte range by adding the request header <code>x-amz-copy-source-range</code> in your request. </p> <p>The minimum allowable part size for a multipart upload is 5 MB. For more information about multipart upload limits, go to <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/qfacts.html\">Quick Facts</a> in the <i>Amazon S3 User Guide</i>. </p> <note> <p>Instead of using an existing object as part data, you might use the <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPart.html\">UploadPart</a> action and provide data in your request.</p> </note> <p>You must initiate a multipart upload before you can upload any part. In response to your initiate request. Amazon S3 returns a unique identifier, the upload ID, that you must include in your upload part request.</p> <p>For more information about using the <code>UploadPartCopy</code> operation, see the following:</p> <ul> <li> <p>For conceptual information about multipart uploads, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/uploadobjusingmpu.html\">Uploading Objects Using Multipart Upload</a> in the <i>Amazon S3 User Guide</i>.</p> </li> <li> <p>For information about permissions required to use the multipart upload API, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/mpuAndPermissions.html\">Multipart Upload and Permissions</a> in the <i>Amazon S3 User Guide</i>.</p> </li> <li> <p>For information about copying objects using a single atomic action vs. the multipart upload, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectOperations.html\">Operations on Objects</a> in the <i>Amazon S3 User Guide</i>.</p> </li> <li> <p>For information about using server-side encryption with customer-provided encryption keys with the UploadPartCopy operation, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_CopyObject.html\">CopyObject</a> and <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPart.html\">UploadPart</a>.</p> </li> </ul> <p>Note the following additional considerations about the request headers <code>x-amz-copy-source-if-match</code>, <code>x-amz-copy-source-if-none-match</code>, <code>x-amz-copy-source-if-unmodified-since</code>, and <code>x-amz-copy-source-if-modified-since</code>:</p> <p> </p> <ul> <li> <p> <b>Consideration 1</b> - If both of the <code>x-amz-copy-source-if-match</code> and <code>x-amz-copy-source-if-unmodified-since</code> headers are present in the request as follows:</p> <p> <code>x-amz-copy-source-if-match</code> condition evaluates to <code>true</code>, and;</p> <p> <code>x-amz-copy-source-if-unmodified-since</code> condition evaluates to <code>false</code>;</p> <p>Amazon S3 returns <code>200 OK</code> and copies the data. </p> </li> <li> <p> <b>Consideration 2</b> - If both of the <code>x-amz-copy-source-if-none-match</code> and <code>x-amz-copy-source-if-modified-since</code> headers are present in the request as follows:</p> <p> <code>x-amz-copy-source-if-none-match</code> condition evaluates to <code>false</code>, and;</p> <p> <code>x-amz-copy-source-if-modified-since</code> condition evaluates to <code>true</code>;</p> <p>Amazon S3 returns <code>412 Precondition Failed</code> response code. </p> </li> </ul> <p> <b>Versioning</b> </p> <p>If your bucket has versioning enabled, you could have multiple versions of the same object. By default, <code>x-amz-copy-source</code> identifies the current version of the object to copy. If the current version is a delete marker and you don't specify a versionId in the <code>x-amz-copy-source</code>, Amazon S3 returns a 404 error, because the object does not exist. If you specify versionId in the <code>x-amz-copy-source</code> and the versionId is a delete marker, Amazon S3 returns an HTTP 400 error, because you are not allowed to specify a delete marker as a version for the <code>x-amz-copy-source</code>. </p> <p>You can optionally specify a specific version of the source object to copy by adding the <code>versionId</code> subresource as shown in the following example:</p> <p> <code>x-amz-copy-source: /bucket/object?versionId=version id</code> </p> <p class=\"title\"> <b>Special Errors</b> </p> <ul> <li> <ul> <li> <p> <i>Code: NoSuchUpload</i> </p> </li> <li> <p> <i>Cause: The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed.</i> </p> </li> <li> <p> <i>HTTP Status Code: 404 Not Found</i> </p> </li> </ul> </li> <li> <ul> <li> <p> <i>Code: InvalidRequest</i> </p> </li> <li> <p> <i>Cause: The specified copy source is not supported as a byte-range copy source.</i> </p> </li> <li> <p> <i>HTTP Status Code: 400 Bad Request</i> </p> </li> </ul> </li> </ul> <p class=\"title\"> <b>Related Resources</b> </p> <ul> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateMultipartUpload.html\">CreateMultipartUpload</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPart.html\">UploadPart</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_CompleteMultipartUpload.html\">CompleteMultipartUpload</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_AbortMultipartUpload.html\">AbortMultipartUpload</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListParts.html\">ListParts</a> </p> </li> <li> <p> <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListMultipartUploads.html\">ListMultipartUploads</a> </p> </li> </ul>"
},
"WriteGetObjectResponse":{
@@ -1089,230 +1089,230 @@
"endpoint":{
"hostPrefix":"{RequestRoute}."
}
- }
- },
- "shapes":{
- "AbortDate":{"type":"timestamp"},
- "AbortIncompleteMultipartUpload":{
- "type":"structure",
- "members":{
- "DaysAfterInitiation":{
- "shape":"DaysAfterInitiation",
+ }
+ },
+ "shapes":{
+ "AbortDate":{"type":"timestamp"},
+ "AbortIncompleteMultipartUpload":{
+ "type":"structure",
+ "members":{
+ "DaysAfterInitiation":{
+ "shape":"DaysAfterInitiation",
"documentation":"<p>Specifies the number of days after which Amazon S3 aborts an incomplete multipart upload.</p>"
- }
- },
+ }
+ },
"documentation":"<p>Specifies the days since the initiation of an incomplete multipart upload that Amazon S3 will wait before permanently removing all parts of the upload. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/mpuoverview.html#mpu-abort-incomplete-mpu-lifecycle-config\"> Aborting Incomplete Multipart Uploads Using a Bucket Lifecycle Policy</a> in the <i>Amazon S3 User Guide</i>.</p>"
- },
- "AbortMultipartUploadOutput":{
- "type":"structure",
- "members":{
- "RequestCharged":{
- "shape":"RequestCharged",
- "location":"header",
- "locationName":"x-amz-request-charged"
- }
- }
- },
- "AbortMultipartUploadRequest":{
- "type":"structure",
- "required":[
- "Bucket",
- "Key",
- "UploadId"
- ],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ },
+ "AbortMultipartUploadOutput":{
+ "type":"structure",
+ "members":{
+ "RequestCharged":{
+ "shape":"RequestCharged",
+ "location":"header",
+ "locationName":"x-amz-request-charged"
+ }
+ }
+ },
+ "AbortMultipartUploadRequest":{
+ "type":"structure",
+ "required":[
+ "Bucket",
+ "Key",
+ "UploadId"
+ ],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The bucket name to which the upload was taking place. </p> <p>When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.s3-accesspoint.<i>Region</i>.amazonaws.com. When using this action with an access point through the AWS SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\">Using access points</a> in the <i>Amazon S3 User Guide</i>.</p> <p>When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.<i>outpostID</i>.s3-outposts.<i>Region</i>.amazonaws.com. When using this action using S3 on Outposts through the AWS SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html\">Using S3 on Outposts</a> in the <i>Amazon S3 User Guide</i>.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "Key":{
- "shape":"ObjectKey",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "Key":{
+ "shape":"ObjectKey",
"documentation":"<p>Key of the object for which the multipart upload was initiated.</p>",
- "location":"uri",
- "locationName":"Key"
- },
- "UploadId":{
- "shape":"MultipartUploadId",
+ "location":"uri",
+ "locationName":"Key"
+ },
+ "UploadId":{
+ "shape":"MultipartUploadId",
"documentation":"<p>Upload ID that identifies the multipart upload.</p>",
- "location":"querystring",
- "locationName":"uploadId"
- },
- "RequestPayer":{
- "shape":"RequestPayer",
- "location":"header",
- "locationName":"x-amz-request-payer"
+ "location":"querystring",
+ "locationName":"uploadId"
+ },
+ "RequestPayer":{
+ "shape":"RequestPayer",
+ "location":"header",
+ "locationName":"x-amz-request-payer"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
- "AbortRuleId":{"type":"string"},
- "AccelerateConfiguration":{
- "type":"structure",
- "members":{
- "Status":{
- "shape":"BucketAccelerateStatus",
+ }
+ }
+ },
+ "AbortRuleId":{"type":"string"},
+ "AccelerateConfiguration":{
+ "type":"structure",
+ "members":{
+ "Status":{
+ "shape":"BucketAccelerateStatus",
"documentation":"<p>Specifies the transfer acceleration status of the bucket.</p>"
- }
+ }
},
"documentation":"<p>Configures the transfer acceleration state for an Amazon S3 bucket. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/transfer-acceleration.html\">Amazon S3 Transfer Acceleration</a> in the <i>Amazon S3 User Guide</i>.</p>"
- },
- "AcceptRanges":{"type":"string"},
- "AccessControlPolicy":{
- "type":"structure",
- "members":{
- "Grants":{
- "shape":"Grants",
+ },
+ "AcceptRanges":{"type":"string"},
+ "AccessControlPolicy":{
+ "type":"structure",
+ "members":{
+ "Grants":{
+ "shape":"Grants",
"documentation":"<p>A list of grants.</p>",
- "locationName":"AccessControlList"
- },
+ "locationName":"AccessControlList"
+ },
"Owner":{
"shape":"Owner",
"documentation":"<p>Container for the bucket owner's display name and ID.</p>"
}
},
"documentation":"<p>Contains the elements that set the ACL permissions for an object per grantee.</p>"
- },
- "AccessControlTranslation":{
- "type":"structure",
- "required":["Owner"],
- "members":{
- "Owner":{
- "shape":"OwnerOverride",
+ },
+ "AccessControlTranslation":{
+ "type":"structure",
+ "required":["Owner"],
+ "members":{
+ "Owner":{
+ "shape":"OwnerOverride",
"documentation":"<p>Specifies the replica ownership. For default and valid values, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketPUTreplication.html\">PUT bucket replication</a> in the <i>Amazon S3 API Reference</i>.</p>"
- }
- },
+ }
+ },
"documentation":"<p>A container for information about access control for replicas.</p>"
- },
- "AccountId":{"type":"string"},
- "AllowQuotedRecordDelimiter":{"type":"boolean"},
- "AllowedHeader":{"type":"string"},
- "AllowedHeaders":{
- "type":"list",
- "member":{"shape":"AllowedHeader"},
- "flattened":true
- },
- "AllowedMethod":{"type":"string"},
- "AllowedMethods":{
- "type":"list",
- "member":{"shape":"AllowedMethod"},
- "flattened":true
- },
- "AllowedOrigin":{"type":"string"},
- "AllowedOrigins":{
- "type":"list",
- "member":{"shape":"AllowedOrigin"},
- "flattened":true
- },
- "AnalyticsAndOperator":{
- "type":"structure",
- "members":{
- "Prefix":{
- "shape":"Prefix",
+ },
+ "AccountId":{"type":"string"},
+ "AllowQuotedRecordDelimiter":{"type":"boolean"},
+ "AllowedHeader":{"type":"string"},
+ "AllowedHeaders":{
+ "type":"list",
+ "member":{"shape":"AllowedHeader"},
+ "flattened":true
+ },
+ "AllowedMethod":{"type":"string"},
+ "AllowedMethods":{
+ "type":"list",
+ "member":{"shape":"AllowedMethod"},
+ "flattened":true
+ },
+ "AllowedOrigin":{"type":"string"},
+ "AllowedOrigins":{
+ "type":"list",
+ "member":{"shape":"AllowedOrigin"},
+ "flattened":true
+ },
+ "AnalyticsAndOperator":{
+ "type":"structure",
+ "members":{
+ "Prefix":{
+ "shape":"Prefix",
"documentation":"<p>The prefix to use when evaluating an AND predicate: The prefix that an object must have to be included in the metrics results.</p>"
- },
- "Tags":{
- "shape":"TagSet",
+ },
+ "Tags":{
+ "shape":"TagSet",
"documentation":"<p>The list of tags to use when evaluating an AND predicate.</p>",
- "flattened":true,
- "locationName":"Tag"
- }
+ "flattened":true,
+ "locationName":"Tag"
+ }
},
"documentation":"<p>A conjunction (logical AND) of predicates, which is used in evaluating a metrics filter. The operator must have at least two predicates in any combination, and an object must match all of the predicates for the filter to apply.</p>"
- },
- "AnalyticsConfiguration":{
- "type":"structure",
- "required":[
- "Id",
- "StorageClassAnalysis"
- ],
- "members":{
- "Id":{
- "shape":"AnalyticsId",
+ },
+ "AnalyticsConfiguration":{
+ "type":"structure",
+ "required":[
+ "Id",
+ "StorageClassAnalysis"
+ ],
+ "members":{
+ "Id":{
+ "shape":"AnalyticsId",
"documentation":"<p>The ID that identifies the analytics configuration.</p>"
- },
- "Filter":{
- "shape":"AnalyticsFilter",
+ },
+ "Filter":{
+ "shape":"AnalyticsFilter",
"documentation":"<p>The filter used to describe a set of objects for analyses. A filter must have exactly one prefix, one tag, or one conjunction (AnalyticsAndOperator). If no filter is provided, all objects will be considered in any analysis.</p>"
- },
- "StorageClassAnalysis":{
- "shape":"StorageClassAnalysis",
+ },
+ "StorageClassAnalysis":{
+ "shape":"StorageClassAnalysis",
"documentation":"<p> Contains data related to access patterns to be collected and made available to analyze the tradeoffs between different storage classes. </p>"
- }
+ }
},
"documentation":"<p>Specifies the configuration and any analyses for the analytics filter of an Amazon S3 bucket.</p>"
- },
- "AnalyticsConfigurationList":{
- "type":"list",
- "member":{"shape":"AnalyticsConfiguration"},
- "flattened":true
- },
- "AnalyticsExportDestination":{
- "type":"structure",
- "required":["S3BucketDestination"],
- "members":{
- "S3BucketDestination":{
- "shape":"AnalyticsS3BucketDestination",
+ },
+ "AnalyticsConfigurationList":{
+ "type":"list",
+ "member":{"shape":"AnalyticsConfiguration"},
+ "flattened":true
+ },
+ "AnalyticsExportDestination":{
+ "type":"structure",
+ "required":["S3BucketDestination"],
+ "members":{
+ "S3BucketDestination":{
+ "shape":"AnalyticsS3BucketDestination",
"documentation":"<p>A destination signifying output to an S3 bucket.</p>"
- }
+ }
},
"documentation":"<p>Where to publish the analytics results.</p>"
- },
- "AnalyticsFilter":{
- "type":"structure",
- "members":{
- "Prefix":{
- "shape":"Prefix",
+ },
+ "AnalyticsFilter":{
+ "type":"structure",
+ "members":{
+ "Prefix":{
+ "shape":"Prefix",
"documentation":"<p>The prefix to use when evaluating an analytics filter.</p>"
- },
- "Tag":{
- "shape":"Tag",
+ },
+ "Tag":{
+ "shape":"Tag",
"documentation":"<p>The tag to use when evaluating an analytics filter.</p>"
- },
- "And":{
- "shape":"AnalyticsAndOperator",
+ },
+ "And":{
+ "shape":"AnalyticsAndOperator",
"documentation":"<p>A conjunction (logical AND) of predicates, which is used in evaluating an analytics filter. The operator must have at least two predicates.</p>"
- }
+ }
},
"documentation":"<p>The filter used to describe a set of objects for analyses. A filter must have exactly one prefix, one tag, or one conjunction (AnalyticsAndOperator). If no filter is provided, all objects will be considered in any analysis.</p>"
- },
- "AnalyticsId":{"type":"string"},
- "AnalyticsS3BucketDestination":{
- "type":"structure",
- "required":[
- "Format",
- "Bucket"
- ],
- "members":{
- "Format":{
- "shape":"AnalyticsS3ExportFileFormat",
+ },
+ "AnalyticsId":{"type":"string"},
+ "AnalyticsS3BucketDestination":{
+ "type":"structure",
+ "required":[
+ "Format",
+ "Bucket"
+ ],
+ "members":{
+ "Format":{
+ "shape":"AnalyticsS3ExportFileFormat",
"documentation":"<p>Specifies the file format used when exporting data to Amazon S3.</p>"
- },
- "BucketAccountId":{
- "shape":"AccountId",
+ },
+ "BucketAccountId":{
+ "shape":"AccountId",
"documentation":"<p>The account ID that owns the destination S3 bucket. If no account ID is provided, the owner is not validated before exporting data.</p> <note> <p> Although this value is optional, we strongly recommend that you set it to help prevent problems if the destination bucket ownership changes. </p> </note>"
- },
- "Bucket":{
- "shape":"BucketName",
+ },
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The Amazon Resource Name (ARN) of the bucket to which data is exported.</p>"
- },
- "Prefix":{
- "shape":"Prefix",
+ },
+ "Prefix":{
+ "shape":"Prefix",
"documentation":"<p>The prefix to use when exporting data. The prefix is prepended to all results.</p>"
- }
+ }
},
"documentation":"<p>Contains information about where to publish the analytics results.</p>"
- },
- "AnalyticsS3ExportFileFormat":{
- "type":"string",
- "enum":["CSV"]
- },
+ },
+ "AnalyticsS3ExportFileFormat":{
+ "type":"string",
+ "enum":["CSV"]
+ },
"ArchiveStatus":{
"type":"string",
"enum":[
@@ -1320,75 +1320,75 @@
"DEEP_ARCHIVE_ACCESS"
]
},
- "Body":{"type":"blob"},
- "Bucket":{
- "type":"structure",
- "members":{
- "Name":{
- "shape":"BucketName",
+ "Body":{"type":"blob"},
+ "Bucket":{
+ "type":"structure",
+ "members":{
+ "Name":{
+ "shape":"BucketName",
"documentation":"<p>The name of the bucket.</p>"
- },
- "CreationDate":{
- "shape":"CreationDate",
+ },
+ "CreationDate":{
+ "shape":"CreationDate",
"documentation":"<p>Date the bucket was created. This date can change when making changes to your bucket, such as editing its bucket policy.</p>"
- }
+ }
},
"documentation":"<p> In terms of implementation, a Bucket is a resource. An Amazon S3 bucket name is globally unique, and the namespace is shared by all AWS accounts. </p>"
- },
- "BucketAccelerateStatus":{
- "type":"string",
- "enum":[
- "Enabled",
- "Suspended"
- ]
- },
- "BucketAlreadyExists":{
- "type":"structure",
- "members":{
- },
+ },
+ "BucketAccelerateStatus":{
+ "type":"string",
+ "enum":[
+ "Enabled",
+ "Suspended"
+ ]
+ },
+ "BucketAlreadyExists":{
+ "type":"structure",
+ "members":{
+ },
"documentation":"<p>The requested bucket name is not available. The bucket namespace is shared by all users of the system. Select a different name and try again.</p>",
- "exception":true
- },
- "BucketAlreadyOwnedByYou":{
- "type":"structure",
- "members":{
- },
+ "exception":true
+ },
+ "BucketAlreadyOwnedByYou":{
+ "type":"structure",
+ "members":{
+ },
"documentation":"<p>The bucket you tried to create already exists, and you own it. Amazon S3 returns this error in all AWS Regions except in the North Virginia Region. For legacy compatibility, if you re-create an existing bucket that you already own in the North Virginia Region, Amazon S3 returns 200 OK and resets the bucket access control lists (ACLs).</p>",
- "exception":true
- },
- "BucketCannedACL":{
- "type":"string",
- "enum":[
- "private",
- "public-read",
- "public-read-write",
- "authenticated-read"
- ]
- },
+ "exception":true
+ },
+ "BucketCannedACL":{
+ "type":"string",
+ "enum":[
+ "private",
+ "public-read",
+ "public-read-write",
+ "authenticated-read"
+ ]
+ },
"BucketKeyEnabled":{"type":"boolean"},
- "BucketLifecycleConfiguration":{
- "type":"structure",
- "required":["Rules"],
- "members":{
- "Rules":{
- "shape":"LifecycleRules",
+ "BucketLifecycleConfiguration":{
+ "type":"structure",
+ "required":["Rules"],
+ "members":{
+ "Rules":{
+ "shape":"LifecycleRules",
"documentation":"<p>A lifecycle rule for individual objects in an Amazon S3 bucket.</p>",
- "locationName":"Rule"
- }
+ "locationName":"Rule"
+ }
},
"documentation":"<p>Specifies the lifecycle configuration for objects in an Amazon S3 bucket. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/object-lifecycle-mgmt.html\">Object Lifecycle Management</a> in the <i>Amazon S3 User Guide</i>.</p>"
- },
- "BucketLocationConstraint":{
- "type":"string",
- "enum":[
+ },
+ "BucketLocationConstraint":{
+ "type":"string",
+ "enum":[
"af-south-1",
"ap-east-1",
"ap-northeast-1",
"ap-northeast-2",
"ap-northeast-3",
- "ap-south-1",
- "ap-southeast-1",
- "ap-southeast-2",
+ "ap-south-1",
+ "ap-southeast-1",
+ "ap-southeast-2",
"ca-central-1",
"cn-north-1",
"cn-northwest-1",
@@ -1400,178 +1400,178 @@
"eu-west-2",
"eu-west-3",
"me-south-1",
- "sa-east-1",
+ "sa-east-1",
"us-east-2",
"us-gov-east-1",
"us-gov-west-1",
"us-west-1",
"us-west-2"
- ]
- },
- "BucketLoggingStatus":{
- "type":"structure",
- "members":{
+ ]
+ },
+ "BucketLoggingStatus":{
+ "type":"structure",
+ "members":{
"LoggingEnabled":{"shape":"LoggingEnabled"}
},
"documentation":"<p>Container for logging status information.</p>"
- },
- "BucketLogsPermission":{
- "type":"string",
- "enum":[
- "FULL_CONTROL",
- "READ",
- "WRITE"
- ]
- },
- "BucketName":{"type":"string"},
- "BucketVersioningStatus":{
- "type":"string",
- "enum":[
- "Enabled",
- "Suspended"
- ]
- },
- "Buckets":{
- "type":"list",
- "member":{
- "shape":"Bucket",
- "locationName":"Bucket"
- }
- },
+ },
+ "BucketLogsPermission":{
+ "type":"string",
+ "enum":[
+ "FULL_CONTROL",
+ "READ",
+ "WRITE"
+ ]
+ },
+ "BucketName":{"type":"string"},
+ "BucketVersioningStatus":{
+ "type":"string",
+ "enum":[
+ "Enabled",
+ "Suspended"
+ ]
+ },
+ "Buckets":{
+ "type":"list",
+ "member":{
+ "shape":"Bucket",
+ "locationName":"Bucket"
+ }
+ },
"BypassGovernanceRetention":{"type":"boolean"},
- "BytesProcessed":{"type":"long"},
- "BytesReturned":{"type":"long"},
- "BytesScanned":{"type":"long"},
- "CORSConfiguration":{
- "type":"structure",
- "required":["CORSRules"],
- "members":{
- "CORSRules":{
- "shape":"CORSRules",
+ "BytesProcessed":{"type":"long"},
+ "BytesReturned":{"type":"long"},
+ "BytesScanned":{"type":"long"},
+ "CORSConfiguration":{
+ "type":"structure",
+ "required":["CORSRules"],
+ "members":{
+ "CORSRules":{
+ "shape":"CORSRules",
"documentation":"<p>A set of origins and methods (cross-origin access that you want to allow). You can add up to 100 rules to the configuration.</p>",
- "locationName":"CORSRule"
- }
+ "locationName":"CORSRule"
+ }
},
"documentation":"<p>Describes the cross-origin access configuration for objects in an Amazon S3 bucket. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/cors.html\">Enabling Cross-Origin Resource Sharing</a> in the <i>Amazon S3 User Guide</i>.</p>"
- },
- "CORSRule":{
- "type":"structure",
- "required":[
- "AllowedMethods",
- "AllowedOrigins"
- ],
- "members":{
+ },
+ "CORSRule":{
+ "type":"structure",
+ "required":[
+ "AllowedMethods",
+ "AllowedOrigins"
+ ],
+ "members":{
"ID":{
"shape":"ID",
"documentation":"<p>Unique identifier for the rule. The value cannot be longer than 255 characters.</p>"
},
- "AllowedHeaders":{
- "shape":"AllowedHeaders",
+ "AllowedHeaders":{
+ "shape":"AllowedHeaders",
"documentation":"<p>Headers that are specified in the <code>Access-Control-Request-Headers</code> header. These headers are allowed in a preflight OPTIONS request. In response to any preflight OPTIONS request, Amazon S3 returns any requested headers that are allowed.</p>",
- "locationName":"AllowedHeader"
- },
- "AllowedMethods":{
- "shape":"AllowedMethods",
+ "locationName":"AllowedHeader"
+ },
+ "AllowedMethods":{
+ "shape":"AllowedMethods",
"documentation":"<p>An HTTP method that you allow the origin to execute. Valid values are <code>GET</code>, <code>PUT</code>, <code>HEAD</code>, <code>POST</code>, and <code>DELETE</code>.</p>",
- "locationName":"AllowedMethod"
- },
- "AllowedOrigins":{
- "shape":"AllowedOrigins",
+ "locationName":"AllowedMethod"
+ },
+ "AllowedOrigins":{
+ "shape":"AllowedOrigins",
"documentation":"<p>One or more origins you want customers to be able to access the bucket from.</p>",
- "locationName":"AllowedOrigin"
- },
- "ExposeHeaders":{
- "shape":"ExposeHeaders",
+ "locationName":"AllowedOrigin"
+ },
+ "ExposeHeaders":{
+ "shape":"ExposeHeaders",
"documentation":"<p>One or more headers in the response that you want customers to be able to access from their applications (for example, from a JavaScript <code>XMLHttpRequest</code> object).</p>",
- "locationName":"ExposeHeader"
- },
- "MaxAgeSeconds":{
- "shape":"MaxAgeSeconds",
+ "locationName":"ExposeHeader"
+ },
+ "MaxAgeSeconds":{
+ "shape":"MaxAgeSeconds",
"documentation":"<p>The time in seconds that your browser is to cache the preflight response for the specified resource.</p>"
- }
+ }
},
"documentation":"<p>Specifies a cross-origin access rule for an Amazon S3 bucket.</p>"
- },
- "CORSRules":{
- "type":"list",
- "member":{"shape":"CORSRule"},
- "flattened":true
- },
- "CSVInput":{
- "type":"structure",
- "members":{
- "FileHeaderInfo":{
- "shape":"FileHeaderInfo",
+ },
+ "CORSRules":{
+ "type":"list",
+ "member":{"shape":"CORSRule"},
+ "flattened":true
+ },
+ "CSVInput":{
+ "type":"structure",
+ "members":{
+ "FileHeaderInfo":{
+ "shape":"FileHeaderInfo",
"documentation":"<p>Describes the first line of input. Valid values are:</p> <ul> <li> <p> <code>NONE</code>: First line is not a header.</p> </li> <li> <p> <code>IGNORE</code>: First line is a header, but you can't use the header values to indicate the column in an expression. You can use column position (such as _1, _2, …) to indicate the column (<code>SELECT s._1 FROM OBJECT s</code>).</p> </li> <li> <p> <code>Use</code>: First line is a header, and you can use the header value to identify a column in an expression (<code>SELECT \"name\" FROM OBJECT</code>). </p> </li> </ul>"
- },
- "Comments":{
- "shape":"Comments",
+ },
+ "Comments":{
+ "shape":"Comments",
"documentation":"<p>A single character used to indicate that a row should be ignored when the character is present at the start of that row. You can specify any character to indicate a comment line.</p>"
- },
- "QuoteEscapeCharacter":{
- "shape":"QuoteEscapeCharacter",
+ },
+ "QuoteEscapeCharacter":{
+ "shape":"QuoteEscapeCharacter",
"documentation":"<p>A single character used for escaping the quotation mark character inside an already escaped value. For example, the value \"\"\" a , b \"\"\" is parsed as \" a , b \".</p>"
- },
- "RecordDelimiter":{
- "shape":"RecordDelimiter",
+ },
+ "RecordDelimiter":{
+ "shape":"RecordDelimiter",
"documentation":"<p>A single character used to separate individual records in the input. Instead of the default value, you can specify an arbitrary delimiter.</p>"
- },
- "FieldDelimiter":{
- "shape":"FieldDelimiter",
+ },
+ "FieldDelimiter":{
+ "shape":"FieldDelimiter",
"documentation":"<p>A single character used to separate individual fields in a record. You can specify an arbitrary delimiter.</p>"
- },
- "QuoteCharacter":{
- "shape":"QuoteCharacter",
+ },
+ "QuoteCharacter":{
+ "shape":"QuoteCharacter",
"documentation":"<p>A single character used for escaping when the field delimiter is part of the value. For example, if the value is <code>a, b</code>, Amazon S3 wraps this field value in quotation marks, as follows: <code>\" a , b \"</code>.</p> <p>Type: String</p> <p>Default: <code>\"</code> </p> <p>Ancestors: <code>CSV</code> </p>"
- },
- "AllowQuotedRecordDelimiter":{
- "shape":"AllowQuotedRecordDelimiter",
+ },
+ "AllowQuotedRecordDelimiter":{
+ "shape":"AllowQuotedRecordDelimiter",
"documentation":"<p>Specifies that CSV field values may contain quoted record delimiters and such records should be allowed. Default value is FALSE. Setting this value to TRUE may lower performance.</p>"
- }
- },
+ }
+ },
"documentation":"<p>Describes how an uncompressed comma-separated values (CSV)-formatted input object is formatted.</p>"
- },
- "CSVOutput":{
- "type":"structure",
- "members":{
- "QuoteFields":{
- "shape":"QuoteFields",
+ },
+ "CSVOutput":{
+ "type":"structure",
+ "members":{
+ "QuoteFields":{
+ "shape":"QuoteFields",
"documentation":"<p>Indicates whether to use quotation marks around output fields. </p> <ul> <li> <p> <code>ALWAYS</code>: Always use quotation marks for output fields.</p> </li> <li> <p> <code>ASNEEDED</code>: Use quotation marks for output fields when needed.</p> </li> </ul>"
- },
- "QuoteEscapeCharacter":{
- "shape":"QuoteEscapeCharacter",
+ },
+ "QuoteEscapeCharacter":{
+ "shape":"QuoteEscapeCharacter",
"documentation":"<p>The single character used for escaping the quote character inside an already escaped value.</p>"
- },
- "RecordDelimiter":{
- "shape":"RecordDelimiter",
+ },
+ "RecordDelimiter":{
+ "shape":"RecordDelimiter",
"documentation":"<p>A single character used to separate individual records in the output. Instead of the default value, you can specify an arbitrary delimiter.</p>"
- },
- "FieldDelimiter":{
- "shape":"FieldDelimiter",
+ },
+ "FieldDelimiter":{
+ "shape":"FieldDelimiter",
"documentation":"<p>The value used to separate individual fields in a record. You can specify an arbitrary delimiter.</p>"
- },
- "QuoteCharacter":{
- "shape":"QuoteCharacter",
+ },
+ "QuoteCharacter":{
+ "shape":"QuoteCharacter",
"documentation":"<p>A single character used for escaping when the field delimiter is part of the value. For example, if the value is <code>a, b</code>, Amazon S3 wraps this field value in quotation marks, as follows: <code>\" a , b \"</code>.</p>"
- }
- },
+ }
+ },
"documentation":"<p>Describes how uncompressed comma-separated values (CSV)-formatted results are formatted.</p>"
- },
- "CacheControl":{"type":"string"},
- "CloudFunction":{"type":"string"},
- "CloudFunctionConfiguration":{
- "type":"structure",
- "members":{
- "Id":{"shape":"NotificationId"},
- "Event":{
- "shape":"Event",
- "deprecated":true
- },
- "Events":{
- "shape":"EventList",
+ },
+ "CacheControl":{"type":"string"},
+ "CloudFunction":{"type":"string"},
+ "CloudFunctionConfiguration":{
+ "type":"structure",
+ "members":{
+ "Id":{"shape":"NotificationId"},
+ "Event":{
+ "shape":"Event",
+ "deprecated":true
+ },
+ "Events":{
+ "shape":"EventList",
"documentation":"<p>Bucket events for which to send notifications.</p>",
- "locationName":"Event"
- },
+ "locationName":"Event"
+ },
"CloudFunction":{
"shape":"CloudFunction",
"documentation":"<p>Lambda cloud function ARN that Amazon S3 can invoke when it detects events of the specified type.</p>"
@@ -1582,28 +1582,28 @@
}
},
"documentation":"<p>Container for specifying the AWS Lambda notification configuration.</p>"
- },
- "CloudFunctionInvocationRole":{"type":"string"},
- "Code":{"type":"string"},
- "Comments":{"type":"string"},
- "CommonPrefix":{
- "type":"structure",
- "members":{
+ },
+ "CloudFunctionInvocationRole":{"type":"string"},
+ "Code":{"type":"string"},
+ "Comments":{"type":"string"},
+ "CommonPrefix":{
+ "type":"structure",
+ "members":{
"Prefix":{
"shape":"Prefix",
"documentation":"<p>Container for the specified common prefix.</p>"
}
},
"documentation":"<p>Container for all (if there are any) keys between Prefix and the next occurrence of the string specified by a delimiter. CommonPrefixes lists keys that act like subdirectories in the directory specified by Prefix. For example, if the prefix is notes/ and the delimiter is a slash (/) as in notes/summer/july, the common prefix is notes/summer/. </p>"
- },
- "CommonPrefixList":{
- "type":"list",
- "member":{"shape":"CommonPrefix"},
- "flattened":true
- },
- "CompleteMultipartUploadOutput":{
- "type":"structure",
- "members":{
+ },
+ "CommonPrefixList":{
+ "type":"list",
+ "member":{"shape":"CommonPrefix"},
+ "flattened":true
+ },
+ "CompleteMultipartUploadOutput":{
+ "type":"structure",
+ "members":{
"Location":{
"shape":"Location",
"documentation":"<p>The URI that identifies the newly created object.</p>"
@@ -1616,209 +1616,209 @@
"shape":"ObjectKey",
"documentation":"<p>The object key of the newly created object.</p>"
},
- "Expiration":{
- "shape":"Expiration",
+ "Expiration":{
+ "shape":"Expiration",
"documentation":"<p>If the object expiration is configured, this will contain the expiration date (expiry-date) and rule ID (rule-id). The value of rule-id is URL encoded.</p>",
- "location":"header",
- "locationName":"x-amz-expiration"
- },
- "ETag":{
- "shape":"ETag",
+ "location":"header",
+ "locationName":"x-amz-expiration"
+ },
+ "ETag":{
+ "shape":"ETag",
"documentation":"<p>Entity tag that identifies the newly created object's data. Objects with different object data will have different entity tags. The entity tag is an opaque string. The entity tag may or may not be an MD5 digest of the object data. If the entity tag is not an MD5 digest of the object data, it will contain one or more nonhexadecimal characters and/or will consist of less than 32 or more than 32 hexadecimal digits.</p>"
- },
- "ServerSideEncryption":{
- "shape":"ServerSideEncryption",
+ },
+ "ServerSideEncryption":{
+ "shape":"ServerSideEncryption",
"documentation":"<p>If you specified server-side encryption either with an Amazon S3-managed encryption key or an AWS KMS customer master key (CMK) in your initiate multipart upload request, the response includes this header. It confirms the encryption algorithm that Amazon S3 used to encrypt the object.</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption"
- },
- "VersionId":{
- "shape":"ObjectVersionId",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption"
+ },
+ "VersionId":{
+ "shape":"ObjectVersionId",
"documentation":"<p>Version ID of the newly created object, in case the bucket has versioning turned on.</p>",
- "location":"header",
- "locationName":"x-amz-version-id"
- },
- "SSEKMSKeyId":{
- "shape":"SSEKMSKeyId",
+ "location":"header",
+ "locationName":"x-amz-version-id"
+ },
+ "SSEKMSKeyId":{
+ "shape":"SSEKMSKeyId",
"documentation":"<p>If present, specifies the ID of the AWS Key Management Service (AWS KMS) symmetric customer managed customer master key (CMK) that was used for the object.</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-aws-kms-key-id"
- },
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-aws-kms-key-id"
+ },
"BucketKeyEnabled":{
"shape":"BucketKeyEnabled",
"documentation":"<p>Indicates whether the multipart upload uses an S3 Bucket Key for server-side encryption with AWS KMS (SSE-KMS).</p>",
"location":"header",
"locationName":"x-amz-server-side-encryption-bucket-key-enabled"
},
- "RequestCharged":{
- "shape":"RequestCharged",
- "location":"header",
- "locationName":"x-amz-request-charged"
- }
- }
- },
- "CompleteMultipartUploadRequest":{
- "type":"structure",
- "required":[
- "Bucket",
- "Key",
- "UploadId"
- ],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ "RequestCharged":{
+ "shape":"RequestCharged",
+ "location":"header",
+ "locationName":"x-amz-request-charged"
+ }
+ }
+ },
+ "CompleteMultipartUploadRequest":{
+ "type":"structure",
+ "required":[
+ "Bucket",
+ "Key",
+ "UploadId"
+ ],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>Name of the bucket to which the multipart upload was initiated.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "Key":{
- "shape":"ObjectKey",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "Key":{
+ "shape":"ObjectKey",
"documentation":"<p>Object key for which the multipart upload was initiated.</p>",
- "location":"uri",
- "locationName":"Key"
- },
- "MultipartUpload":{
- "shape":"CompletedMultipartUpload",
+ "location":"uri",
+ "locationName":"Key"
+ },
+ "MultipartUpload":{
+ "shape":"CompletedMultipartUpload",
"documentation":"<p>The container for the multipart upload request information.</p>",
- "locationName":"CompleteMultipartUpload",
- "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
- },
- "UploadId":{
- "shape":"MultipartUploadId",
+ "locationName":"CompleteMultipartUpload",
+ "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
+ },
+ "UploadId":{
+ "shape":"MultipartUploadId",
"documentation":"<p>ID for the initiated multipart upload.</p>",
- "location":"querystring",
- "locationName":"uploadId"
- },
- "RequestPayer":{
- "shape":"RequestPayer",
- "location":"header",
- "locationName":"x-amz-request-payer"
+ "location":"querystring",
+ "locationName":"uploadId"
+ },
+ "RequestPayer":{
+ "shape":"RequestPayer",
+ "location":"header",
+ "locationName":"x-amz-request-payer"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- },
- "payload":"MultipartUpload"
- },
- "CompletedMultipartUpload":{
- "type":"structure",
- "members":{
- "Parts":{
- "shape":"CompletedPartList",
+ }
+ },
+ "payload":"MultipartUpload"
+ },
+ "CompletedMultipartUpload":{
+ "type":"structure",
+ "members":{
+ "Parts":{
+ "shape":"CompletedPartList",
"documentation":"<p>Array of CompletedPart data types.</p>",
- "locationName":"Part"
- }
+ "locationName":"Part"
+ }
},
"documentation":"<p>The container for the completed multipart upload details.</p>"
- },
- "CompletedPart":{
- "type":"structure",
- "members":{
- "ETag":{
- "shape":"ETag",
+ },
+ "CompletedPart":{
+ "type":"structure",
+ "members":{
+ "ETag":{
+ "shape":"ETag",
"documentation":"<p>Entity tag returned when the part was uploaded.</p>"
- },
- "PartNumber":{
- "shape":"PartNumber",
+ },
+ "PartNumber":{
+ "shape":"PartNumber",
"documentation":"<p>Part number that identifies the part. This is a positive integer between 1 and 10,000.</p>"
- }
+ }
},
"documentation":"<p>Details of the parts that were uploaded.</p>"
- },
- "CompletedPartList":{
- "type":"list",
- "member":{"shape":"CompletedPart"},
- "flattened":true
- },
- "CompressionType":{
- "type":"string",
- "enum":[
- "NONE",
+ },
+ "CompletedPartList":{
+ "type":"list",
+ "member":{"shape":"CompletedPart"},
+ "flattened":true
+ },
+ "CompressionType":{
+ "type":"string",
+ "enum":[
+ "NONE",
"GZIP",
"BZIP2"
- ]
- },
- "Condition":{
- "type":"structure",
- "members":{
- "HttpErrorCodeReturnedEquals":{
- "shape":"HttpErrorCodeReturnedEquals",
+ ]
+ },
+ "Condition":{
+ "type":"structure",
+ "members":{
+ "HttpErrorCodeReturnedEquals":{
+ "shape":"HttpErrorCodeReturnedEquals",
"documentation":"<p>The HTTP error code when the redirect is applied. In the event of an error, if the error code equals this value, then the specified redirect is applied. Required when parent element <code>Condition</code> is specified and sibling <code>KeyPrefixEquals</code> is not specified. If both are specified, then both must be true for the redirect to be applied.</p>"
- },
- "KeyPrefixEquals":{
- "shape":"KeyPrefixEquals",
+ },
+ "KeyPrefixEquals":{
+ "shape":"KeyPrefixEquals",
"documentation":"<p>The object key name prefix when the redirect is applied. For example, to redirect requests for <code>ExamplePage.html</code>, the key prefix will be <code>ExamplePage.html</code>. To redirect request for all pages with the prefix <code>docs/</code>, the key prefix will be <code>/docs</code>, which identifies all objects in the <code>docs/</code> folder. Required when the parent element <code>Condition</code> is specified and sibling <code>HttpErrorCodeReturnedEquals</code> is not specified. If both conditions are specified, both must be true for the redirect to be applied.</p> <important> <p>Replacement must be made for object keys containing special characters (such as carriage returns) when using XML requests. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-keys.html#object-key-xml-related-constraints\"> XML related object key constraints</a>.</p> </important>"
- }
+ }
},
"documentation":"<p>A container for describing a condition that must be met for the specified redirect to apply. For example, 1. If request is for pages in the <code>/docs</code> folder, redirect to the <code>/documents</code> folder. 2. If request results in HTTP error 4xx, redirect request to another host where you might process the error.</p>"
- },
- "ConfirmRemoveSelfBucketAccess":{"type":"boolean"},
- "ContentDisposition":{"type":"string"},
- "ContentEncoding":{"type":"string"},
- "ContentLanguage":{"type":"string"},
- "ContentLength":{"type":"long"},
- "ContentMD5":{"type":"string"},
- "ContentRange":{"type":"string"},
- "ContentType":{"type":"string"},
- "ContinuationEvent":{
- "type":"structure",
- "members":{
- },
+ },
+ "ConfirmRemoveSelfBucketAccess":{"type":"boolean"},
+ "ContentDisposition":{"type":"string"},
+ "ContentEncoding":{"type":"string"},
+ "ContentLanguage":{"type":"string"},
+ "ContentLength":{"type":"long"},
+ "ContentMD5":{"type":"string"},
+ "ContentRange":{"type":"string"},
+ "ContentType":{"type":"string"},
+ "ContinuationEvent":{
+ "type":"structure",
+ "members":{
+ },
"documentation":"<p/>",
- "event":true
- },
- "CopyObjectOutput":{
- "type":"structure",
- "members":{
+ "event":true
+ },
+ "CopyObjectOutput":{
+ "type":"structure",
+ "members":{
"CopyObjectResult":{
"shape":"CopyObjectResult",
"documentation":"<p>Container for all response elements.</p>"
},
- "Expiration":{
- "shape":"Expiration",
+ "Expiration":{
+ "shape":"Expiration",
"documentation":"<p>If the object expiration is configured, the response includes this header.</p>",
- "location":"header",
- "locationName":"x-amz-expiration"
- },
- "CopySourceVersionId":{
- "shape":"CopySourceVersionId",
+ "location":"header",
+ "locationName":"x-amz-expiration"
+ },
+ "CopySourceVersionId":{
+ "shape":"CopySourceVersionId",
"documentation":"<p>Version of the copied object in the destination bucket.</p>",
- "location":"header",
- "locationName":"x-amz-copy-source-version-id"
- },
- "VersionId":{
- "shape":"ObjectVersionId",
+ "location":"header",
+ "locationName":"x-amz-copy-source-version-id"
+ },
+ "VersionId":{
+ "shape":"ObjectVersionId",
"documentation":"<p>Version ID of the newly created copy.</p>",
- "location":"header",
- "locationName":"x-amz-version-id"
- },
- "ServerSideEncryption":{
- "shape":"ServerSideEncryption",
+ "location":"header",
+ "locationName":"x-amz-version-id"
+ },
+ "ServerSideEncryption":{
+ "shape":"ServerSideEncryption",
"documentation":"<p>The server-side encryption algorithm used when storing this object in Amazon S3 (for example, AES256, aws:kms).</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption"
- },
- "SSECustomerAlgorithm":{
- "shape":"SSECustomerAlgorithm",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption"
+ },
+ "SSECustomerAlgorithm":{
+ "shape":"SSECustomerAlgorithm",
"documentation":"<p>If server-side encryption with a customer-provided encryption key was requested, the response will include this header confirming the encryption algorithm used.</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-customer-algorithm"
- },
- "SSECustomerKeyMD5":{
- "shape":"SSECustomerKeyMD5",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-customer-algorithm"
+ },
+ "SSECustomerKeyMD5":{
+ "shape":"SSECustomerKeyMD5",
"documentation":"<p>If server-side encryption with a customer-provided encryption key was requested, the response will include this header to provide round-trip message integrity verification of the customer-provided encryption key.</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-customer-key-MD5"
- },
- "SSEKMSKeyId":{
- "shape":"SSEKMSKeyId",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-customer-key-MD5"
+ },
+ "SSEKMSKeyId":{
+ "shape":"SSEKMSKeyId",
"documentation":"<p>If present, specifies the ID of the AWS Key Management Service (AWS KMS) symmetric customer managed customer master key (CMK) that was used for the object.</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-aws-kms-key-id"
- },
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-aws-kms-key-id"
+ },
"SSEKMSEncryptionContext":{
"shape":"SSEKMSEncryptionContext",
"documentation":"<p>If present, specifies the AWS KMS Encryption Context to use for object encryption. The value of this header is a base64-encoded UTF-8 string holding JSON with the encryption context key-value pairs.</p>",
@@ -1831,190 +1831,190 @@
"location":"header",
"locationName":"x-amz-server-side-encryption-bucket-key-enabled"
},
- "RequestCharged":{
- "shape":"RequestCharged",
- "location":"header",
- "locationName":"x-amz-request-charged"
- }
- },
- "payload":"CopyObjectResult"
- },
- "CopyObjectRequest":{
- "type":"structure",
- "required":[
- "Bucket",
- "CopySource",
- "Key"
- ],
- "members":{
- "ACL":{
- "shape":"ObjectCannedACL",
+ "RequestCharged":{
+ "shape":"RequestCharged",
+ "location":"header",
+ "locationName":"x-amz-request-charged"
+ }
+ },
+ "payload":"CopyObjectResult"
+ },
+ "CopyObjectRequest":{
+ "type":"structure",
+ "required":[
+ "Bucket",
+ "CopySource",
+ "Key"
+ ],
+ "members":{
+ "ACL":{
+ "shape":"ObjectCannedACL",
"documentation":"<p>The canned ACL to apply to the object.</p> <p>This action is not supported by Amazon S3 on Outposts.</p>",
- "location":"header",
- "locationName":"x-amz-acl"
- },
- "Bucket":{
- "shape":"BucketName",
+ "location":"header",
+ "locationName":"x-amz-acl"
+ },
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The name of the destination bucket.</p> <p>When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.s3-accesspoint.<i>Region</i>.amazonaws.com. When using this action with an access point through the AWS SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\">Using access points</a> in the <i>Amazon S3 User Guide</i>.</p> <p>When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.<i>outpostID</i>.s3-outposts.<i>Region</i>.amazonaws.com. When using this action using S3 on Outposts through the AWS SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html\">Using S3 on Outposts</a> in the <i>Amazon S3 User Guide</i>.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "CacheControl":{
- "shape":"CacheControl",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "CacheControl":{
+ "shape":"CacheControl",
"documentation":"<p>Specifies caching behavior along the request/reply chain.</p>",
- "location":"header",
- "locationName":"Cache-Control"
- },
- "ContentDisposition":{
- "shape":"ContentDisposition",
+ "location":"header",
+ "locationName":"Cache-Control"
+ },
+ "ContentDisposition":{
+ "shape":"ContentDisposition",
"documentation":"<p>Specifies presentational information for the object.</p>",
- "location":"header",
- "locationName":"Content-Disposition"
- },
- "ContentEncoding":{
- "shape":"ContentEncoding",
+ "location":"header",
+ "locationName":"Content-Disposition"
+ },
+ "ContentEncoding":{
+ "shape":"ContentEncoding",
"documentation":"<p>Specifies what content encodings have been applied to the object and thus what decoding mechanisms must be applied to obtain the media-type referenced by the Content-Type header field.</p>",
- "location":"header",
- "locationName":"Content-Encoding"
- },
- "ContentLanguage":{
- "shape":"ContentLanguage",
+ "location":"header",
+ "locationName":"Content-Encoding"
+ },
+ "ContentLanguage":{
+ "shape":"ContentLanguage",
"documentation":"<p>The language the content is in.</p>",
- "location":"header",
- "locationName":"Content-Language"
- },
- "ContentType":{
- "shape":"ContentType",
+ "location":"header",
+ "locationName":"Content-Language"
+ },
+ "ContentType":{
+ "shape":"ContentType",
"documentation":"<p>A standard MIME type describing the format of the object data.</p>",
- "location":"header",
- "locationName":"Content-Type"
- },
- "CopySource":{
- "shape":"CopySource",
+ "location":"header",
+ "locationName":"Content-Type"
+ },
+ "CopySource":{
+ "shape":"CopySource",
"documentation":"<p>Specifies the source object for the copy operation. You specify the value in one of two formats, depending on whether you want to access the source object through an <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-points.html\">access point</a>:</p> <ul> <li> <p>For objects not accessed through an access point, specify the name of the source bucket and the key of the source object, separated by a slash (/). For example, to copy the object <code>reports/january.pdf</code> from the bucket <code>awsexamplebucket</code>, use <code>awsexamplebucket/reports/january.pdf</code>. The value must be URL encoded.</p> </li> <li> <p>For objects accessed through access points, specify the Amazon Resource Name (ARN) of the object as accessed through the access point, in the format <code>arn:aws:s3:&lt;Region&gt;:&lt;account-id&gt;:accesspoint/&lt;access-point-name&gt;/object/&lt;key&gt;</code>. For example, to copy the object <code>reports/january.pdf</code> through access point <code>my-access-point</code> owned by account <code>123456789012</code> in Region <code>us-west-2</code>, use the URL encoding of <code>arn:aws:s3:us-west-2:123456789012:accesspoint/my-access-point/object/reports/january.pdf</code>. The value must be URL encoded.</p> <note> <p>Amazon S3 supports copy operations using access points only when the source and destination buckets are in the same AWS Region.</p> </note> <p>Alternatively, for objects accessed through Amazon S3 on Outposts, specify the ARN of the object as accessed in the format <code>arn:aws:s3-outposts:&lt;Region&gt;:&lt;account-id&gt;:outpost/&lt;outpost-id&gt;/object/&lt;key&gt;</code>. For example, to copy the object <code>reports/january.pdf</code> through outpost <code>my-outpost</code> owned by account <code>123456789012</code> in Region <code>us-west-2</code>, use the URL encoding of <code>arn:aws:s3-outposts:us-west-2:123456789012:outpost/my-outpost/object/reports/january.pdf</code>. The value must be URL encoded. </p> </li> </ul> <p>To copy a specific version of an object, append <code>?versionId=&lt;version-id&gt;</code> to the value (for example, <code>awsexamplebucket/reports/january.pdf?versionId=QUpfdndhfd8438MNFDN93jdnJFkdmqnh893</code>). If you don't specify a version ID, Amazon S3 copies the latest version of the source object.</p>",
- "location":"header",
- "locationName":"x-amz-copy-source"
- },
- "CopySourceIfMatch":{
- "shape":"CopySourceIfMatch",
+ "location":"header",
+ "locationName":"x-amz-copy-source"
+ },
+ "CopySourceIfMatch":{
+ "shape":"CopySourceIfMatch",
"documentation":"<p>Copies the object if its entity tag (ETag) matches the specified tag.</p>",
- "location":"header",
- "locationName":"x-amz-copy-source-if-match"
- },
- "CopySourceIfModifiedSince":{
- "shape":"CopySourceIfModifiedSince",
+ "location":"header",
+ "locationName":"x-amz-copy-source-if-match"
+ },
+ "CopySourceIfModifiedSince":{
+ "shape":"CopySourceIfModifiedSince",
"documentation":"<p>Copies the object if it has been modified since the specified time.</p>",
- "location":"header",
- "locationName":"x-amz-copy-source-if-modified-since"
- },
- "CopySourceIfNoneMatch":{
- "shape":"CopySourceIfNoneMatch",
+ "location":"header",
+ "locationName":"x-amz-copy-source-if-modified-since"
+ },
+ "CopySourceIfNoneMatch":{
+ "shape":"CopySourceIfNoneMatch",
"documentation":"<p>Copies the object if its entity tag (ETag) is different than the specified ETag.</p>",
- "location":"header",
- "locationName":"x-amz-copy-source-if-none-match"
- },
- "CopySourceIfUnmodifiedSince":{
- "shape":"CopySourceIfUnmodifiedSince",
+ "location":"header",
+ "locationName":"x-amz-copy-source-if-none-match"
+ },
+ "CopySourceIfUnmodifiedSince":{
+ "shape":"CopySourceIfUnmodifiedSince",
"documentation":"<p>Copies the object if it hasn't been modified since the specified time.</p>",
- "location":"header",
- "locationName":"x-amz-copy-source-if-unmodified-since"
- },
- "Expires":{
- "shape":"Expires",
+ "location":"header",
+ "locationName":"x-amz-copy-source-if-unmodified-since"
+ },
+ "Expires":{
+ "shape":"Expires",
"documentation":"<p>The date and time at which the object is no longer cacheable.</p>",
- "location":"header",
- "locationName":"Expires"
- },
- "GrantFullControl":{
- "shape":"GrantFullControl",
+ "location":"header",
+ "locationName":"Expires"
+ },
+ "GrantFullControl":{
+ "shape":"GrantFullControl",
"documentation":"<p>Gives the grantee READ, READ_ACP, and WRITE_ACP permissions on the object.</p> <p>This action is not supported by Amazon S3 on Outposts.</p>",
- "location":"header",
- "locationName":"x-amz-grant-full-control"
- },
- "GrantRead":{
- "shape":"GrantRead",
+ "location":"header",
+ "locationName":"x-amz-grant-full-control"
+ },
+ "GrantRead":{
+ "shape":"GrantRead",
"documentation":"<p>Allows grantee to read the object data and its metadata.</p> <p>This action is not supported by Amazon S3 on Outposts.</p>",
- "location":"header",
- "locationName":"x-amz-grant-read"
- },
- "GrantReadACP":{
- "shape":"GrantReadACP",
+ "location":"header",
+ "locationName":"x-amz-grant-read"
+ },
+ "GrantReadACP":{
+ "shape":"GrantReadACP",
"documentation":"<p>Allows grantee to read the object ACL.</p> <p>This action is not supported by Amazon S3 on Outposts.</p>",
- "location":"header",
- "locationName":"x-amz-grant-read-acp"
- },
- "GrantWriteACP":{
- "shape":"GrantWriteACP",
+ "location":"header",
+ "locationName":"x-amz-grant-read-acp"
+ },
+ "GrantWriteACP":{
+ "shape":"GrantWriteACP",
"documentation":"<p>Allows grantee to write the ACL for the applicable object.</p> <p>This action is not supported by Amazon S3 on Outposts.</p>",
- "location":"header",
- "locationName":"x-amz-grant-write-acp"
- },
- "Key":{
- "shape":"ObjectKey",
+ "location":"header",
+ "locationName":"x-amz-grant-write-acp"
+ },
+ "Key":{
+ "shape":"ObjectKey",
"documentation":"<p>The key of the destination object.</p>",
- "location":"uri",
- "locationName":"Key"
- },
- "Metadata":{
- "shape":"Metadata",
+ "location":"uri",
+ "locationName":"Key"
+ },
+ "Metadata":{
+ "shape":"Metadata",
"documentation":"<p>A map of metadata to store with the object in S3.</p>",
- "location":"headers",
- "locationName":"x-amz-meta-"
- },
- "MetadataDirective":{
- "shape":"MetadataDirective",
+ "location":"headers",
+ "locationName":"x-amz-meta-"
+ },
+ "MetadataDirective":{
+ "shape":"MetadataDirective",
"documentation":"<p>Specifies whether the metadata is copied from the source object or replaced with metadata provided in the request.</p>",
- "location":"header",
- "locationName":"x-amz-metadata-directive"
- },
- "TaggingDirective":{
- "shape":"TaggingDirective",
+ "location":"header",
+ "locationName":"x-amz-metadata-directive"
+ },
+ "TaggingDirective":{
+ "shape":"TaggingDirective",
"documentation":"<p>Specifies whether the object tag-set are copied from the source object or replaced with tag-set provided in the request.</p>",
- "location":"header",
- "locationName":"x-amz-tagging-directive"
- },
- "ServerSideEncryption":{
- "shape":"ServerSideEncryption",
+ "location":"header",
+ "locationName":"x-amz-tagging-directive"
+ },
+ "ServerSideEncryption":{
+ "shape":"ServerSideEncryption",
"documentation":"<p>The server-side encryption algorithm used when storing this object in Amazon S3 (for example, AES256, aws:kms).</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption"
- },
- "StorageClass":{
- "shape":"StorageClass",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption"
+ },
+ "StorageClass":{
+ "shape":"StorageClass",
"documentation":"<p>By default, Amazon S3 uses the STANDARD Storage Class to store newly created objects. The STANDARD storage class provides high durability and high availability. Depending on performance needs, you can specify a different Storage Class. Amazon S3 on Outposts only uses the OUTPOSTS Storage Class. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/storage-class-intro.html\">Storage Classes</a> in the <i>Amazon S3 User Guide</i>.</p>",
- "location":"header",
- "locationName":"x-amz-storage-class"
- },
- "WebsiteRedirectLocation":{
- "shape":"WebsiteRedirectLocation",
+ "location":"header",
+ "locationName":"x-amz-storage-class"
+ },
+ "WebsiteRedirectLocation":{
+ "shape":"WebsiteRedirectLocation",
"documentation":"<p>If the bucket is configured as a website, redirects requests for this object to another object in the same bucket or to an external URL. Amazon S3 stores the value of this header in the object metadata.</p>",
- "location":"header",
- "locationName":"x-amz-website-redirect-location"
- },
- "SSECustomerAlgorithm":{
- "shape":"SSECustomerAlgorithm",
+ "location":"header",
+ "locationName":"x-amz-website-redirect-location"
+ },
+ "SSECustomerAlgorithm":{
+ "shape":"SSECustomerAlgorithm",
"documentation":"<p>Specifies the algorithm to use to when encrypting the object (for example, AES256).</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-customer-algorithm"
- },
- "SSECustomerKey":{
- "shape":"SSECustomerKey",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-customer-algorithm"
+ },
+ "SSECustomerKey":{
+ "shape":"SSECustomerKey",
"documentation":"<p>Specifies the customer-provided encryption key for Amazon S3 to use in encrypting data. This value is used to store the object and then it is discarded; Amazon S3 does not store the encryption key. The key must be appropriate for use with the algorithm specified in the <code>x-amz-server-side-encryption-customer-algorithm</code> header.</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-customer-key"
- },
- "SSECustomerKeyMD5":{
- "shape":"SSECustomerKeyMD5",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-customer-key"
+ },
+ "SSECustomerKeyMD5":{
+ "shape":"SSECustomerKeyMD5",
"documentation":"<p>Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. Amazon S3 uses this header for a message integrity check to ensure that the encryption key was transmitted without error.</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-customer-key-MD5"
- },
- "SSEKMSKeyId":{
- "shape":"SSEKMSKeyId",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-customer-key-MD5"
+ },
+ "SSEKMSKeyId":{
+ "shape":"SSEKMSKeyId",
"documentation":"<p>Specifies the AWS KMS key ID to use for object encryption. All GET and PUT requests for an object protected by AWS KMS will fail if not made via SSL or using SigV4. For information about configuring using any of the officially supported AWS SDKs and AWS CLI, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingAWSSDK.html#specify-signature-version\">Specifying the Signature Version in Request Authentication</a> in the <i>Amazon S3 User Guide</i>.</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-aws-kms-key-id"
- },
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-aws-kms-key-id"
+ },
"SSEKMSEncryptionContext":{
"shape":"SSEKMSEncryptionContext",
"documentation":"<p>Specifies the AWS KMS Encryption Context to use for object encryption. The value of this header is a base64-encoded UTF-8 string holding JSON with the encryption context key-value pairs.</p>",
@@ -2027,34 +2027,34 @@
"location":"header",
"locationName":"x-amz-server-side-encryption-bucket-key-enabled"
},
- "CopySourceSSECustomerAlgorithm":{
- "shape":"CopySourceSSECustomerAlgorithm",
+ "CopySourceSSECustomerAlgorithm":{
+ "shape":"CopySourceSSECustomerAlgorithm",
"documentation":"<p>Specifies the algorithm to use when decrypting the source object (for example, AES256).</p>",
- "location":"header",
- "locationName":"x-amz-copy-source-server-side-encryption-customer-algorithm"
- },
- "CopySourceSSECustomerKey":{
- "shape":"CopySourceSSECustomerKey",
+ "location":"header",
+ "locationName":"x-amz-copy-source-server-side-encryption-customer-algorithm"
+ },
+ "CopySourceSSECustomerKey":{
+ "shape":"CopySourceSSECustomerKey",
"documentation":"<p>Specifies the customer-provided encryption key for Amazon S3 to use to decrypt the source object. The encryption key provided in this header must be one that was used when the source object was created.</p>",
- "location":"header",
- "locationName":"x-amz-copy-source-server-side-encryption-customer-key"
- },
- "CopySourceSSECustomerKeyMD5":{
- "shape":"CopySourceSSECustomerKeyMD5",
+ "location":"header",
+ "locationName":"x-amz-copy-source-server-side-encryption-customer-key"
+ },
+ "CopySourceSSECustomerKeyMD5":{
+ "shape":"CopySourceSSECustomerKeyMD5",
"documentation":"<p>Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. Amazon S3 uses this header for a message integrity check to ensure that the encryption key was transmitted without error.</p>",
- "location":"header",
- "locationName":"x-amz-copy-source-server-side-encryption-customer-key-MD5"
- },
- "RequestPayer":{
- "shape":"RequestPayer",
- "location":"header",
- "locationName":"x-amz-request-payer"
- },
- "Tagging":{
- "shape":"TaggingHeader",
+ "location":"header",
+ "locationName":"x-amz-copy-source-server-side-encryption-customer-key-MD5"
+ },
+ "RequestPayer":{
+ "shape":"RequestPayer",
+ "location":"header",
+ "locationName":"x-amz-request-payer"
+ },
+ "Tagging":{
+ "shape":"TaggingHeader",
"documentation":"<p>The tag-set for the object destination object this value must be used in conjunction with the <code>TaggingDirective</code>. The tag-set must be encoded as URL Query parameters.</p>",
- "location":"header",
- "locationName":"x-amz-tagging"
+ "location":"header",
+ "locationName":"x-amz-tagging"
},
"ObjectLockMode":{
"shape":"ObjectLockMode",
@@ -2085,12 +2085,12 @@
"documentation":"<p>The account ID of the expected source bucket owner. If the source bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-source-expected-bucket-owner"
- }
- }
- },
- "CopyObjectResult":{
- "type":"structure",
- "members":{
+ }
+ }
+ },
+ "CopyObjectResult":{
+ "type":"structure",
+ "members":{
"ETag":{
"shape":"ETag",
"documentation":"<p>Returns the ETag of the new object. The ETag reflects only changes to the contents of an object, not its metadata. The source and destination ETag is identical for a successfully copied non-multipart object.</p>"
@@ -2101,171 +2101,171 @@
}
},
"documentation":"<p>Container for all response elements.</p>"
- },
- "CopyPartResult":{
- "type":"structure",
- "members":{
- "ETag":{
- "shape":"ETag",
+ },
+ "CopyPartResult":{
+ "type":"structure",
+ "members":{
+ "ETag":{
+ "shape":"ETag",
"documentation":"<p>Entity tag of the object.</p>"
- },
- "LastModified":{
- "shape":"LastModified",
+ },
+ "LastModified":{
+ "shape":"LastModified",
"documentation":"<p>Date and time at which the object was uploaded.</p>"
- }
+ }
},
"documentation":"<p>Container for all response elements.</p>"
- },
- "CopySource":{
- "type":"string",
- "pattern":"\\/.+\\/.+"
- },
- "CopySourceIfMatch":{"type":"string"},
- "CopySourceIfModifiedSince":{"type":"timestamp"},
- "CopySourceIfNoneMatch":{"type":"string"},
- "CopySourceIfUnmodifiedSince":{"type":"timestamp"},
- "CopySourceRange":{"type":"string"},
- "CopySourceSSECustomerAlgorithm":{"type":"string"},
- "CopySourceSSECustomerKey":{
- "type":"string",
- "sensitive":true
- },
- "CopySourceSSECustomerKeyMD5":{"type":"string"},
- "CopySourceVersionId":{"type":"string"},
- "CreateBucketConfiguration":{
- "type":"structure",
- "members":{
- "LocationConstraint":{
- "shape":"BucketLocationConstraint",
+ },
+ "CopySource":{
+ "type":"string",
+ "pattern":"\\/.+\\/.+"
+ },
+ "CopySourceIfMatch":{"type":"string"},
+ "CopySourceIfModifiedSince":{"type":"timestamp"},
+ "CopySourceIfNoneMatch":{"type":"string"},
+ "CopySourceIfUnmodifiedSince":{"type":"timestamp"},
+ "CopySourceRange":{"type":"string"},
+ "CopySourceSSECustomerAlgorithm":{"type":"string"},
+ "CopySourceSSECustomerKey":{
+ "type":"string",
+ "sensitive":true
+ },
+ "CopySourceSSECustomerKeyMD5":{"type":"string"},
+ "CopySourceVersionId":{"type":"string"},
+ "CreateBucketConfiguration":{
+ "type":"structure",
+ "members":{
+ "LocationConstraint":{
+ "shape":"BucketLocationConstraint",
"documentation":"<p>Specifies the Region where the bucket will be created. If you don't specify a Region, the bucket is created in the US East (N. Virginia) Region (us-east-1).</p>"
- }
+ }
},
"documentation":"<p>The configuration information for the bucket.</p>"
- },
- "CreateBucketOutput":{
- "type":"structure",
- "members":{
- "Location":{
- "shape":"Location",
+ },
+ "CreateBucketOutput":{
+ "type":"structure",
+ "members":{
+ "Location":{
+ "shape":"Location",
"documentation":"<p>Specifies the Region where the bucket will be created. If you are creating a bucket on the US East (N. Virginia) Region (us-east-1), you do not need to specify the location.</p>",
- "location":"header",
- "locationName":"Location"
- }
- }
- },
- "CreateBucketRequest":{
- "type":"structure",
- "required":["Bucket"],
- "members":{
- "ACL":{
- "shape":"BucketCannedACL",
+ "location":"header",
+ "locationName":"Location"
+ }
+ }
+ },
+ "CreateBucketRequest":{
+ "type":"structure",
+ "required":["Bucket"],
+ "members":{
+ "ACL":{
+ "shape":"BucketCannedACL",
"documentation":"<p>The canned ACL to apply to the bucket.</p>",
- "location":"header",
- "locationName":"x-amz-acl"
- },
- "Bucket":{
- "shape":"BucketName",
+ "location":"header",
+ "locationName":"x-amz-acl"
+ },
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The name of the bucket to create.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "CreateBucketConfiguration":{
- "shape":"CreateBucketConfiguration",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "CreateBucketConfiguration":{
+ "shape":"CreateBucketConfiguration",
"documentation":"<p>The configuration information for the bucket.</p>",
- "locationName":"CreateBucketConfiguration",
- "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
- },
- "GrantFullControl":{
- "shape":"GrantFullControl",
+ "locationName":"CreateBucketConfiguration",
+ "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
+ },
+ "GrantFullControl":{
+ "shape":"GrantFullControl",
"documentation":"<p>Allows grantee the read, write, read ACP, and write ACP permissions on the bucket.</p>",
- "location":"header",
- "locationName":"x-amz-grant-full-control"
- },
- "GrantRead":{
- "shape":"GrantRead",
+ "location":"header",
+ "locationName":"x-amz-grant-full-control"
+ },
+ "GrantRead":{
+ "shape":"GrantRead",
"documentation":"<p>Allows grantee to list the objects in the bucket.</p>",
- "location":"header",
- "locationName":"x-amz-grant-read"
- },
- "GrantReadACP":{
- "shape":"GrantReadACP",
+ "location":"header",
+ "locationName":"x-amz-grant-read"
+ },
+ "GrantReadACP":{
+ "shape":"GrantReadACP",
"documentation":"<p>Allows grantee to read the bucket ACL.</p>",
- "location":"header",
- "locationName":"x-amz-grant-read-acp"
- },
- "GrantWrite":{
- "shape":"GrantWrite",
+ "location":"header",
+ "locationName":"x-amz-grant-read-acp"
+ },
+ "GrantWrite":{
+ "shape":"GrantWrite",
"documentation":"<p>Allows grantee to create new objects in the bucket.</p> <p>For the bucket and object owners of existing objects, also allows deletions and overwrites of those objects.</p>",
- "location":"header",
- "locationName":"x-amz-grant-write"
- },
- "GrantWriteACP":{
- "shape":"GrantWriteACP",
+ "location":"header",
+ "locationName":"x-amz-grant-write"
+ },
+ "GrantWriteACP":{
+ "shape":"GrantWriteACP",
"documentation":"<p>Allows grantee to write the ACL for the applicable bucket.</p>",
- "location":"header",
- "locationName":"x-amz-grant-write-acp"
+ "location":"header",
+ "locationName":"x-amz-grant-write-acp"
},
"ObjectLockEnabledForBucket":{
"shape":"ObjectLockEnabledForBucket",
"documentation":"<p>Specifies whether you want S3 Object Lock to be enabled for the new bucket.</p>",
"location":"header",
"locationName":"x-amz-bucket-object-lock-enabled"
- }
- },
- "payload":"CreateBucketConfiguration"
- },
- "CreateMultipartUploadOutput":{
- "type":"structure",
- "members":{
- "AbortDate":{
- "shape":"AbortDate",
+ }
+ },
+ "payload":"CreateBucketConfiguration"
+ },
+ "CreateMultipartUploadOutput":{
+ "type":"structure",
+ "members":{
+ "AbortDate":{
+ "shape":"AbortDate",
"documentation":"<p>If the bucket has a lifecycle rule configured with an action to abort incomplete multipart uploads and the prefix in the lifecycle rule matches the object name in the request, the response includes this header. The header indicates when the initiated multipart upload becomes eligible for an abort operation. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/mpuoverview.html#mpu-abort-incomplete-mpu-lifecycle-config\"> Aborting Incomplete Multipart Uploads Using a Bucket Lifecycle Policy</a>.</p> <p>The response also includes the <code>x-amz-abort-rule-id</code> header that provides the ID of the lifecycle configuration rule that defines this action.</p>",
- "location":"header",
- "locationName":"x-amz-abort-date"
- },
- "AbortRuleId":{
- "shape":"AbortRuleId",
+ "location":"header",
+ "locationName":"x-amz-abort-date"
+ },
+ "AbortRuleId":{
+ "shape":"AbortRuleId",
"documentation":"<p>This header is returned along with the <code>x-amz-abort-date</code> header. It identifies the applicable lifecycle configuration rule that defines the action to abort incomplete multipart uploads.</p>",
- "location":"header",
- "locationName":"x-amz-abort-rule-id"
- },
- "Bucket":{
- "shape":"BucketName",
+ "location":"header",
+ "locationName":"x-amz-abort-rule-id"
+ },
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The name of the bucket to which the multipart upload was initiated. </p> <p>When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.s3-accesspoint.<i>Region</i>.amazonaws.com. When using this action with an access point through the AWS SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\">Using access points</a> in the <i>Amazon S3 User Guide</i>.</p> <p>When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.<i>outpostID</i>.s3-outposts.<i>Region</i>.amazonaws.com. When using this action using S3 on Outposts through the AWS SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html\">Using S3 on Outposts</a> in the <i>Amazon S3 User Guide</i>.</p>",
- "locationName":"Bucket"
- },
- "Key":{
- "shape":"ObjectKey",
+ "locationName":"Bucket"
+ },
+ "Key":{
+ "shape":"ObjectKey",
"documentation":"<p>Object key for which the multipart upload was initiated.</p>"
- },
- "UploadId":{
- "shape":"MultipartUploadId",
+ },
+ "UploadId":{
+ "shape":"MultipartUploadId",
"documentation":"<p>ID for the initiated multipart upload.</p>"
- },
- "ServerSideEncryption":{
- "shape":"ServerSideEncryption",
+ },
+ "ServerSideEncryption":{
+ "shape":"ServerSideEncryption",
"documentation":"<p>The server-side encryption algorithm used when storing this object in Amazon S3 (for example, AES256, aws:kms).</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption"
- },
- "SSECustomerAlgorithm":{
- "shape":"SSECustomerAlgorithm",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption"
+ },
+ "SSECustomerAlgorithm":{
+ "shape":"SSECustomerAlgorithm",
"documentation":"<p>If server-side encryption with a customer-provided encryption key was requested, the response will include this header confirming the encryption algorithm used.</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-customer-algorithm"
- },
- "SSECustomerKeyMD5":{
- "shape":"SSECustomerKeyMD5",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-customer-algorithm"
+ },
+ "SSECustomerKeyMD5":{
+ "shape":"SSECustomerKeyMD5",
"documentation":"<p>If server-side encryption with a customer-provided encryption key was requested, the response will include this header to provide round-trip message integrity verification of the customer-provided encryption key.</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-customer-key-MD5"
- },
- "SSEKMSKeyId":{
- "shape":"SSEKMSKeyId",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-customer-key-MD5"
+ },
+ "SSEKMSKeyId":{
+ "shape":"SSEKMSKeyId",
"documentation":"<p>If present, specifies the ID of the AWS Key Management Service (AWS KMS) symmetric customer managed customer master key (CMK) that was used for the object.</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-aws-kms-key-id"
- },
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-aws-kms-key-id"
+ },
"SSEKMSEncryptionContext":{
"shape":"SSEKMSEncryptionContext",
"documentation":"<p>If present, specifies the AWS KMS Encryption Context to use for object encryption. The value of this header is a base64-encoded UTF-8 string holding JSON with the encryption context key-value pairs.</p>",
@@ -2278,146 +2278,146 @@
"location":"header",
"locationName":"x-amz-server-side-encryption-bucket-key-enabled"
},
- "RequestCharged":{
- "shape":"RequestCharged",
- "location":"header",
- "locationName":"x-amz-request-charged"
- }
- }
- },
- "CreateMultipartUploadRequest":{
- "type":"structure",
- "required":[
- "Bucket",
- "Key"
- ],
- "members":{
- "ACL":{
- "shape":"ObjectCannedACL",
+ "RequestCharged":{
+ "shape":"RequestCharged",
+ "location":"header",
+ "locationName":"x-amz-request-charged"
+ }
+ }
+ },
+ "CreateMultipartUploadRequest":{
+ "type":"structure",
+ "required":[
+ "Bucket",
+ "Key"
+ ],
+ "members":{
+ "ACL":{
+ "shape":"ObjectCannedACL",
"documentation":"<p>The canned ACL to apply to the object.</p> <p>This action is not supported by Amazon S3 on Outposts.</p>",
- "location":"header",
- "locationName":"x-amz-acl"
- },
- "Bucket":{
- "shape":"BucketName",
+ "location":"header",
+ "locationName":"x-amz-acl"
+ },
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The name of the bucket to which to initiate the upload</p> <p>When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.s3-accesspoint.<i>Region</i>.amazonaws.com. When using this action with an access point through the AWS SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\">Using access points</a> in the <i>Amazon S3 User Guide</i>.</p> <p>When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.<i>outpostID</i>.s3-outposts.<i>Region</i>.amazonaws.com. When using this action using S3 on Outposts through the AWS SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html\">Using S3 on Outposts</a> in the <i>Amazon S3 User Guide</i>.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "CacheControl":{
- "shape":"CacheControl",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "CacheControl":{
+ "shape":"CacheControl",
"documentation":"<p>Specifies caching behavior along the request/reply chain.</p>",
- "location":"header",
- "locationName":"Cache-Control"
- },
- "ContentDisposition":{
- "shape":"ContentDisposition",
+ "location":"header",
+ "locationName":"Cache-Control"
+ },
+ "ContentDisposition":{
+ "shape":"ContentDisposition",
"documentation":"<p>Specifies presentational information for the object.</p>",
- "location":"header",
- "locationName":"Content-Disposition"
- },
- "ContentEncoding":{
- "shape":"ContentEncoding",
+ "location":"header",
+ "locationName":"Content-Disposition"
+ },
+ "ContentEncoding":{
+ "shape":"ContentEncoding",
"documentation":"<p>Specifies what content encodings have been applied to the object and thus what decoding mechanisms must be applied to obtain the media-type referenced by the Content-Type header field.</p>",
- "location":"header",
- "locationName":"Content-Encoding"
- },
- "ContentLanguage":{
- "shape":"ContentLanguage",
+ "location":"header",
+ "locationName":"Content-Encoding"
+ },
+ "ContentLanguage":{
+ "shape":"ContentLanguage",
"documentation":"<p>The language the content is in.</p>",
- "location":"header",
- "locationName":"Content-Language"
- },
- "ContentType":{
- "shape":"ContentType",
+ "location":"header",
+ "locationName":"Content-Language"
+ },
+ "ContentType":{
+ "shape":"ContentType",
"documentation":"<p>A standard MIME type describing the format of the object data.</p>",
- "location":"header",
- "locationName":"Content-Type"
- },
- "Expires":{
- "shape":"Expires",
+ "location":"header",
+ "locationName":"Content-Type"
+ },
+ "Expires":{
+ "shape":"Expires",
"documentation":"<p>The date and time at which the object is no longer cacheable.</p>",
- "location":"header",
- "locationName":"Expires"
- },
- "GrantFullControl":{
- "shape":"GrantFullControl",
+ "location":"header",
+ "locationName":"Expires"
+ },
+ "GrantFullControl":{
+ "shape":"GrantFullControl",
"documentation":"<p>Gives the grantee READ, READ_ACP, and WRITE_ACP permissions on the object.</p> <p>This action is not supported by Amazon S3 on Outposts.</p>",
- "location":"header",
- "locationName":"x-amz-grant-full-control"
- },
- "GrantRead":{
- "shape":"GrantRead",
+ "location":"header",
+ "locationName":"x-amz-grant-full-control"
+ },
+ "GrantRead":{
+ "shape":"GrantRead",
"documentation":"<p>Allows grantee to read the object data and its metadata.</p> <p>This action is not supported by Amazon S3 on Outposts.</p>",
- "location":"header",
- "locationName":"x-amz-grant-read"
- },
- "GrantReadACP":{
- "shape":"GrantReadACP",
+ "location":"header",
+ "locationName":"x-amz-grant-read"
+ },
+ "GrantReadACP":{
+ "shape":"GrantReadACP",
"documentation":"<p>Allows grantee to read the object ACL.</p> <p>This action is not supported by Amazon S3 on Outposts.</p>",
- "location":"header",
- "locationName":"x-amz-grant-read-acp"
- },
- "GrantWriteACP":{
- "shape":"GrantWriteACP",
+ "location":"header",
+ "locationName":"x-amz-grant-read-acp"
+ },
+ "GrantWriteACP":{
+ "shape":"GrantWriteACP",
"documentation":"<p>Allows grantee to write the ACL for the applicable object.</p> <p>This action is not supported by Amazon S3 on Outposts.</p>",
- "location":"header",
- "locationName":"x-amz-grant-write-acp"
- },
- "Key":{
- "shape":"ObjectKey",
+ "location":"header",
+ "locationName":"x-amz-grant-write-acp"
+ },
+ "Key":{
+ "shape":"ObjectKey",
"documentation":"<p>Object key for which the multipart upload is to be initiated.</p>",
- "location":"uri",
- "locationName":"Key"
- },
- "Metadata":{
- "shape":"Metadata",
+ "location":"uri",
+ "locationName":"Key"
+ },
+ "Metadata":{
+ "shape":"Metadata",
"documentation":"<p>A map of metadata to store with the object in S3.</p>",
- "location":"headers",
- "locationName":"x-amz-meta-"
- },
- "ServerSideEncryption":{
- "shape":"ServerSideEncryption",
+ "location":"headers",
+ "locationName":"x-amz-meta-"
+ },
+ "ServerSideEncryption":{
+ "shape":"ServerSideEncryption",
"documentation":"<p>The server-side encryption algorithm used when storing this object in Amazon S3 (for example, AES256, aws:kms).</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption"
- },
- "StorageClass":{
- "shape":"StorageClass",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption"
+ },
+ "StorageClass":{
+ "shape":"StorageClass",
"documentation":"<p>By default, Amazon S3 uses the STANDARD Storage Class to store newly created objects. The STANDARD storage class provides high durability and high availability. Depending on performance needs, you can specify a different Storage Class. Amazon S3 on Outposts only uses the OUTPOSTS Storage Class. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/storage-class-intro.html\">Storage Classes</a> in the <i>Amazon S3 User Guide</i>.</p>",
- "location":"header",
- "locationName":"x-amz-storage-class"
- },
- "WebsiteRedirectLocation":{
- "shape":"WebsiteRedirectLocation",
+ "location":"header",
+ "locationName":"x-amz-storage-class"
+ },
+ "WebsiteRedirectLocation":{
+ "shape":"WebsiteRedirectLocation",
"documentation":"<p>If the bucket is configured as a website, redirects requests for this object to another object in the same bucket or to an external URL. Amazon S3 stores the value of this header in the object metadata.</p>",
- "location":"header",
- "locationName":"x-amz-website-redirect-location"
- },
- "SSECustomerAlgorithm":{
- "shape":"SSECustomerAlgorithm",
+ "location":"header",
+ "locationName":"x-amz-website-redirect-location"
+ },
+ "SSECustomerAlgorithm":{
+ "shape":"SSECustomerAlgorithm",
"documentation":"<p>Specifies the algorithm to use to when encrypting the object (for example, AES256).</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-customer-algorithm"
- },
- "SSECustomerKey":{
- "shape":"SSECustomerKey",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-customer-algorithm"
+ },
+ "SSECustomerKey":{
+ "shape":"SSECustomerKey",
"documentation":"<p>Specifies the customer-provided encryption key for Amazon S3 to use in encrypting data. This value is used to store the object and then it is discarded; Amazon S3 does not store the encryption key. The key must be appropriate for use with the algorithm specified in the <code>x-amz-server-side-encryption-customer-algorithm</code> header.</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-customer-key"
- },
- "SSECustomerKeyMD5":{
- "shape":"SSECustomerKeyMD5",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-customer-key"
+ },
+ "SSECustomerKeyMD5":{
+ "shape":"SSECustomerKeyMD5",
"documentation":"<p>Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. Amazon S3 uses this header for a message integrity check to ensure that the encryption key was transmitted without error.</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-customer-key-MD5"
- },
- "SSEKMSKeyId":{
- "shape":"SSEKMSKeyId",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-customer-key-MD5"
+ },
+ "SSEKMSKeyId":{
+ "shape":"SSEKMSKeyId",
"documentation":"<p>Specifies the ID of the symmetric customer managed AWS KMS CMK to use for object encryption. All GET and PUT requests for an object protected by AWS KMS will fail if not made via SSL or using SigV4. For information about configuring using any of the officially supported AWS SDKs and AWS CLI, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingAWSSDK.html#specify-signature-version\">Specifying the Signature Version in Request Authentication</a> in the <i>Amazon S3 User Guide</i>.</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-aws-kms-key-id"
- },
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-aws-kms-key-id"
+ },
"SSEKMSEncryptionContext":{
"shape":"SSEKMSEncryptionContext",
"documentation":"<p>Specifies the AWS KMS Encryption Context to use for object encryption. The value of this header is a base64-encoded UTF-8 string holding JSON with the encryption context key-value pairs.</p>",
@@ -2430,16 +2430,16 @@
"location":"header",
"locationName":"x-amz-server-side-encryption-bucket-key-enabled"
},
- "RequestPayer":{
- "shape":"RequestPayer",
- "location":"header",
- "locationName":"x-amz-request-payer"
- },
- "Tagging":{
- "shape":"TaggingHeader",
+ "RequestPayer":{
+ "shape":"RequestPayer",
+ "location":"header",
+ "locationName":"x-amz-request-payer"
+ },
+ "Tagging":{
+ "shape":"TaggingHeader",
"documentation":"<p>The tag-set for the object. The tag-set must be encoded as URL Query parameters.</p>",
- "location":"header",
- "locationName":"x-amz-tagging"
+ "location":"header",
+ "locationName":"x-amz-tagging"
},
"ObjectLockMode":{
"shape":"ObjectLockMode",
@@ -2464,16 +2464,16 @@
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
- "CreationDate":{"type":"timestamp"},
- "Date":{
- "type":"timestamp",
- "timestampFormat":"iso8601"
- },
- "Days":{"type":"integer"},
- "DaysAfterInitiation":{"type":"integer"},
+ }
+ }
+ },
+ "CreationDate":{"type":"timestamp"},
+ "Date":{
+ "type":"timestamp",
+ "timestampFormat":"iso8601"
+ },
+ "Days":{"type":"integer"},
+ "DaysAfterInitiation":{"type":"integer"},
"DefaultRetention":{
"type":"structure",
"members":{
@@ -2492,85 +2492,85 @@
},
"documentation":"<p>The container element for specifying the default Object Lock retention settings for new objects placed in the specified bucket.</p> <note> <ul> <li> <p>The <code>DefaultRetention</code> settings require both a mode and a period.</p> </li> <li> <p>The <code>DefaultRetention</code> period can be either <code>Days</code> or <code>Years</code> but you must select one. You cannot specify <code>Days</code> and <code>Years</code> at the same time.</p> </li> </ul> </note>"
},
- "Delete":{
- "type":"structure",
- "required":["Objects"],
- "members":{
- "Objects":{
- "shape":"ObjectIdentifierList",
+ "Delete":{
+ "type":"structure",
+ "required":["Objects"],
+ "members":{
+ "Objects":{
+ "shape":"ObjectIdentifierList",
"documentation":"<p>The objects to delete.</p>",
- "locationName":"Object"
- },
- "Quiet":{
- "shape":"Quiet",
+ "locationName":"Object"
+ },
+ "Quiet":{
+ "shape":"Quiet",
"documentation":"<p>Element to enable quiet mode for the request. When you add this element, you must set its value to true.</p>"
- }
+ }
},
"documentation":"<p>Container for the objects to delete.</p>"
- },
- "DeleteBucketAnalyticsConfigurationRequest":{
- "type":"structure",
- "required":[
- "Bucket",
- "Id"
- ],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ },
+ "DeleteBucketAnalyticsConfigurationRequest":{
+ "type":"structure",
+ "required":[
+ "Bucket",
+ "Id"
+ ],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The name of the bucket from which an analytics configuration is deleted.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "Id":{
- "shape":"AnalyticsId",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "Id":{
+ "shape":"AnalyticsId",
"documentation":"<p>The ID that identifies the analytics configuration.</p>",
- "location":"querystring",
- "locationName":"id"
+ "location":"querystring",
+ "locationName":"id"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
- "DeleteBucketCorsRequest":{
- "type":"structure",
- "required":["Bucket"],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ }
+ }
+ },
+ "DeleteBucketCorsRequest":{
+ "type":"structure",
+ "required":["Bucket"],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>Specifies the bucket whose <code>cors</code> configuration is being deleted.</p>",
- "location":"uri",
- "locationName":"Bucket"
+ "location":"uri",
+ "locationName":"Bucket"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
- "DeleteBucketEncryptionRequest":{
- "type":"structure",
- "required":["Bucket"],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ }
+ }
+ },
+ "DeleteBucketEncryptionRequest":{
+ "type":"structure",
+ "required":["Bucket"],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The name of the bucket containing the server-side encryption configuration to delete.</p>",
- "location":"uri",
- "locationName":"Bucket"
+ "location":"uri",
+ "locationName":"Bucket"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
+ }
+ }
+ },
"DeleteBucketIntelligentTieringConfigurationRequest":{
"type":"structure",
"required":[
@@ -2592,78 +2592,78 @@
}
}
},
- "DeleteBucketInventoryConfigurationRequest":{
- "type":"structure",
- "required":[
- "Bucket",
- "Id"
- ],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ "DeleteBucketInventoryConfigurationRequest":{
+ "type":"structure",
+ "required":[
+ "Bucket",
+ "Id"
+ ],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The name of the bucket containing the inventory configuration to delete.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "Id":{
- "shape":"InventoryId",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "Id":{
+ "shape":"InventoryId",
"documentation":"<p>The ID used to identify the inventory configuration.</p>",
- "location":"querystring",
- "locationName":"id"
+ "location":"querystring",
+ "locationName":"id"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
- "DeleteBucketLifecycleRequest":{
- "type":"structure",
- "required":["Bucket"],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ }
+ }
+ },
+ "DeleteBucketLifecycleRequest":{
+ "type":"structure",
+ "required":["Bucket"],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The bucket name of the lifecycle to delete.</p>",
- "location":"uri",
- "locationName":"Bucket"
+ "location":"uri",
+ "locationName":"Bucket"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
- "DeleteBucketMetricsConfigurationRequest":{
- "type":"structure",
- "required":[
- "Bucket",
- "Id"
- ],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ }
+ }
+ },
+ "DeleteBucketMetricsConfigurationRequest":{
+ "type":"structure",
+ "required":[
+ "Bucket",
+ "Id"
+ ],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The name of the bucket containing the metrics configuration to delete.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "Id":{
- "shape":"MetricsId",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "Id":{
+ "shape":"MetricsId",
"documentation":"<p>The ID used to identify the metrics configuration.</p>",
- "location":"querystring",
- "locationName":"id"
+ "location":"querystring",
+ "locationName":"id"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
+ }
+ }
+ },
"DeleteBucketOwnershipControlsRequest":{
"type":"structure",
"required":["Bucket"],
@@ -2682,123 +2682,123 @@
}
}
},
- "DeleteBucketPolicyRequest":{
- "type":"structure",
- "required":["Bucket"],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ "DeleteBucketPolicyRequest":{
+ "type":"structure",
+ "required":["Bucket"],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The bucket name.</p>",
- "location":"uri",
- "locationName":"Bucket"
+ "location":"uri",
+ "locationName":"Bucket"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
- "DeleteBucketReplicationRequest":{
- "type":"structure",
- "required":["Bucket"],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ }
+ }
+ },
+ "DeleteBucketReplicationRequest":{
+ "type":"structure",
+ "required":["Bucket"],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p> The bucket name. </p>",
- "location":"uri",
- "locationName":"Bucket"
+ "location":"uri",
+ "locationName":"Bucket"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
- "DeleteBucketRequest":{
- "type":"structure",
- "required":["Bucket"],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ }
+ }
+ },
+ "DeleteBucketRequest":{
+ "type":"structure",
+ "required":["Bucket"],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>Specifies the bucket being deleted.</p>",
- "location":"uri",
- "locationName":"Bucket"
+ "location":"uri",
+ "locationName":"Bucket"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
- "DeleteBucketTaggingRequest":{
- "type":"structure",
- "required":["Bucket"],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ }
+ }
+ },
+ "DeleteBucketTaggingRequest":{
+ "type":"structure",
+ "required":["Bucket"],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The bucket that has the tag set to be removed.</p>",
- "location":"uri",
- "locationName":"Bucket"
+ "location":"uri",
+ "locationName":"Bucket"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
- "DeleteBucketWebsiteRequest":{
- "type":"structure",
- "required":["Bucket"],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ }
+ }
+ },
+ "DeleteBucketWebsiteRequest":{
+ "type":"structure",
+ "required":["Bucket"],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The bucket name for which you want to remove the website configuration. </p>",
- "location":"uri",
- "locationName":"Bucket"
+ "location":"uri",
+ "locationName":"Bucket"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
- "DeleteMarker":{"type":"boolean"},
- "DeleteMarkerEntry":{
- "type":"structure",
- "members":{
+ }
+ }
+ },
+ "DeleteMarker":{"type":"boolean"},
+ "DeleteMarkerEntry":{
+ "type":"structure",
+ "members":{
"Owner":{
"shape":"Owner",
"documentation":"<p>The account that created the delete marker.&gt;</p>"
},
- "Key":{
- "shape":"ObjectKey",
+ "Key":{
+ "shape":"ObjectKey",
"documentation":"<p>The object key.</p>"
- },
- "VersionId":{
- "shape":"ObjectVersionId",
+ },
+ "VersionId":{
+ "shape":"ObjectVersionId",
"documentation":"<p>Version ID of an object.</p>"
- },
- "IsLatest":{
- "shape":"IsLatest",
+ },
+ "IsLatest":{
+ "shape":"IsLatest",
"documentation":"<p>Specifies whether the object is (true) or is not (false) the latest version of an object.</p>"
- },
- "LastModified":{
- "shape":"LastModified",
+ },
+ "LastModified":{
+ "shape":"LastModified",
"documentation":"<p>Date and time the object was last modified.</p>"
- }
+ }
},
"documentation":"<p>Information about the delete marker.</p>"
- },
+ },
"DeleteMarkerReplication":{
"type":"structure",
"members":{
@@ -2816,69 +2816,69 @@
"Disabled"
]
},
- "DeleteMarkerVersionId":{"type":"string"},
- "DeleteMarkers":{
- "type":"list",
- "member":{"shape":"DeleteMarkerEntry"},
- "flattened":true
- },
- "DeleteObjectOutput":{
- "type":"structure",
- "members":{
- "DeleteMarker":{
- "shape":"DeleteMarker",
+ "DeleteMarkerVersionId":{"type":"string"},
+ "DeleteMarkers":{
+ "type":"list",
+ "member":{"shape":"DeleteMarkerEntry"},
+ "flattened":true
+ },
+ "DeleteObjectOutput":{
+ "type":"structure",
+ "members":{
+ "DeleteMarker":{
+ "shape":"DeleteMarker",
"documentation":"<p>Specifies whether the versioned object that was permanently deleted was (true) or was not (false) a delete marker.</p>",
- "location":"header",
- "locationName":"x-amz-delete-marker"
- },
- "VersionId":{
- "shape":"ObjectVersionId",
+ "location":"header",
+ "locationName":"x-amz-delete-marker"
+ },
+ "VersionId":{
+ "shape":"ObjectVersionId",
"documentation":"<p>Returns the version ID of the delete marker created as a result of the DELETE operation.</p>",
- "location":"header",
- "locationName":"x-amz-version-id"
- },
- "RequestCharged":{
- "shape":"RequestCharged",
- "location":"header",
- "locationName":"x-amz-request-charged"
- }
- }
- },
- "DeleteObjectRequest":{
- "type":"structure",
- "required":[
- "Bucket",
- "Key"
- ],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ "location":"header",
+ "locationName":"x-amz-version-id"
+ },
+ "RequestCharged":{
+ "shape":"RequestCharged",
+ "location":"header",
+ "locationName":"x-amz-request-charged"
+ }
+ }
+ },
+ "DeleteObjectRequest":{
+ "type":"structure",
+ "required":[
+ "Bucket",
+ "Key"
+ ],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The bucket name of the bucket containing the object. </p> <p>When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.s3-accesspoint.<i>Region</i>.amazonaws.com. When using this action with an access point through the AWS SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\">Using access points</a> in the <i>Amazon S3 User Guide</i>.</p> <p>When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.<i>outpostID</i>.s3-outposts.<i>Region</i>.amazonaws.com. When using this action using S3 on Outposts through the AWS SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html\">Using S3 on Outposts</a> in the <i>Amazon S3 User Guide</i>.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "Key":{
- "shape":"ObjectKey",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "Key":{
+ "shape":"ObjectKey",
"documentation":"<p>Key name of the object to delete.</p>",
- "location":"uri",
- "locationName":"Key"
- },
- "MFA":{
- "shape":"MFA",
+ "location":"uri",
+ "locationName":"Key"
+ },
+ "MFA":{
+ "shape":"MFA",
"documentation":"<p>The concatenation of the authentication device's serial number, a space, and the value that is displayed on your authentication device. Required to permanently delete a versioned object if versioning is configured with MFA delete enabled.</p>",
- "location":"header",
- "locationName":"x-amz-mfa"
- },
- "VersionId":{
- "shape":"ObjectVersionId",
+ "location":"header",
+ "locationName":"x-amz-mfa"
+ },
+ "VersionId":{
+ "shape":"ObjectVersionId",
"documentation":"<p>VersionId used to reference a specific version of the object.</p>",
- "location":"querystring",
- "locationName":"versionId"
- },
- "RequestPayer":{
- "shape":"RequestPayer",
- "location":"header",
- "locationName":"x-amz-request-payer"
+ "location":"querystring",
+ "locationName":"versionId"
+ },
+ "RequestPayer":{
+ "shape":"RequestPayer",
+ "location":"header",
+ "locationName":"x-amz-request-payer"
},
"BypassGovernanceRetention":{
"shape":"BypassGovernanceRetention",
@@ -2891,101 +2891,101 @@
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
- "DeleteObjectTaggingOutput":{
- "type":"structure",
- "members":{
- "VersionId":{
- "shape":"ObjectVersionId",
+ }
+ }
+ },
+ "DeleteObjectTaggingOutput":{
+ "type":"structure",
+ "members":{
+ "VersionId":{
+ "shape":"ObjectVersionId",
"documentation":"<p>The versionId of the object the tag-set was removed from.</p>",
- "location":"header",
- "locationName":"x-amz-version-id"
- }
- }
- },
- "DeleteObjectTaggingRequest":{
- "type":"structure",
- "required":[
- "Bucket",
- "Key"
- ],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ "location":"header",
+ "locationName":"x-amz-version-id"
+ }
+ }
+ },
+ "DeleteObjectTaggingRequest":{
+ "type":"structure",
+ "required":[
+ "Bucket",
+ "Key"
+ ],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The bucket name containing the objects from which to remove the tags. </p> <p>When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.s3-accesspoint.<i>Region</i>.amazonaws.com. When using this action with an access point through the AWS SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\">Using access points</a> in the <i>Amazon S3 User Guide</i>.</p> <p>When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.<i>outpostID</i>.s3-outposts.<i>Region</i>.amazonaws.com. When using this action using S3 on Outposts through the AWS SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html\">Using S3 on Outposts</a> in the <i>Amazon S3 User Guide</i>.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "Key":{
- "shape":"ObjectKey",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "Key":{
+ "shape":"ObjectKey",
"documentation":"<p>The key that identifies the object in the bucket from which to remove all tags.</p>",
- "location":"uri",
- "locationName":"Key"
- },
- "VersionId":{
- "shape":"ObjectVersionId",
+ "location":"uri",
+ "locationName":"Key"
+ },
+ "VersionId":{
+ "shape":"ObjectVersionId",
"documentation":"<p>The versionId of the object that the tag-set will be removed from.</p>",
- "location":"querystring",
- "locationName":"versionId"
+ "location":"querystring",
+ "locationName":"versionId"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
- "DeleteObjectsOutput":{
- "type":"structure",
- "members":{
+ }
+ }
+ },
+ "DeleteObjectsOutput":{
+ "type":"structure",
+ "members":{
"Deleted":{
"shape":"DeletedObjects",
"documentation":"<p>Container element for a successful delete. It identifies the object that was successfully deleted.</p>"
},
- "RequestCharged":{
- "shape":"RequestCharged",
- "location":"header",
- "locationName":"x-amz-request-charged"
- },
- "Errors":{
- "shape":"Errors",
+ "RequestCharged":{
+ "shape":"RequestCharged",
+ "location":"header",
+ "locationName":"x-amz-request-charged"
+ },
+ "Errors":{
+ "shape":"Errors",
"documentation":"<p>Container for a failed delete action that describes the object that Amazon S3 attempted to delete and the error it encountered.</p>",
- "locationName":"Error"
- }
- }
- },
- "DeleteObjectsRequest":{
- "type":"structure",
- "required":[
- "Bucket",
- "Delete"
- ],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ "locationName":"Error"
+ }
+ }
+ },
+ "DeleteObjectsRequest":{
+ "type":"structure",
+ "required":[
+ "Bucket",
+ "Delete"
+ ],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The bucket name containing the objects to delete. </p> <p>When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.s3-accesspoint.<i>Region</i>.amazonaws.com. When using this action with an access point through the AWS SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\">Using access points</a> in the <i>Amazon S3 User Guide</i>.</p> <p>When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.<i>outpostID</i>.s3-outposts.<i>Region</i>.amazonaws.com. When using this action using S3 on Outposts through the AWS SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html\">Using S3 on Outposts</a> in the <i>Amazon S3 User Guide</i>.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "Delete":{
- "shape":"Delete",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "Delete":{
+ "shape":"Delete",
"documentation":"<p>Container for the request.</p>",
- "locationName":"Delete",
- "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
- },
- "MFA":{
- "shape":"MFA",
+ "locationName":"Delete",
+ "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
+ },
+ "MFA":{
+ "shape":"MFA",
"documentation":"<p>The concatenation of the authentication device's serial number, a space, and the value that is displayed on your authentication device. Required to permanently delete a versioned object if versioning is configured with MFA delete enabled.</p>",
- "location":"header",
- "locationName":"x-amz-mfa"
- },
- "RequestPayer":{
- "shape":"RequestPayer",
- "location":"header",
- "locationName":"x-amz-request-payer"
+ "location":"header",
+ "locationName":"x-amz-mfa"
+ },
+ "RequestPayer":{
+ "shape":"RequestPayer",
+ "location":"header",
+ "locationName":"x-amz-request-payer"
},
"BypassGovernanceRetention":{
"shape":"BypassGovernanceRetention",
@@ -2998,14 +2998,14 @@
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- },
- "payload":"Delete"
- },
+ }
+ },
+ "payload":"Delete"
+ },
"DeletePublicAccessBlockRequest":{
- "type":"structure",
+ "type":"structure",
"required":["Bucket"],
- "members":{
+ "members":{
"Bucket":{
"shape":"BucketName",
"documentation":"<p>The Amazon S3 bucket whose <code>PublicAccessBlock</code> configuration you want to delete. </p>",
@@ -3018,8 +3018,8 @@
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
}
- }
- },
+ }
+ },
"DeletedObject":{
"type":"structure",
"members":{
@@ -3042,35 +3042,35 @@
},
"documentation":"<p>Information about the deleted object.</p>"
},
- "DeletedObjects":{
- "type":"list",
- "member":{"shape":"DeletedObject"},
- "flattened":true
- },
- "Delimiter":{"type":"string"},
- "Description":{"type":"string"},
- "Destination":{
- "type":"structure",
- "required":["Bucket"],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ "DeletedObjects":{
+ "type":"list",
+ "member":{"shape":"DeletedObject"},
+ "flattened":true
+ },
+ "Delimiter":{"type":"string"},
+ "Description":{"type":"string"},
+ "Destination":{
+ "type":"structure",
+ "required":["Bucket"],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p> The Amazon Resource Name (ARN) of the bucket where you want Amazon S3 to store the results.</p>"
- },
- "Account":{
- "shape":"AccountId",
+ },
+ "Account":{
+ "shape":"AccountId",
"documentation":"<p>Destination bucket owner account ID. In a cross-account scenario, if you direct Amazon S3 to change replica ownership to the AWS account that owns the destination bucket by specifying the <code>AccessControlTranslation</code> property, this is the account ID of the destination bucket owner. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/replication-change-owner.html\">Replication Additional Configuration: Changing the Replica Owner</a> in the <i>Amazon S3 User Guide</i>.</p>"
- },
- "StorageClass":{
- "shape":"StorageClass",
+ },
+ "StorageClass":{
+ "shape":"StorageClass",
"documentation":"<p> The storage class to use when replicating objects, such as S3 Standard or reduced redundancy. By default, Amazon S3 uses the storage class of the source object to create the object replica. </p> <p>For valid values, see the <code>StorageClass</code> element of the <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketPUTreplication.html\">PUT Bucket replication</a> action in the <i>Amazon S3 API Reference</i>.</p>"
- },
- "AccessControlTranslation":{
- "shape":"AccessControlTranslation",
+ },
+ "AccessControlTranslation":{
+ "shape":"AccessControlTranslation",
"documentation":"<p>Specify this only in a cross-account scenario (where source and destination bucket owners are not the same), and you want to change replica ownership to the AWS account that owns the destination bucket. If this is not specified in the replication configuration, the replicas are owned by same AWS account that owns the source object.</p>"
- },
- "EncryptionConfiguration":{
- "shape":"EncryptionConfiguration",
+ },
+ "EncryptionConfiguration":{
+ "shape":"EncryptionConfiguration",
"documentation":"<p>A container that provides information about encryption. If <code>SourceSelectionCriteria</code> is specified, you must specify this element.</p>"
},
"ReplicationTime":{
@@ -3080,59 +3080,59 @@
"Metrics":{
"shape":"Metrics",
"documentation":"<p> A container specifying replication metrics-related settings enabling replication metrics and events. </p>"
- }
- },
+ }
+ },
"documentation":"<p>Specifies information about where to publish analysis or configuration results for an Amazon S3 bucket and S3 Replication Time Control (S3 RTC).</p>"
- },
- "DisplayName":{"type":"string"},
- "ETag":{"type":"string"},
- "EmailAddress":{"type":"string"},
- "EnableRequestProgress":{"type":"boolean"},
- "EncodingType":{
- "type":"string",
+ },
+ "DisplayName":{"type":"string"},
+ "ETag":{"type":"string"},
+ "EmailAddress":{"type":"string"},
+ "EnableRequestProgress":{"type":"boolean"},
+ "EncodingType":{
+ "type":"string",
"documentation":"<p>Requests Amazon S3 to encode the object keys in the response and specifies the encoding method to use. An object key may contain any Unicode character; however, XML 1.0 parser cannot parse some characters, such as characters with an ASCII value from 0 to 10. For characters that are not supported in XML 1.0, you can add this parameter to request that Amazon S3 encode the keys in the response.</p>",
- "enum":["url"]
- },
- "Encryption":{
- "type":"structure",
- "required":["EncryptionType"],
- "members":{
- "EncryptionType":{
- "shape":"ServerSideEncryption",
+ "enum":["url"]
+ },
+ "Encryption":{
+ "type":"structure",
+ "required":["EncryptionType"],
+ "members":{
+ "EncryptionType":{
+ "shape":"ServerSideEncryption",
"documentation":"<p>The server-side encryption algorithm used when storing job results in Amazon S3 (for example, AES256, aws:kms).</p>"
- },
- "KMSKeyId":{
- "shape":"SSEKMSKeyId",
+ },
+ "KMSKeyId":{
+ "shape":"SSEKMSKeyId",
"documentation":"<p>If the encryption type is <code>aws:kms</code>, this optional value specifies the ID of the symmetric customer managed AWS KMS CMK to use for encryption of job results. Amazon S3 only supports symmetric CMKs. For more information, see <a href=\"https://docs.aws.amazon.com/kms/latest/developerguide/symmetric-asymmetric.html\">Using symmetric and asymmetric keys</a> in the <i>AWS Key Management Service Developer Guide</i>.</p>"
- },
- "KMSContext":{
- "shape":"KMSContext",
+ },
+ "KMSContext":{
+ "shape":"KMSContext",
"documentation":"<p>If the encryption type is <code>aws:kms</code>, this optional value can be used to specify the encryption context for the restore results.</p>"
- }
- },
+ }
+ },
"documentation":"<p>Contains the type of server-side encryption used.</p>"
- },
- "EncryptionConfiguration":{
- "type":"structure",
- "members":{
- "ReplicaKmsKeyID":{
- "shape":"ReplicaKmsKeyID",
+ },
+ "EncryptionConfiguration":{
+ "type":"structure",
+ "members":{
+ "ReplicaKmsKeyID":{
+ "shape":"ReplicaKmsKeyID",
"documentation":"<p>Specifies the ID (Key ARN or Alias ARN) of the customer managed AWS KMS key stored in AWS Key Management Service (KMS) for the destination bucket. Amazon S3 uses this key to encrypt replica objects. Amazon S3 only supports symmetric, customer managed KMS keys. For more information, see <a href=\"https://docs.aws.amazon.com/kms/latest/developerguide/symmetric-asymmetric.html\">Using symmetric and asymmetric keys</a> in the <i>AWS Key Management Service Developer Guide</i>.</p>"
- }
- },
+ }
+ },
"documentation":"<p>Specifies encryption-related information for an Amazon S3 bucket that is a destination for replicated objects.</p>"
- },
+ },
"End":{"type":"long"},
- "EndEvent":{
- "type":"structure",
- "members":{
- },
+ "EndEvent":{
+ "type":"structure",
+ "members":{
+ },
"documentation":"<p>A message that indicates the request is complete and no more messages will be sent. You should not assume that the request is complete until the client receives an <code>EndEvent</code>.</p>",
- "event":true
- },
- "Error":{
- "type":"structure",
- "members":{
+ "event":true
+ },
+ "Error":{
+ "type":"structure",
+ "members":{
"Key":{
"shape":"ObjectKey",
"documentation":"<p>The error key.</p>"
@@ -3151,37 +3151,37 @@
}
},
"documentation":"<p>Container for all error elements.</p>"
- },
+ },
"ErrorCode":{"type":"string"},
- "ErrorDocument":{
- "type":"structure",
- "required":["Key"],
- "members":{
- "Key":{
- "shape":"ObjectKey",
+ "ErrorDocument":{
+ "type":"structure",
+ "required":["Key"],
+ "members":{
+ "Key":{
+ "shape":"ObjectKey",
"documentation":"<p>The object key name to use when a 4XX class error occurs.</p> <important> <p>Replacement must be made for object keys containing special characters (such as carriage returns) when using XML requests. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-keys.html#object-key-xml-related-constraints\"> XML related object key constraints</a>.</p> </important>"
- }
+ }
},
"documentation":"<p>The error information.</p>"
- },
+ },
"ErrorMessage":{"type":"string"},
- "Errors":{
- "type":"list",
- "member":{"shape":"Error"},
- "flattened":true
- },
- "Event":{
- "type":"string",
+ "Errors":{
+ "type":"list",
+ "member":{"shape":"Error"},
+ "flattened":true
+ },
+ "Event":{
+ "type":"string",
"documentation":"<p>The bucket event for which to send notifications.</p>",
- "enum":[
- "s3:ReducedRedundancyLostObject",
- "s3:ObjectCreated:*",
- "s3:ObjectCreated:Put",
- "s3:ObjectCreated:Post",
- "s3:ObjectCreated:Copy",
- "s3:ObjectCreated:CompleteMultipartUpload",
- "s3:ObjectRemoved:*",
- "s3:ObjectRemoved:Delete",
+ "enum":[
+ "s3:ReducedRedundancyLostObject",
+ "s3:ObjectCreated:*",
+ "s3:ObjectCreated:Put",
+ "s3:ObjectCreated:Post",
+ "s3:ObjectCreated:Copy",
+ "s3:ObjectCreated:CompleteMultipartUpload",
+ "s3:ObjectRemoved:*",
+ "s3:ObjectRemoved:Delete",
"s3:ObjectRemoved:DeleteMarkerCreated",
"s3:ObjectRestore:*",
"s3:ObjectRestore:Post",
@@ -3191,13 +3191,13 @@
"s3:Replication:OperationNotTracked",
"s3:Replication:OperationMissedThreshold",
"s3:Replication:OperationReplicatedAfterThreshold"
- ]
- },
- "EventList":{
- "type":"list",
- "member":{"shape":"Event"},
- "flattened":true
- },
+ ]
+ },
+ "EventList":{
+ "type":"list",
+ "member":{"shape":"Event"},
+ "flattened":true
+ },
"ExistingObjectReplication":{
"type":"structure",
"required":["Status"],
@@ -3216,214 +3216,214 @@
"Disabled"
]
},
- "Expiration":{"type":"string"},
- "ExpirationStatus":{
- "type":"string",
- "enum":[
- "Enabled",
- "Disabled"
- ]
- },
- "ExpiredObjectDeleteMarker":{"type":"boolean"},
- "Expires":{"type":"timestamp"},
- "ExposeHeader":{"type":"string"},
- "ExposeHeaders":{
- "type":"list",
- "member":{"shape":"ExposeHeader"},
- "flattened":true
- },
- "Expression":{"type":"string"},
- "ExpressionType":{
- "type":"string",
- "enum":["SQL"]
- },
- "FetchOwner":{"type":"boolean"},
- "FieldDelimiter":{"type":"string"},
- "FileHeaderInfo":{
- "type":"string",
- "enum":[
- "USE",
- "IGNORE",
- "NONE"
- ]
- },
- "FilterRule":{
- "type":"structure",
- "members":{
- "Name":{
- "shape":"FilterRuleName",
+ "Expiration":{"type":"string"},
+ "ExpirationStatus":{
+ "type":"string",
+ "enum":[
+ "Enabled",
+ "Disabled"
+ ]
+ },
+ "ExpiredObjectDeleteMarker":{"type":"boolean"},
+ "Expires":{"type":"timestamp"},
+ "ExposeHeader":{"type":"string"},
+ "ExposeHeaders":{
+ "type":"list",
+ "member":{"shape":"ExposeHeader"},
+ "flattened":true
+ },
+ "Expression":{"type":"string"},
+ "ExpressionType":{
+ "type":"string",
+ "enum":["SQL"]
+ },
+ "FetchOwner":{"type":"boolean"},
+ "FieldDelimiter":{"type":"string"},
+ "FileHeaderInfo":{
+ "type":"string",
+ "enum":[
+ "USE",
+ "IGNORE",
+ "NONE"
+ ]
+ },
+ "FilterRule":{
+ "type":"structure",
+ "members":{
+ "Name":{
+ "shape":"FilterRuleName",
"documentation":"<p>The object key name prefix or suffix identifying one or more objects to which the filtering rule applies. The maximum length is 1,024 characters. Overlapping prefixes and suffixes are not supported. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/NotificationHowTo.html\">Configuring Event Notifications</a> in the <i>Amazon S3 User Guide</i>.</p>"
- },
+ },
"Value":{
"shape":"FilterRuleValue",
"documentation":"<p>The value that the filter searches for in object key names.</p>"
}
- },
+ },
"documentation":"<p>Specifies the Amazon S3 object key name to filter on and whether to filter on the suffix or prefix of the key name.</p>"
- },
- "FilterRuleList":{
- "type":"list",
- "member":{"shape":"FilterRule"},
+ },
+ "FilterRuleList":{
+ "type":"list",
+ "member":{"shape":"FilterRule"},
"documentation":"<p>A list of containers for the key-value pair that defines the criteria for the filter rule.</p>",
- "flattened":true
- },
- "FilterRuleName":{
- "type":"string",
- "enum":[
- "prefix",
- "suffix"
- ]
- },
- "FilterRuleValue":{"type":"string"},
- "GetBucketAccelerateConfigurationOutput":{
- "type":"structure",
- "members":{
- "Status":{
- "shape":"BucketAccelerateStatus",
+ "flattened":true
+ },
+ "FilterRuleName":{
+ "type":"string",
+ "enum":[
+ "prefix",
+ "suffix"
+ ]
+ },
+ "FilterRuleValue":{"type":"string"},
+ "GetBucketAccelerateConfigurationOutput":{
+ "type":"structure",
+ "members":{
+ "Status":{
+ "shape":"BucketAccelerateStatus",
"documentation":"<p>The accelerate configuration of the bucket.</p>"
- }
- }
- },
- "GetBucketAccelerateConfigurationRequest":{
- "type":"structure",
- "required":["Bucket"],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ }
+ }
+ },
+ "GetBucketAccelerateConfigurationRequest":{
+ "type":"structure",
+ "required":["Bucket"],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The name of the bucket for which the accelerate configuration is retrieved.</p>",
- "location":"uri",
- "locationName":"Bucket"
+ "location":"uri",
+ "locationName":"Bucket"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
- "GetBucketAclOutput":{
- "type":"structure",
- "members":{
+ }
+ }
+ },
+ "GetBucketAclOutput":{
+ "type":"structure",
+ "members":{
"Owner":{
"shape":"Owner",
"documentation":"<p>Container for the bucket owner's display name and ID.</p>"
},
- "Grants":{
- "shape":"Grants",
+ "Grants":{
+ "shape":"Grants",
"documentation":"<p>A list of grants.</p>",
- "locationName":"AccessControlList"
- }
- }
- },
- "GetBucketAclRequest":{
- "type":"structure",
- "required":["Bucket"],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ "locationName":"AccessControlList"
+ }
+ }
+ },
+ "GetBucketAclRequest":{
+ "type":"structure",
+ "required":["Bucket"],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>Specifies the S3 bucket whose ACL is being requested.</p>",
- "location":"uri",
- "locationName":"Bucket"
+ "location":"uri",
+ "locationName":"Bucket"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
- "GetBucketAnalyticsConfigurationOutput":{
- "type":"structure",
- "members":{
- "AnalyticsConfiguration":{
- "shape":"AnalyticsConfiguration",
+ }
+ }
+ },
+ "GetBucketAnalyticsConfigurationOutput":{
+ "type":"structure",
+ "members":{
+ "AnalyticsConfiguration":{
+ "shape":"AnalyticsConfiguration",
"documentation":"<p>The configuration and any analyses for the analytics filter.</p>"
- }
- },
- "payload":"AnalyticsConfiguration"
- },
- "GetBucketAnalyticsConfigurationRequest":{
- "type":"structure",
- "required":[
- "Bucket",
- "Id"
- ],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ }
+ },
+ "payload":"AnalyticsConfiguration"
+ },
+ "GetBucketAnalyticsConfigurationRequest":{
+ "type":"structure",
+ "required":[
+ "Bucket",
+ "Id"
+ ],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The name of the bucket from which an analytics configuration is retrieved.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "Id":{
- "shape":"AnalyticsId",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "Id":{
+ "shape":"AnalyticsId",
"documentation":"<p>The ID that identifies the analytics configuration.</p>",
- "location":"querystring",
- "locationName":"id"
+ "location":"querystring",
+ "locationName":"id"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
- "GetBucketCorsOutput":{
- "type":"structure",
- "members":{
- "CORSRules":{
- "shape":"CORSRules",
+ }
+ }
+ },
+ "GetBucketCorsOutput":{
+ "type":"structure",
+ "members":{
+ "CORSRules":{
+ "shape":"CORSRules",
"documentation":"<p>A set of origins and methods (cross-origin access that you want to allow). You can add up to 100 rules to the configuration.</p>",
- "locationName":"CORSRule"
- }
- }
- },
- "GetBucketCorsRequest":{
- "type":"structure",
- "required":["Bucket"],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ "locationName":"CORSRule"
+ }
+ }
+ },
+ "GetBucketCorsRequest":{
+ "type":"structure",
+ "required":["Bucket"],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The bucket name for which to get the cors configuration.</p>",
- "location":"uri",
- "locationName":"Bucket"
+ "location":"uri",
+ "locationName":"Bucket"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
- "GetBucketEncryptionOutput":{
- "type":"structure",
- "members":{
+ }
+ }
+ },
+ "GetBucketEncryptionOutput":{
+ "type":"structure",
+ "members":{
"ServerSideEncryptionConfiguration":{"shape":"ServerSideEncryptionConfiguration"}
- },
- "payload":"ServerSideEncryptionConfiguration"
- },
- "GetBucketEncryptionRequest":{
- "type":"structure",
- "required":["Bucket"],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ },
+ "payload":"ServerSideEncryptionConfiguration"
+ },
+ "GetBucketEncryptionRequest":{
+ "type":"structure",
+ "required":["Bucket"],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The name of the bucket from which the server-side encryption configuration is retrieved.</p>",
- "location":"uri",
- "locationName":"Bucket"
+ "location":"uri",
+ "locationName":"Bucket"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
+ }
+ }
+ },
"GetBucketIntelligentTieringConfigurationOutput":{
"type":"structure",
"members":{
@@ -3455,205 +3455,205 @@
}
}
},
- "GetBucketInventoryConfigurationOutput":{
- "type":"structure",
- "members":{
- "InventoryConfiguration":{
- "shape":"InventoryConfiguration",
+ "GetBucketInventoryConfigurationOutput":{
+ "type":"structure",
+ "members":{
+ "InventoryConfiguration":{
+ "shape":"InventoryConfiguration",
"documentation":"<p>Specifies the inventory configuration.</p>"
- }
- },
- "payload":"InventoryConfiguration"
- },
- "GetBucketInventoryConfigurationRequest":{
- "type":"structure",
- "required":[
- "Bucket",
- "Id"
- ],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ }
+ },
+ "payload":"InventoryConfiguration"
+ },
+ "GetBucketInventoryConfigurationRequest":{
+ "type":"structure",
+ "required":[
+ "Bucket",
+ "Id"
+ ],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The name of the bucket containing the inventory configuration to retrieve.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "Id":{
- "shape":"InventoryId",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "Id":{
+ "shape":"InventoryId",
"documentation":"<p>The ID used to identify the inventory configuration.</p>",
- "location":"querystring",
- "locationName":"id"
+ "location":"querystring",
+ "locationName":"id"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
- "GetBucketLifecycleConfigurationOutput":{
- "type":"structure",
- "members":{
- "Rules":{
- "shape":"LifecycleRules",
+ }
+ }
+ },
+ "GetBucketLifecycleConfigurationOutput":{
+ "type":"structure",
+ "members":{
+ "Rules":{
+ "shape":"LifecycleRules",
"documentation":"<p>Container for a lifecycle rule.</p>",
- "locationName":"Rule"
- }
- }
- },
- "GetBucketLifecycleConfigurationRequest":{
- "type":"structure",
- "required":["Bucket"],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ "locationName":"Rule"
+ }
+ }
+ },
+ "GetBucketLifecycleConfigurationRequest":{
+ "type":"structure",
+ "required":["Bucket"],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The name of the bucket for which to get the lifecycle information.</p>",
- "location":"uri",
- "locationName":"Bucket"
+ "location":"uri",
+ "locationName":"Bucket"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
- "GetBucketLifecycleOutput":{
- "type":"structure",
- "members":{
- "Rules":{
- "shape":"Rules",
+ }
+ }
+ },
+ "GetBucketLifecycleOutput":{
+ "type":"structure",
+ "members":{
+ "Rules":{
+ "shape":"Rules",
"documentation":"<p>Container for a lifecycle rule.</p>",
- "locationName":"Rule"
- }
- }
- },
- "GetBucketLifecycleRequest":{
- "type":"structure",
- "required":["Bucket"],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ "locationName":"Rule"
+ }
+ }
+ },
+ "GetBucketLifecycleRequest":{
+ "type":"structure",
+ "required":["Bucket"],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The name of the bucket for which to get the lifecycle information.</p>",
- "location":"uri",
- "locationName":"Bucket"
+ "location":"uri",
+ "locationName":"Bucket"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
- "GetBucketLocationOutput":{
- "type":"structure",
- "members":{
+ }
+ }
+ },
+ "GetBucketLocationOutput":{
+ "type":"structure",
+ "members":{
"LocationConstraint":{
"shape":"BucketLocationConstraint",
"documentation":"<p>Specifies the Region where the bucket resides. For a list of all the Amazon S3 supported location constraints by Region, see <a href=\"https://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region\">Regions and Endpoints</a>. Buckets in Region <code>us-east-1</code> have a LocationConstraint of <code>null</code>.</p>"
}
- }
- },
- "GetBucketLocationRequest":{
- "type":"structure",
- "required":["Bucket"],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ }
+ },
+ "GetBucketLocationRequest":{
+ "type":"structure",
+ "required":["Bucket"],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The name of the bucket for which to get the location.</p>",
- "location":"uri",
- "locationName":"Bucket"
+ "location":"uri",
+ "locationName":"Bucket"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
- "GetBucketLoggingOutput":{
- "type":"structure",
- "members":{
+ }
+ }
+ },
+ "GetBucketLoggingOutput":{
+ "type":"structure",
+ "members":{
"LoggingEnabled":{"shape":"LoggingEnabled"}
- }
- },
- "GetBucketLoggingRequest":{
- "type":"structure",
- "required":["Bucket"],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ }
+ },
+ "GetBucketLoggingRequest":{
+ "type":"structure",
+ "required":["Bucket"],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The bucket name for which to get the logging information.</p>",
- "location":"uri",
- "locationName":"Bucket"
+ "location":"uri",
+ "locationName":"Bucket"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
- "GetBucketMetricsConfigurationOutput":{
- "type":"structure",
- "members":{
- "MetricsConfiguration":{
- "shape":"MetricsConfiguration",
+ }
+ }
+ },
+ "GetBucketMetricsConfigurationOutput":{
+ "type":"structure",
+ "members":{
+ "MetricsConfiguration":{
+ "shape":"MetricsConfiguration",
"documentation":"<p>Specifies the metrics configuration.</p>"
- }
- },
- "payload":"MetricsConfiguration"
- },
- "GetBucketMetricsConfigurationRequest":{
- "type":"structure",
- "required":[
- "Bucket",
- "Id"
- ],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ }
+ },
+ "payload":"MetricsConfiguration"
+ },
+ "GetBucketMetricsConfigurationRequest":{
+ "type":"structure",
+ "required":[
+ "Bucket",
+ "Id"
+ ],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The name of the bucket containing the metrics configuration to retrieve.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "Id":{
- "shape":"MetricsId",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "Id":{
+ "shape":"MetricsId",
"documentation":"<p>The ID used to identify the metrics configuration.</p>",
- "location":"querystring",
- "locationName":"id"
+ "location":"querystring",
+ "locationName":"id"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
- "GetBucketNotificationConfigurationRequest":{
- "type":"structure",
- "required":["Bucket"],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ }
+ }
+ },
+ "GetBucketNotificationConfigurationRequest":{
+ "type":"structure",
+ "required":["Bucket"],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The name of the bucket for which to get the notification configuration.</p>",
- "location":"uri",
- "locationName":"Bucket"
+ "location":"uri",
+ "locationName":"Bucket"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
+ }
+ }
+ },
"GetBucketOwnershipControlsOutput":{
"type":"structure",
"members":{
@@ -3682,34 +3682,34 @@
}
}
},
- "GetBucketPolicyOutput":{
- "type":"structure",
- "members":{
- "Policy":{
- "shape":"Policy",
+ "GetBucketPolicyOutput":{
+ "type":"structure",
+ "members":{
+ "Policy":{
+ "shape":"Policy",
"documentation":"<p>The bucket policy as a JSON document.</p>"
- }
- },
- "payload":"Policy"
- },
- "GetBucketPolicyRequest":{
- "type":"structure",
- "required":["Bucket"],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ }
+ },
+ "payload":"Policy"
+ },
+ "GetBucketPolicyRequest":{
+ "type":"structure",
+ "required":["Bucket"],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The bucket name for which to get the bucket policy.</p>",
- "location":"uri",
- "locationName":"Bucket"
+ "location":"uri",
+ "locationName":"Bucket"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
+ }
+ }
+ },
"GetBucketPolicyStatusOutput":{
"type":"structure",
"members":{
@@ -3738,121 +3738,121 @@
}
}
},
- "GetBucketReplicationOutput":{
- "type":"structure",
- "members":{
+ "GetBucketReplicationOutput":{
+ "type":"structure",
+ "members":{
"ReplicationConfiguration":{"shape":"ReplicationConfiguration"}
- },
- "payload":"ReplicationConfiguration"
- },
- "GetBucketReplicationRequest":{
- "type":"structure",
- "required":["Bucket"],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ },
+ "payload":"ReplicationConfiguration"
+ },
+ "GetBucketReplicationRequest":{
+ "type":"structure",
+ "required":["Bucket"],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The bucket name for which to get the replication information.</p>",
- "location":"uri",
- "locationName":"Bucket"
+ "location":"uri",
+ "locationName":"Bucket"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
- "GetBucketRequestPaymentOutput":{
- "type":"structure",
- "members":{
- "Payer":{
- "shape":"Payer",
+ }
+ }
+ },
+ "GetBucketRequestPaymentOutput":{
+ "type":"structure",
+ "members":{
+ "Payer":{
+ "shape":"Payer",
"documentation":"<p>Specifies who pays for the download and request fees.</p>"
- }
- }
- },
- "GetBucketRequestPaymentRequest":{
- "type":"structure",
- "required":["Bucket"],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ }
+ }
+ },
+ "GetBucketRequestPaymentRequest":{
+ "type":"structure",
+ "required":["Bucket"],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The name of the bucket for which to get the payment request configuration</p>",
- "location":"uri",
- "locationName":"Bucket"
+ "location":"uri",
+ "locationName":"Bucket"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
- "GetBucketTaggingOutput":{
- "type":"structure",
- "required":["TagSet"],
- "members":{
+ }
+ }
+ },
+ "GetBucketTaggingOutput":{
+ "type":"structure",
+ "required":["TagSet"],
+ "members":{
"TagSet":{
"shape":"TagSet",
"documentation":"<p>Contains the tag set.</p>"
}
- }
- },
- "GetBucketTaggingRequest":{
- "type":"structure",
- "required":["Bucket"],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ }
+ },
+ "GetBucketTaggingRequest":{
+ "type":"structure",
+ "required":["Bucket"],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The name of the bucket for which to get the tagging information.</p>",
- "location":"uri",
- "locationName":"Bucket"
+ "location":"uri",
+ "locationName":"Bucket"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
- "GetBucketVersioningOutput":{
- "type":"structure",
- "members":{
- "Status":{
- "shape":"BucketVersioningStatus",
+ }
+ }
+ },
+ "GetBucketVersioningOutput":{
+ "type":"structure",
+ "members":{
+ "Status":{
+ "shape":"BucketVersioningStatus",
"documentation":"<p>The versioning state of the bucket.</p>"
- },
- "MFADelete":{
- "shape":"MFADeleteStatus",
+ },
+ "MFADelete":{
+ "shape":"MFADeleteStatus",
"documentation":"<p>Specifies whether MFA delete is enabled in the bucket versioning configuration. This element is only returned if the bucket has been configured with MFA delete. If the bucket has never been so configured, this element is not returned.</p>",
- "locationName":"MfaDelete"
- }
- }
- },
- "GetBucketVersioningRequest":{
- "type":"structure",
- "required":["Bucket"],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ "locationName":"MfaDelete"
+ }
+ }
+ },
+ "GetBucketVersioningRequest":{
+ "type":"structure",
+ "required":["Bucket"],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The name of the bucket for which to get the versioning information.</p>",
- "location":"uri",
- "locationName":"Bucket"
+ "location":"uri",
+ "locationName":"Bucket"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
- "GetBucketWebsiteOutput":{
- "type":"structure",
- "members":{
+ }
+ }
+ },
+ "GetBucketWebsiteOutput":{
+ "type":"structure",
+ "members":{
"RedirectAllRequestsTo":{
"shape":"RedirectAllRequestsTo",
"documentation":"<p>Specifies the redirect behavior of all requests to a website endpoint of an Amazon S3 bucket.</p>"
@@ -3869,83 +3869,83 @@
"shape":"RoutingRules",
"documentation":"<p>Rules that define when a redirect is applied and the redirect behavior.</p>"
}
- }
- },
- "GetBucketWebsiteRequest":{
- "type":"structure",
- "required":["Bucket"],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ }
+ },
+ "GetBucketWebsiteRequest":{
+ "type":"structure",
+ "required":["Bucket"],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The bucket name for which to get the website configuration.</p>",
- "location":"uri",
- "locationName":"Bucket"
+ "location":"uri",
+ "locationName":"Bucket"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
- "GetObjectAclOutput":{
- "type":"structure",
- "members":{
+ }
+ }
+ },
+ "GetObjectAclOutput":{
+ "type":"structure",
+ "members":{
"Owner":{
"shape":"Owner",
"documentation":"<p> Container for the bucket owner's display name and ID.</p>"
},
- "Grants":{
- "shape":"Grants",
+ "Grants":{
+ "shape":"Grants",
"documentation":"<p>A list of grants.</p>",
- "locationName":"AccessControlList"
- },
- "RequestCharged":{
- "shape":"RequestCharged",
- "location":"header",
- "locationName":"x-amz-request-charged"
- }
- }
- },
- "GetObjectAclRequest":{
- "type":"structure",
- "required":[
- "Bucket",
- "Key"
- ],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ "locationName":"AccessControlList"
+ },
+ "RequestCharged":{
+ "shape":"RequestCharged",
+ "location":"header",
+ "locationName":"x-amz-request-charged"
+ }
+ }
+ },
+ "GetObjectAclRequest":{
+ "type":"structure",
+ "required":[
+ "Bucket",
+ "Key"
+ ],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The bucket name that contains the object for which to get the ACL information. </p> <p>When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.s3-accesspoint.<i>Region</i>.amazonaws.com. When using this action with an access point through the AWS SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\">Using access points</a> in the <i>Amazon S3 User Guide</i>.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "Key":{
- "shape":"ObjectKey",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "Key":{
+ "shape":"ObjectKey",
"documentation":"<p>The key of the object for which to get the ACL information.</p>",
- "location":"uri",
- "locationName":"Key"
- },
- "VersionId":{
- "shape":"ObjectVersionId",
+ "location":"uri",
+ "locationName":"Key"
+ },
+ "VersionId":{
+ "shape":"ObjectVersionId",
"documentation":"<p>VersionId used to reference a specific version of the object.</p>",
- "location":"querystring",
- "locationName":"versionId"
- },
- "RequestPayer":{
- "shape":"RequestPayer",
- "location":"header",
- "locationName":"x-amz-request-payer"
+ "location":"querystring",
+ "locationName":"versionId"
+ },
+ "RequestPayer":{
+ "shape":"RequestPayer",
+ "location":"header",
+ "locationName":"x-amz-request-payer"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
+ }
+ }
+ },
"GetObjectLegalHoldOutput":{
"type":"structure",
"members":{
@@ -4022,180 +4022,180 @@
}
}
},
- "GetObjectOutput":{
- "type":"structure",
- "members":{
- "Body":{
- "shape":"Body",
+ "GetObjectOutput":{
+ "type":"structure",
+ "members":{
+ "Body":{
+ "shape":"Body",
"documentation":"<p>Object data.</p>",
- "streaming":true
- },
- "DeleteMarker":{
- "shape":"DeleteMarker",
+ "streaming":true
+ },
+ "DeleteMarker":{
+ "shape":"DeleteMarker",
"documentation":"<p>Specifies whether the object retrieved was (true) or was not (false) a Delete Marker. If false, this response header does not appear in the response.</p>",
- "location":"header",
- "locationName":"x-amz-delete-marker"
- },
- "AcceptRanges":{
- "shape":"AcceptRanges",
+ "location":"header",
+ "locationName":"x-amz-delete-marker"
+ },
+ "AcceptRanges":{
+ "shape":"AcceptRanges",
"documentation":"<p>Indicates that a range of bytes was specified.</p>",
- "location":"header",
- "locationName":"accept-ranges"
- },
- "Expiration":{
- "shape":"Expiration",
+ "location":"header",
+ "locationName":"accept-ranges"
+ },
+ "Expiration":{
+ "shape":"Expiration",
"documentation":"<p>If the object expiration is configured (see PUT Bucket lifecycle), the response includes this header. It includes the expiry-date and rule-id key-value pairs providing object expiration information. The value of the rule-id is URL encoded.</p>",
- "location":"header",
- "locationName":"x-amz-expiration"
- },
- "Restore":{
- "shape":"Restore",
+ "location":"header",
+ "locationName":"x-amz-expiration"
+ },
+ "Restore":{
+ "shape":"Restore",
"documentation":"<p>Provides information about object restoration action and expiration time of the restored object copy.</p>",
- "location":"header",
- "locationName":"x-amz-restore"
- },
- "LastModified":{
- "shape":"LastModified",
+ "location":"header",
+ "locationName":"x-amz-restore"
+ },
+ "LastModified":{
+ "shape":"LastModified",
"documentation":"<p>Creation date of the object.</p>",
- "location":"header",
- "locationName":"Last-Modified"
- },
- "ContentLength":{
- "shape":"ContentLength",
+ "location":"header",
+ "locationName":"Last-Modified"
+ },
+ "ContentLength":{
+ "shape":"ContentLength",
"documentation":"<p>Size of the body in bytes.</p>",
- "location":"header",
- "locationName":"Content-Length"
- },
- "ETag":{
- "shape":"ETag",
+ "location":"header",
+ "locationName":"Content-Length"
+ },
+ "ETag":{
+ "shape":"ETag",
"documentation":"<p>An ETag is an opaque identifier assigned by a web server to a specific version of a resource found at a URL.</p>",
- "location":"header",
- "locationName":"ETag"
- },
- "MissingMeta":{
- "shape":"MissingMeta",
+ "location":"header",
+ "locationName":"ETag"
+ },
+ "MissingMeta":{
+ "shape":"MissingMeta",
"documentation":"<p>This is set to the number of metadata entries not returned in <code>x-amz-meta</code> headers. This can happen if you create metadata using an API like SOAP that supports more flexible metadata than the REST API. For example, using SOAP, you can create metadata whose values are not legal HTTP headers.</p>",
- "location":"header",
- "locationName":"x-amz-missing-meta"
- },
- "VersionId":{
- "shape":"ObjectVersionId",
+ "location":"header",
+ "locationName":"x-amz-missing-meta"
+ },
+ "VersionId":{
+ "shape":"ObjectVersionId",
"documentation":"<p>Version of the object.</p>",
- "location":"header",
- "locationName":"x-amz-version-id"
- },
- "CacheControl":{
- "shape":"CacheControl",
+ "location":"header",
+ "locationName":"x-amz-version-id"
+ },
+ "CacheControl":{
+ "shape":"CacheControl",
"documentation":"<p>Specifies caching behavior along the request/reply chain.</p>",
- "location":"header",
- "locationName":"Cache-Control"
- },
- "ContentDisposition":{
- "shape":"ContentDisposition",
+ "location":"header",
+ "locationName":"Cache-Control"
+ },
+ "ContentDisposition":{
+ "shape":"ContentDisposition",
"documentation":"<p>Specifies presentational information for the object.</p>",
- "location":"header",
- "locationName":"Content-Disposition"
- },
- "ContentEncoding":{
- "shape":"ContentEncoding",
+ "location":"header",
+ "locationName":"Content-Disposition"
+ },
+ "ContentEncoding":{
+ "shape":"ContentEncoding",
"documentation":"<p>Specifies what content encodings have been applied to the object and thus what decoding mechanisms must be applied to obtain the media-type referenced by the Content-Type header field.</p>",
- "location":"header",
- "locationName":"Content-Encoding"
- },
- "ContentLanguage":{
- "shape":"ContentLanguage",
+ "location":"header",
+ "locationName":"Content-Encoding"
+ },
+ "ContentLanguage":{
+ "shape":"ContentLanguage",
"documentation":"<p>The language the content is in.</p>",
- "location":"header",
- "locationName":"Content-Language"
- },
- "ContentRange":{
- "shape":"ContentRange",
+ "location":"header",
+ "locationName":"Content-Language"
+ },
+ "ContentRange":{
+ "shape":"ContentRange",
"documentation":"<p>The portion of the object returned in the response.</p>",
- "location":"header",
- "locationName":"Content-Range"
- },
- "ContentType":{
- "shape":"ContentType",
+ "location":"header",
+ "locationName":"Content-Range"
+ },
+ "ContentType":{
+ "shape":"ContentType",
"documentation":"<p>A standard MIME type describing the format of the object data.</p>",
- "location":"header",
- "locationName":"Content-Type"
- },
- "Expires":{
- "shape":"Expires",
+ "location":"header",
+ "locationName":"Content-Type"
+ },
+ "Expires":{
+ "shape":"Expires",
"documentation":"<p>The date and time at which the object is no longer cacheable.</p>",
- "location":"header",
- "locationName":"Expires"
- },
- "WebsiteRedirectLocation":{
- "shape":"WebsiteRedirectLocation",
+ "location":"header",
+ "locationName":"Expires"
+ },
+ "WebsiteRedirectLocation":{
+ "shape":"WebsiteRedirectLocation",
"documentation":"<p>If the bucket is configured as a website, redirects requests for this object to another object in the same bucket or to an external URL. Amazon S3 stores the value of this header in the object metadata.</p>",
- "location":"header",
- "locationName":"x-amz-website-redirect-location"
- },
- "ServerSideEncryption":{
- "shape":"ServerSideEncryption",
+ "location":"header",
+ "locationName":"x-amz-website-redirect-location"
+ },
+ "ServerSideEncryption":{
+ "shape":"ServerSideEncryption",
"documentation":"<p>The server-side encryption algorithm used when storing this object in Amazon S3 (for example, AES256, aws:kms).</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption"
- },
- "Metadata":{
- "shape":"Metadata",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption"
+ },
+ "Metadata":{
+ "shape":"Metadata",
"documentation":"<p>A map of metadata to store with the object in S3.</p>",
- "location":"headers",
- "locationName":"x-amz-meta-"
- },
- "SSECustomerAlgorithm":{
- "shape":"SSECustomerAlgorithm",
+ "location":"headers",
+ "locationName":"x-amz-meta-"
+ },
+ "SSECustomerAlgorithm":{
+ "shape":"SSECustomerAlgorithm",
"documentation":"<p>If server-side encryption with a customer-provided encryption key was requested, the response will include this header confirming the encryption algorithm used.</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-customer-algorithm"
- },
- "SSECustomerKeyMD5":{
- "shape":"SSECustomerKeyMD5",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-customer-algorithm"
+ },
+ "SSECustomerKeyMD5":{
+ "shape":"SSECustomerKeyMD5",
"documentation":"<p>If server-side encryption with a customer-provided encryption key was requested, the response will include this header to provide round-trip message integrity verification of the customer-provided encryption key.</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-customer-key-MD5"
- },
- "SSEKMSKeyId":{
- "shape":"SSEKMSKeyId",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-customer-key-MD5"
+ },
+ "SSEKMSKeyId":{
+ "shape":"SSEKMSKeyId",
"documentation":"<p>If present, specifies the ID of the AWS Key Management Service (AWS KMS) symmetric customer managed customer master key (CMK) that was used for the object.</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-aws-kms-key-id"
- },
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-aws-kms-key-id"
+ },
"BucketKeyEnabled":{
"shape":"BucketKeyEnabled",
"documentation":"<p>Indicates whether the object uses an S3 Bucket Key for server-side encryption with AWS KMS (SSE-KMS).</p>",
"location":"header",
"locationName":"x-amz-server-side-encryption-bucket-key-enabled"
},
- "StorageClass":{
- "shape":"StorageClass",
+ "StorageClass":{
+ "shape":"StorageClass",
"documentation":"<p>Provides storage class information of the object. Amazon S3 returns this header for all objects except for S3 Standard storage class objects.</p>",
- "location":"header",
- "locationName":"x-amz-storage-class"
- },
- "RequestCharged":{
- "shape":"RequestCharged",
- "location":"header",
- "locationName":"x-amz-request-charged"
- },
- "ReplicationStatus":{
- "shape":"ReplicationStatus",
+ "location":"header",
+ "locationName":"x-amz-storage-class"
+ },
+ "RequestCharged":{
+ "shape":"RequestCharged",
+ "location":"header",
+ "locationName":"x-amz-request-charged"
+ },
+ "ReplicationStatus":{
+ "shape":"ReplicationStatus",
"documentation":"<p>Amazon S3 can return this if your request involves a bucket that is either a source or destination in a replication rule.</p>",
- "location":"header",
- "locationName":"x-amz-replication-status"
- },
- "PartsCount":{
- "shape":"PartsCount",
+ "location":"header",
+ "locationName":"x-amz-replication-status"
+ },
+ "PartsCount":{
+ "shape":"PartsCount",
"documentation":"<p>The count of parts this object has.</p>",
- "location":"header",
- "locationName":"x-amz-mp-parts-count"
- },
- "TagCount":{
- "shape":"TagCount",
+ "location":"header",
+ "locationName":"x-amz-mp-parts-count"
+ },
+ "TagCount":{
+ "shape":"TagCount",
"documentation":"<p>The number of tags, if any, on the object.</p>",
- "location":"header",
- "locationName":"x-amz-tagging-count"
+ "location":"header",
+ "locationName":"x-amz-tagging-count"
},
"ObjectLockMode":{
"shape":"ObjectLockMode",
@@ -4214,138 +4214,138 @@
"documentation":"<p>Indicates whether this object has an active legal hold. This field is only returned if you have permission to view an object's legal hold status. </p>",
"location":"header",
"locationName":"x-amz-object-lock-legal-hold"
- }
- },
- "payload":"Body"
- },
- "GetObjectRequest":{
- "type":"structure",
- "required":[
- "Bucket",
- "Key"
- ],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ }
+ },
+ "payload":"Body"
+ },
+ "GetObjectRequest":{
+ "type":"structure",
+ "required":[
+ "Bucket",
+ "Key"
+ ],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The bucket name containing the object. </p> <p>When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.s3-accesspoint.<i>Region</i>.amazonaws.com. When using this action with an access point through the AWS SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\">Using access points</a> in the <i>Amazon S3 User Guide</i>.</p> <p>When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.<i>outpostID</i>.s3-outposts.<i>Region</i>.amazonaws.com. When using this action using S3 on Outposts through the AWS SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html\">Using S3 on Outposts</a> in the <i>Amazon S3 User Guide</i>.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "IfMatch":{
- "shape":"IfMatch",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "IfMatch":{
+ "shape":"IfMatch",
"documentation":"<p>Return the object only if its entity tag (ETag) is the same as the one specified, otherwise return a 412 (precondition failed).</p>",
- "location":"header",
- "locationName":"If-Match"
- },
- "IfModifiedSince":{
- "shape":"IfModifiedSince",
+ "location":"header",
+ "locationName":"If-Match"
+ },
+ "IfModifiedSince":{
+ "shape":"IfModifiedSince",
"documentation":"<p>Return the object only if it has been modified since the specified time, otherwise return a 304 (not modified).</p>",
- "location":"header",
- "locationName":"If-Modified-Since"
- },
- "IfNoneMatch":{
- "shape":"IfNoneMatch",
+ "location":"header",
+ "locationName":"If-Modified-Since"
+ },
+ "IfNoneMatch":{
+ "shape":"IfNoneMatch",
"documentation":"<p>Return the object only if its entity tag (ETag) is different from the one specified, otherwise return a 304 (not modified).</p>",
- "location":"header",
- "locationName":"If-None-Match"
- },
- "IfUnmodifiedSince":{
- "shape":"IfUnmodifiedSince",
+ "location":"header",
+ "locationName":"If-None-Match"
+ },
+ "IfUnmodifiedSince":{
+ "shape":"IfUnmodifiedSince",
"documentation":"<p>Return the object only if it has not been modified since the specified time, otherwise return a 412 (precondition failed).</p>",
- "location":"header",
- "locationName":"If-Unmodified-Since"
- },
- "Key":{
- "shape":"ObjectKey",
+ "location":"header",
+ "locationName":"If-Unmodified-Since"
+ },
+ "Key":{
+ "shape":"ObjectKey",
"documentation":"<p>Key of the object to get.</p>",
- "location":"uri",
- "locationName":"Key"
- },
- "Range":{
- "shape":"Range",
+ "location":"uri",
+ "locationName":"Key"
+ },
+ "Range":{
+ "shape":"Range",
"documentation":"<p>Downloads the specified range bytes of an object. For more information about the HTTP Range header, see <a href=\"https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35\">https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35</a>.</p> <note> <p>Amazon S3 doesn't support retrieving multiple ranges of data per <code>GET</code> request.</p> </note>",
- "location":"header",
- "locationName":"Range"
- },
- "ResponseCacheControl":{
- "shape":"ResponseCacheControl",
+ "location":"header",
+ "locationName":"Range"
+ },
+ "ResponseCacheControl":{
+ "shape":"ResponseCacheControl",
"documentation":"<p>Sets the <code>Cache-Control</code> header of the response.</p>",
- "location":"querystring",
- "locationName":"response-cache-control"
- },
- "ResponseContentDisposition":{
- "shape":"ResponseContentDisposition",
+ "location":"querystring",
+ "locationName":"response-cache-control"
+ },
+ "ResponseContentDisposition":{
+ "shape":"ResponseContentDisposition",
"documentation":"<p>Sets the <code>Content-Disposition</code> header of the response</p>",
- "location":"querystring",
- "locationName":"response-content-disposition"
- },
- "ResponseContentEncoding":{
- "shape":"ResponseContentEncoding",
+ "location":"querystring",
+ "locationName":"response-content-disposition"
+ },
+ "ResponseContentEncoding":{
+ "shape":"ResponseContentEncoding",
"documentation":"<p>Sets the <code>Content-Encoding</code> header of the response.</p>",
- "location":"querystring",
- "locationName":"response-content-encoding"
- },
- "ResponseContentLanguage":{
- "shape":"ResponseContentLanguage",
+ "location":"querystring",
+ "locationName":"response-content-encoding"
+ },
+ "ResponseContentLanguage":{
+ "shape":"ResponseContentLanguage",
"documentation":"<p>Sets the <code>Content-Language</code> header of the response.</p>",
- "location":"querystring",
- "locationName":"response-content-language"
- },
- "ResponseContentType":{
- "shape":"ResponseContentType",
+ "location":"querystring",
+ "locationName":"response-content-language"
+ },
+ "ResponseContentType":{
+ "shape":"ResponseContentType",
"documentation":"<p>Sets the <code>Content-Type</code> header of the response.</p>",
- "location":"querystring",
- "locationName":"response-content-type"
- },
- "ResponseExpires":{
- "shape":"ResponseExpires",
+ "location":"querystring",
+ "locationName":"response-content-type"
+ },
+ "ResponseExpires":{
+ "shape":"ResponseExpires",
"documentation":"<p>Sets the <code>Expires</code> header of the response.</p>",
- "location":"querystring",
- "locationName":"response-expires"
- },
- "VersionId":{
- "shape":"ObjectVersionId",
+ "location":"querystring",
+ "locationName":"response-expires"
+ },
+ "VersionId":{
+ "shape":"ObjectVersionId",
"documentation":"<p>VersionId used to reference a specific version of the object.</p>",
- "location":"querystring",
- "locationName":"versionId"
- },
- "SSECustomerAlgorithm":{
- "shape":"SSECustomerAlgorithm",
+ "location":"querystring",
+ "locationName":"versionId"
+ },
+ "SSECustomerAlgorithm":{
+ "shape":"SSECustomerAlgorithm",
"documentation":"<p>Specifies the algorithm to use to when decrypting the object (for example, AES256).</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-customer-algorithm"
- },
- "SSECustomerKey":{
- "shape":"SSECustomerKey",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-customer-algorithm"
+ },
+ "SSECustomerKey":{
+ "shape":"SSECustomerKey",
"documentation":"<p>Specifies the customer-provided encryption key for Amazon S3 used to encrypt the data. This value is used to decrypt the object when recovering it and must match the one used when storing the data. The key must be appropriate for use with the algorithm specified in the <code>x-amz-server-side-encryption-customer-algorithm</code> header.</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-customer-key"
- },
- "SSECustomerKeyMD5":{
- "shape":"SSECustomerKeyMD5",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-customer-key"
+ },
+ "SSECustomerKeyMD5":{
+ "shape":"SSECustomerKeyMD5",
"documentation":"<p>Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. Amazon S3 uses this header for a message integrity check to ensure that the encryption key was transmitted without error.</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-customer-key-MD5"
- },
- "RequestPayer":{
- "shape":"RequestPayer",
- "location":"header",
- "locationName":"x-amz-request-payer"
- },
- "PartNumber":{
- "shape":"PartNumber",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-customer-key-MD5"
+ },
+ "RequestPayer":{
+ "shape":"RequestPayer",
+ "location":"header",
+ "locationName":"x-amz-request-payer"
+ },
+ "PartNumber":{
+ "shape":"PartNumber",
"documentation":"<p>Part number of the object being read. This is a positive integer between 1 and 10,000. Effectively performs a 'ranged' GET request for the part specified. Useful for downloading just a part of an object.</p>",
- "location":"querystring",
- "locationName":"partNumber"
+ "location":"querystring",
+ "locationName":"partNumber"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
+ }
+ }
+ },
"GetObjectResponseStatusCode":{"type":"integer"},
"GetObjectRetentionOutput":{
"type":"structure",
@@ -4395,46 +4395,46 @@
}
}
},
- "GetObjectTaggingOutput":{
- "type":"structure",
- "required":["TagSet"],
- "members":{
- "VersionId":{
- "shape":"ObjectVersionId",
+ "GetObjectTaggingOutput":{
+ "type":"structure",
+ "required":["TagSet"],
+ "members":{
+ "VersionId":{
+ "shape":"ObjectVersionId",
"documentation":"<p>The versionId of the object for which you got the tagging information.</p>",
- "location":"header",
- "locationName":"x-amz-version-id"
- },
+ "location":"header",
+ "locationName":"x-amz-version-id"
+ },
"TagSet":{
"shape":"TagSet",
"documentation":"<p>Contains the tag set.</p>"
}
- }
- },
- "GetObjectTaggingRequest":{
- "type":"structure",
- "required":[
- "Bucket",
- "Key"
- ],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ }
+ },
+ "GetObjectTaggingRequest":{
+ "type":"structure",
+ "required":[
+ "Bucket",
+ "Key"
+ ],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The bucket name containing the object for which to get the tagging information. </p> <p>When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.s3-accesspoint.<i>Region</i>.amazonaws.com. When using this action with an access point through the AWS SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\">Using access points</a> in the <i>Amazon S3 User Guide</i>.</p> <p>When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.<i>outpostID</i>.s3-outposts.<i>Region</i>.amazonaws.com. When using this action using S3 on Outposts through the AWS SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html\">Using S3 on Outposts</a> in the <i>Amazon S3 User Guide</i>.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "Key":{
- "shape":"ObjectKey",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "Key":{
+ "shape":"ObjectKey",
"documentation":"<p>Object key for which to get the tagging information.</p>",
- "location":"uri",
- "locationName":"Key"
- },
- "VersionId":{
- "shape":"ObjectVersionId",
+ "location":"uri",
+ "locationName":"Key"
+ },
+ "VersionId":{
+ "shape":"ObjectVersionId",
"documentation":"<p>The versionId of the object for which to get the tagging information.</p>",
- "location":"querystring",
- "locationName":"versionId"
+ "location":"querystring",
+ "locationName":"versionId"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
@@ -4446,57 +4446,57 @@
"shape":"RequestPayer",
"location":"header",
"locationName":"x-amz-request-payer"
- }
- }
- },
- "GetObjectTorrentOutput":{
- "type":"structure",
- "members":{
- "Body":{
- "shape":"Body",
+ }
+ }
+ },
+ "GetObjectTorrentOutput":{
+ "type":"structure",
+ "members":{
+ "Body":{
+ "shape":"Body",
"documentation":"<p>A Bencoded dictionary as defined by the BitTorrent specification</p>",
- "streaming":true
- },
- "RequestCharged":{
- "shape":"RequestCharged",
- "location":"header",
- "locationName":"x-amz-request-charged"
- }
- },
- "payload":"Body"
- },
- "GetObjectTorrentRequest":{
- "type":"structure",
- "required":[
- "Bucket",
- "Key"
- ],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ "streaming":true
+ },
+ "RequestCharged":{
+ "shape":"RequestCharged",
+ "location":"header",
+ "locationName":"x-amz-request-charged"
+ }
+ },
+ "payload":"Body"
+ },
+ "GetObjectTorrentRequest":{
+ "type":"structure",
+ "required":[
+ "Bucket",
+ "Key"
+ ],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The name of the bucket containing the object for which to get the torrent files.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "Key":{
- "shape":"ObjectKey",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "Key":{
+ "shape":"ObjectKey",
"documentation":"<p>The object key for which to get the information.</p>",
- "location":"uri",
- "locationName":"Key"
- },
- "RequestPayer":{
- "shape":"RequestPayer",
- "location":"header",
- "locationName":"x-amz-request-payer"
+ "location":"uri",
+ "locationName":"Key"
+ },
+ "RequestPayer":{
+ "shape":"RequestPayer",
+ "location":"header",
+ "locationName":"x-amz-request-payer"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
+ }
+ }
+ },
"GetPublicAccessBlockOutput":{
"type":"structure",
"members":{
@@ -4525,257 +4525,257 @@
}
}
},
- "GlacierJobParameters":{
- "type":"structure",
- "required":["Tier"],
- "members":{
- "Tier":{
- "shape":"Tier",
+ "GlacierJobParameters":{
+ "type":"structure",
+ "required":["Tier"],
+ "members":{
+ "Tier":{
+ "shape":"Tier",
"documentation":"<p>Retrieval tier at which the restore will be processed.</p>"
- }
+ }
},
"documentation":"<p>Container for S3 Glacier job parameters.</p>"
- },
- "Grant":{
- "type":"structure",
- "members":{
+ },
+ "Grant":{
+ "type":"structure",
+ "members":{
"Grantee":{
"shape":"Grantee",
"documentation":"<p>The person being granted permissions.</p>"
},
- "Permission":{
- "shape":"Permission",
+ "Permission":{
+ "shape":"Permission",
"documentation":"<p>Specifies the permission given to the grantee.</p>"
- }
+ }
},
"documentation":"<p>Container for grant information.</p>"
- },
- "GrantFullControl":{"type":"string"},
- "GrantRead":{"type":"string"},
- "GrantReadACP":{"type":"string"},
- "GrantWrite":{"type":"string"},
- "GrantWriteACP":{"type":"string"},
- "Grantee":{
- "type":"structure",
- "required":["Type"],
- "members":{
- "DisplayName":{
- "shape":"DisplayName",
+ },
+ "GrantFullControl":{"type":"string"},
+ "GrantRead":{"type":"string"},
+ "GrantReadACP":{"type":"string"},
+ "GrantWrite":{"type":"string"},
+ "GrantWriteACP":{"type":"string"},
+ "Grantee":{
+ "type":"structure",
+ "required":["Type"],
+ "members":{
+ "DisplayName":{
+ "shape":"DisplayName",
"documentation":"<p>Screen name of the grantee.</p>"
- },
- "EmailAddress":{
- "shape":"EmailAddress",
+ },
+ "EmailAddress":{
+ "shape":"EmailAddress",
"documentation":"<p>Email address of the grantee.</p> <note> <p>Using email addresses to specify a grantee is only supported in the following AWS Regions: </p> <ul> <li> <p>US East (N. Virginia)</p> </li> <li> <p>US West (N. California)</p> </li> <li> <p> US West (Oregon)</p> </li> <li> <p> Asia Pacific (Singapore)</p> </li> <li> <p>Asia Pacific (Sydney)</p> </li> <li> <p>Asia Pacific (Tokyo)</p> </li> <li> <p>Europe (Ireland)</p> </li> <li> <p>South America (São Paulo)</p> </li> </ul> <p>For a list of all the Amazon S3 supported Regions and endpoints, see <a href=\"https://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region\">Regions and Endpoints</a> in the AWS General Reference.</p> </note>"
- },
- "ID":{
- "shape":"ID",
+ },
+ "ID":{
+ "shape":"ID",
"documentation":"<p>The canonical user ID of the grantee.</p>"
- },
- "Type":{
- "shape":"Type",
+ },
+ "Type":{
+ "shape":"Type",
"documentation":"<p>Type of grantee</p>",
- "locationName":"xsi:type",
- "xmlAttribute":true
- },
- "URI":{
- "shape":"URI",
+ "locationName":"xsi:type",
+ "xmlAttribute":true
+ },
+ "URI":{
+ "shape":"URI",
"documentation":"<p>URI of the grantee group.</p>"
- }
- },
+ }
+ },
"documentation":"<p>Container for the person being granted permissions.</p>",
- "xmlNamespace":{
- "prefix":"xsi",
- "uri":"http://www.w3.org/2001/XMLSchema-instance"
- }
- },
- "Grants":{
- "type":"list",
- "member":{
- "shape":"Grant",
- "locationName":"Grant"
- }
- },
- "HeadBucketRequest":{
- "type":"structure",
- "required":["Bucket"],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ "xmlNamespace":{
+ "prefix":"xsi",
+ "uri":"http://www.w3.org/2001/XMLSchema-instance"
+ }
+ },
+ "Grants":{
+ "type":"list",
+ "member":{
+ "shape":"Grant",
+ "locationName":"Grant"
+ }
+ },
+ "HeadBucketRequest":{
+ "type":"structure",
+ "required":["Bucket"],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The bucket name.</p> <p>When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.s3-accesspoint.<i>Region</i>.amazonaws.com. When using this action with an access point through the AWS SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\">Using access points</a> in the <i>Amazon S3 User Guide</i>.</p> <p>When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.<i>outpostID</i>.s3-outposts.<i>Region</i>.amazonaws.com. When using this action using S3 on Outposts through the AWS SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html\">Using S3 on Outposts</a> in the <i>Amazon S3 User Guide</i>.</p>",
- "location":"uri",
- "locationName":"Bucket"
+ "location":"uri",
+ "locationName":"Bucket"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
- "HeadObjectOutput":{
- "type":"structure",
- "members":{
- "DeleteMarker":{
- "shape":"DeleteMarker",
+ }
+ }
+ },
+ "HeadObjectOutput":{
+ "type":"structure",
+ "members":{
+ "DeleteMarker":{
+ "shape":"DeleteMarker",
"documentation":"<p>Specifies whether the object retrieved was (true) or was not (false) a Delete Marker. If false, this response header does not appear in the response.</p>",
- "location":"header",
- "locationName":"x-amz-delete-marker"
- },
- "AcceptRanges":{
- "shape":"AcceptRanges",
+ "location":"header",
+ "locationName":"x-amz-delete-marker"
+ },
+ "AcceptRanges":{
+ "shape":"AcceptRanges",
"documentation":"<p>Indicates that a range of bytes was specified.</p>",
- "location":"header",
- "locationName":"accept-ranges"
- },
- "Expiration":{
- "shape":"Expiration",
+ "location":"header",
+ "locationName":"accept-ranges"
+ },
+ "Expiration":{
+ "shape":"Expiration",
"documentation":"<p>If the object expiration is configured (see PUT Bucket lifecycle), the response includes this header. It includes the expiry-date and rule-id key-value pairs providing object expiration information. The value of the rule-id is URL encoded.</p>",
- "location":"header",
- "locationName":"x-amz-expiration"
- },
- "Restore":{
- "shape":"Restore",
+ "location":"header",
+ "locationName":"x-amz-expiration"
+ },
+ "Restore":{
+ "shape":"Restore",
"documentation":"<p>If the object is an archived object (an object whose storage class is GLACIER), the response includes this header if either the archive restoration is in progress (see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_RestoreObject.html\">RestoreObject</a> or an archive copy is already restored.</p> <p> If an archive copy is already restored, the header value indicates when Amazon S3 is scheduled to delete the object copy. For example:</p> <p> <code>x-amz-restore: ongoing-request=\"false\", expiry-date=\"Fri, 21 Dec 2012 00:00:00 GMT\"</code> </p> <p>If the object restoration is in progress, the header returns the value <code>ongoing-request=\"true\"</code>.</p> <p>For more information about archiving objects, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/object-lifecycle-mgmt.html#lifecycle-transition-general-considerations\">Transitioning Objects: General Considerations</a>.</p>",
- "location":"header",
- "locationName":"x-amz-restore"
- },
+ "location":"header",
+ "locationName":"x-amz-restore"
+ },
"ArchiveStatus":{
"shape":"ArchiveStatus",
"documentation":"<p>The archive state of the head object.</p>",
"location":"header",
"locationName":"x-amz-archive-status"
},
- "LastModified":{
- "shape":"LastModified",
+ "LastModified":{
+ "shape":"LastModified",
"documentation":"<p>Creation date of the object.</p>",
- "location":"header",
- "locationName":"Last-Modified"
- },
- "ContentLength":{
- "shape":"ContentLength",
+ "location":"header",
+ "locationName":"Last-Modified"
+ },
+ "ContentLength":{
+ "shape":"ContentLength",
"documentation":"<p>Size of the body in bytes.</p>",
- "location":"header",
- "locationName":"Content-Length"
- },
- "ETag":{
- "shape":"ETag",
+ "location":"header",
+ "locationName":"Content-Length"
+ },
+ "ETag":{
+ "shape":"ETag",
"documentation":"<p>An ETag is an opaque identifier assigned by a web server to a specific version of a resource found at a URL.</p>",
- "location":"header",
- "locationName":"ETag"
- },
- "MissingMeta":{
- "shape":"MissingMeta",
+ "location":"header",
+ "locationName":"ETag"
+ },
+ "MissingMeta":{
+ "shape":"MissingMeta",
"documentation":"<p>This is set to the number of metadata entries not returned in <code>x-amz-meta</code> headers. This can happen if you create metadata using an API like SOAP that supports more flexible metadata than the REST API. For example, using SOAP, you can create metadata whose values are not legal HTTP headers.</p>",
- "location":"header",
- "locationName":"x-amz-missing-meta"
- },
- "VersionId":{
- "shape":"ObjectVersionId",
+ "location":"header",
+ "locationName":"x-amz-missing-meta"
+ },
+ "VersionId":{
+ "shape":"ObjectVersionId",
"documentation":"<p>Version of the object.</p>",
- "location":"header",
- "locationName":"x-amz-version-id"
- },
- "CacheControl":{
- "shape":"CacheControl",
+ "location":"header",
+ "locationName":"x-amz-version-id"
+ },
+ "CacheControl":{
+ "shape":"CacheControl",
"documentation":"<p>Specifies caching behavior along the request/reply chain.</p>",
- "location":"header",
- "locationName":"Cache-Control"
- },
- "ContentDisposition":{
- "shape":"ContentDisposition",
+ "location":"header",
+ "locationName":"Cache-Control"
+ },
+ "ContentDisposition":{
+ "shape":"ContentDisposition",
"documentation":"<p>Specifies presentational information for the object.</p>",
- "location":"header",
- "locationName":"Content-Disposition"
- },
- "ContentEncoding":{
- "shape":"ContentEncoding",
+ "location":"header",
+ "locationName":"Content-Disposition"
+ },
+ "ContentEncoding":{
+ "shape":"ContentEncoding",
"documentation":"<p>Specifies what content encodings have been applied to the object and thus what decoding mechanisms must be applied to obtain the media-type referenced by the Content-Type header field.</p>",
- "location":"header",
- "locationName":"Content-Encoding"
- },
- "ContentLanguage":{
- "shape":"ContentLanguage",
+ "location":"header",
+ "locationName":"Content-Encoding"
+ },
+ "ContentLanguage":{
+ "shape":"ContentLanguage",
"documentation":"<p>The language the content is in.</p>",
- "location":"header",
- "locationName":"Content-Language"
- },
- "ContentType":{
- "shape":"ContentType",
+ "location":"header",
+ "locationName":"Content-Language"
+ },
+ "ContentType":{
+ "shape":"ContentType",
"documentation":"<p>A standard MIME type describing the format of the object data.</p>",
- "location":"header",
- "locationName":"Content-Type"
- },
- "Expires":{
- "shape":"Expires",
+ "location":"header",
+ "locationName":"Content-Type"
+ },
+ "Expires":{
+ "shape":"Expires",
"documentation":"<p>The date and time at which the object is no longer cacheable.</p>",
- "location":"header",
- "locationName":"Expires"
- },
- "WebsiteRedirectLocation":{
- "shape":"WebsiteRedirectLocation",
+ "location":"header",
+ "locationName":"Expires"
+ },
+ "WebsiteRedirectLocation":{
+ "shape":"WebsiteRedirectLocation",
"documentation":"<p>If the bucket is configured as a website, redirects requests for this object to another object in the same bucket or to an external URL. Amazon S3 stores the value of this header in the object metadata.</p>",
- "location":"header",
- "locationName":"x-amz-website-redirect-location"
- },
- "ServerSideEncryption":{
- "shape":"ServerSideEncryption",
+ "location":"header",
+ "locationName":"x-amz-website-redirect-location"
+ },
+ "ServerSideEncryption":{
+ "shape":"ServerSideEncryption",
"documentation":"<p>If the object is stored using server-side encryption either with an AWS KMS customer master key (CMK) or an Amazon S3-managed encryption key, the response includes this header with the value of the server-side encryption algorithm used when storing this object in Amazon S3 (for example, AES256, aws:kms).</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption"
- },
- "Metadata":{
- "shape":"Metadata",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption"
+ },
+ "Metadata":{
+ "shape":"Metadata",
"documentation":"<p>A map of metadata to store with the object in S3.</p>",
- "location":"headers",
- "locationName":"x-amz-meta-"
- },
- "SSECustomerAlgorithm":{
- "shape":"SSECustomerAlgorithm",
+ "location":"headers",
+ "locationName":"x-amz-meta-"
+ },
+ "SSECustomerAlgorithm":{
+ "shape":"SSECustomerAlgorithm",
"documentation":"<p>If server-side encryption with a customer-provided encryption key was requested, the response will include this header confirming the encryption algorithm used.</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-customer-algorithm"
- },
- "SSECustomerKeyMD5":{
- "shape":"SSECustomerKeyMD5",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-customer-algorithm"
+ },
+ "SSECustomerKeyMD5":{
+ "shape":"SSECustomerKeyMD5",
"documentation":"<p>If server-side encryption with a customer-provided encryption key was requested, the response will include this header to provide round-trip message integrity verification of the customer-provided encryption key.</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-customer-key-MD5"
- },
- "SSEKMSKeyId":{
- "shape":"SSEKMSKeyId",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-customer-key-MD5"
+ },
+ "SSEKMSKeyId":{
+ "shape":"SSEKMSKeyId",
"documentation":"<p>If present, specifies the ID of the AWS Key Management Service (AWS KMS) symmetric customer managed customer master key (CMK) that was used for the object.</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-aws-kms-key-id"
- },
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-aws-kms-key-id"
+ },
"BucketKeyEnabled":{
"shape":"BucketKeyEnabled",
"documentation":"<p>Indicates whether the object uses an S3 Bucket Key for server-side encryption with AWS KMS (SSE-KMS).</p>",
"location":"header",
"locationName":"x-amz-server-side-encryption-bucket-key-enabled"
},
- "StorageClass":{
- "shape":"StorageClass",
+ "StorageClass":{
+ "shape":"StorageClass",
"documentation":"<p>Provides storage class information of the object. Amazon S3 returns this header for all objects except for S3 Standard storage class objects.</p> <p>For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/storage-class-intro.html\">Storage Classes</a>.</p>",
- "location":"header",
- "locationName":"x-amz-storage-class"
- },
- "RequestCharged":{
- "shape":"RequestCharged",
- "location":"header",
- "locationName":"x-amz-request-charged"
- },
- "ReplicationStatus":{
- "shape":"ReplicationStatus",
+ "location":"header",
+ "locationName":"x-amz-storage-class"
+ },
+ "RequestCharged":{
+ "shape":"RequestCharged",
+ "location":"header",
+ "locationName":"x-amz-request-charged"
+ },
+ "ReplicationStatus":{
+ "shape":"ReplicationStatus",
"documentation":"<p>Amazon S3 can return this header if your request involves a bucket that is either a source or a destination in a replication rule.</p> <p>In replication, you have a source bucket on which you configure replication and destination bucket or buckets where Amazon S3 stores object replicas. When you request an object (<code>GetObject</code>) or object metadata (<code>HeadObject</code>) from these buckets, Amazon S3 will return the <code>x-amz-replication-status</code> header in the response as follows:</p> <ul> <li> <p>If requesting an object from the source bucket — Amazon S3 will return the <code>x-amz-replication-status</code> header if the object in your request is eligible for replication.</p> <p> For example, suppose that in your replication configuration, you specify object prefix <code>TaxDocs</code> requesting Amazon S3 to replicate objects with key prefix <code>TaxDocs</code>. Any objects you upload with this key name prefix, for example <code>TaxDocs/document1.pdf</code>, are eligible for replication. For any object request with this key name prefix, Amazon S3 will return the <code>x-amz-replication-status</code> header with value PENDING, COMPLETED or FAILED indicating object replication status.</p> </li> <li> <p>If requesting an object from a destination bucket — Amazon S3 will return the <code>x-amz-replication-status</code> header with value REPLICA if the object in your request is a replica that Amazon S3 created and there is no replica modification replication in progress.</p> </li> <li> <p>When replicating objects to multiple destination buckets the <code>x-amz-replication-status</code> header acts differently. The header of the source object will only return a value of COMPLETED when replication is successful to all destinations. The header will remain at value PENDING until replication has completed for all destinations. If one or more destinations fails replication the header will return FAILED. </p> </li> </ul> <p>For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/NotificationHowTo.html\">Replication</a>.</p>",
- "location":"header",
- "locationName":"x-amz-replication-status"
- },
- "PartsCount":{
- "shape":"PartsCount",
+ "location":"header",
+ "locationName":"x-amz-replication-status"
+ },
+ "PartsCount":{
+ "shape":"PartsCount",
"documentation":"<p>The count of parts this object has.</p>",
- "location":"header",
- "locationName":"x-amz-mp-parts-count"
+ "location":"header",
+ "locationName":"x-amz-mp-parts-count"
},
"ObjectLockMode":{
"shape":"ObjectLockMode",
@@ -4794,157 +4794,157 @@
"documentation":"<p>Specifies whether a legal hold is in effect for this object. This header is only returned if the requester has the <code>s3:GetObjectLegalHold</code> permission. This header is not returned if the specified version of this object has never had a legal hold applied. For more information about S3 Object Lock, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/object-lock.html\">Object Lock</a>.</p>",
"location":"header",
"locationName":"x-amz-object-lock-legal-hold"
- }
- }
- },
- "HeadObjectRequest":{
- "type":"structure",
- "required":[
- "Bucket",
- "Key"
- ],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ }
+ }
+ },
+ "HeadObjectRequest":{
+ "type":"structure",
+ "required":[
+ "Bucket",
+ "Key"
+ ],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The name of the bucket containing the object.</p> <p>When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.s3-accesspoint.<i>Region</i>.amazonaws.com. When using this action with an access point through the AWS SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\">Using access points</a> in the <i>Amazon S3 User Guide</i>.</p> <p>When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.<i>outpostID</i>.s3-outposts.<i>Region</i>.amazonaws.com. When using this action using S3 on Outposts through the AWS SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html\">Using S3 on Outposts</a> in the <i>Amazon S3 User Guide</i>.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "IfMatch":{
- "shape":"IfMatch",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "IfMatch":{
+ "shape":"IfMatch",
"documentation":"<p>Return the object only if its entity tag (ETag) is the same as the one specified, otherwise return a 412 (precondition failed).</p>",
- "location":"header",
- "locationName":"If-Match"
- },
- "IfModifiedSince":{
- "shape":"IfModifiedSince",
+ "location":"header",
+ "locationName":"If-Match"
+ },
+ "IfModifiedSince":{
+ "shape":"IfModifiedSince",
"documentation":"<p>Return the object only if it has been modified since the specified time, otherwise return a 304 (not modified).</p>",
- "location":"header",
- "locationName":"If-Modified-Since"
- },
- "IfNoneMatch":{
- "shape":"IfNoneMatch",
+ "location":"header",
+ "locationName":"If-Modified-Since"
+ },
+ "IfNoneMatch":{
+ "shape":"IfNoneMatch",
"documentation":"<p>Return the object only if its entity tag (ETag) is different from the one specified, otherwise return a 304 (not modified).</p>",
- "location":"header",
- "locationName":"If-None-Match"
- },
- "IfUnmodifiedSince":{
- "shape":"IfUnmodifiedSince",
+ "location":"header",
+ "locationName":"If-None-Match"
+ },
+ "IfUnmodifiedSince":{
+ "shape":"IfUnmodifiedSince",
"documentation":"<p>Return the object only if it has not been modified since the specified time, otherwise return a 412 (precondition failed).</p>",
- "location":"header",
- "locationName":"If-Unmodified-Since"
- },
- "Key":{
- "shape":"ObjectKey",
+ "location":"header",
+ "locationName":"If-Unmodified-Since"
+ },
+ "Key":{
+ "shape":"ObjectKey",
"documentation":"<p>The object key.</p>",
- "location":"uri",
- "locationName":"Key"
- },
- "Range":{
- "shape":"Range",
+ "location":"uri",
+ "locationName":"Key"
+ },
+ "Range":{
+ "shape":"Range",
"documentation":"<p>Downloads the specified range bytes of an object. For more information about the HTTP Range header, see <a href=\"http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35\">http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35</a>.</p> <note> <p>Amazon S3 doesn't support retrieving multiple ranges of data per <code>GET</code> request.</p> </note>",
- "location":"header",
- "locationName":"Range"
- },
- "VersionId":{
- "shape":"ObjectVersionId",
+ "location":"header",
+ "locationName":"Range"
+ },
+ "VersionId":{
+ "shape":"ObjectVersionId",
"documentation":"<p>VersionId used to reference a specific version of the object.</p>",
- "location":"querystring",
- "locationName":"versionId"
- },
- "SSECustomerAlgorithm":{
- "shape":"SSECustomerAlgorithm",
+ "location":"querystring",
+ "locationName":"versionId"
+ },
+ "SSECustomerAlgorithm":{
+ "shape":"SSECustomerAlgorithm",
"documentation":"<p>Specifies the algorithm to use to when encrypting the object (for example, AES256).</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-customer-algorithm"
- },
- "SSECustomerKey":{
- "shape":"SSECustomerKey",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-customer-algorithm"
+ },
+ "SSECustomerKey":{
+ "shape":"SSECustomerKey",
"documentation":"<p>Specifies the customer-provided encryption key for Amazon S3 to use in encrypting data. This value is used to store the object and then it is discarded; Amazon S3 does not store the encryption key. The key must be appropriate for use with the algorithm specified in the <code>x-amz-server-side-encryption-customer-algorithm</code> header.</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-customer-key"
- },
- "SSECustomerKeyMD5":{
- "shape":"SSECustomerKeyMD5",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-customer-key"
+ },
+ "SSECustomerKeyMD5":{
+ "shape":"SSECustomerKeyMD5",
"documentation":"<p>Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. Amazon S3 uses this header for a message integrity check to ensure that the encryption key was transmitted without error.</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-customer-key-MD5"
- },
- "RequestPayer":{
- "shape":"RequestPayer",
- "location":"header",
- "locationName":"x-amz-request-payer"
- },
- "PartNumber":{
- "shape":"PartNumber",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-customer-key-MD5"
+ },
+ "RequestPayer":{
+ "shape":"RequestPayer",
+ "location":"header",
+ "locationName":"x-amz-request-payer"
+ },
+ "PartNumber":{
+ "shape":"PartNumber",
"documentation":"<p>Part number of the object being read. This is a positive integer between 1 and 10,000. Effectively performs a 'ranged' HEAD request for the part specified. Useful querying about the size of the part and the number of parts in this object.</p>",
- "location":"querystring",
- "locationName":"partNumber"
+ "location":"querystring",
+ "locationName":"partNumber"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
- "HostName":{"type":"string"},
- "HttpErrorCodeReturnedEquals":{"type":"string"},
- "HttpRedirectCode":{"type":"string"},
- "ID":{"type":"string"},
- "IfMatch":{"type":"string"},
- "IfModifiedSince":{"type":"timestamp"},
- "IfNoneMatch":{"type":"string"},
- "IfUnmodifiedSince":{"type":"timestamp"},
- "IndexDocument":{
- "type":"structure",
- "required":["Suffix"],
- "members":{
- "Suffix":{
- "shape":"Suffix",
+ }
+ }
+ },
+ "HostName":{"type":"string"},
+ "HttpErrorCodeReturnedEquals":{"type":"string"},
+ "HttpRedirectCode":{"type":"string"},
+ "ID":{"type":"string"},
+ "IfMatch":{"type":"string"},
+ "IfModifiedSince":{"type":"timestamp"},
+ "IfNoneMatch":{"type":"string"},
+ "IfUnmodifiedSince":{"type":"timestamp"},
+ "IndexDocument":{
+ "type":"structure",
+ "required":["Suffix"],
+ "members":{
+ "Suffix":{
+ "shape":"Suffix",
"documentation":"<p>A suffix that is appended to a request that is for a directory on the website endpoint (for example,if the suffix is index.html and you make a request to samplebucket/images/ the data that is returned will be for the object with the key name images/index.html) The suffix must not be empty and must not include a slash character.</p> <important> <p>Replacement must be made for object keys containing special characters (such as carriage returns) when using XML requests. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-keys.html#object-key-xml-related-constraints\"> XML related object key constraints</a>.</p> </important>"
- }
+ }
},
"documentation":"<p>Container for the <code>Suffix</code> element.</p>"
- },
- "Initiated":{"type":"timestamp"},
- "Initiator":{
- "type":"structure",
- "members":{
- "ID":{
- "shape":"ID",
+ },
+ "Initiated":{"type":"timestamp"},
+ "Initiator":{
+ "type":"structure",
+ "members":{
+ "ID":{
+ "shape":"ID",
"documentation":"<p>If the principal is an AWS account, it provides the Canonical User ID. If the principal is an IAM User, it provides a user ARN value.</p>"
- },
- "DisplayName":{
- "shape":"DisplayName",
+ },
+ "DisplayName":{
+ "shape":"DisplayName",
"documentation":"<p>Name of the Principal.</p>"
- }
+ }
},
"documentation":"<p>Container element that identifies who initiated the multipart upload. </p>"
- },
- "InputSerialization":{
- "type":"structure",
- "members":{
- "CSV":{
- "shape":"CSVInput",
+ },
+ "InputSerialization":{
+ "type":"structure",
+ "members":{
+ "CSV":{
+ "shape":"CSVInput",
"documentation":"<p>Describes the serialization of a CSV-encoded object.</p>"
- },
- "CompressionType":{
- "shape":"CompressionType",
+ },
+ "CompressionType":{
+ "shape":"CompressionType",
"documentation":"<p>Specifies object's compression format. Valid values: NONE, GZIP, BZIP2. Default Value: NONE.</p>"
- },
- "JSON":{
- "shape":"JSONInput",
+ },
+ "JSON":{
+ "shape":"JSONInput",
"documentation":"<p>Specifies JSON as object's input serialization format.</p>"
},
"Parquet":{
"shape":"ParquetInput",
"documentation":"<p>Specifies Parquet as object's input serialization format.</p>"
- }
- },
+ }
+ },
"documentation":"<p>Describes the serialization format of the object.</p>"
- },
+ },
"IntelligentTieringAccessTier":{
"type":"string",
"enum":[
@@ -5034,394 +5034,394 @@
"documentation":"<p>Object is archived and inaccessible until restored.</p>",
"exception":true
},
- "InventoryConfiguration":{
- "type":"structure",
- "required":[
- "Destination",
- "IsEnabled",
- "Id",
- "IncludedObjectVersions",
- "Schedule"
- ],
- "members":{
- "Destination":{
- "shape":"InventoryDestination",
+ "InventoryConfiguration":{
+ "type":"structure",
+ "required":[
+ "Destination",
+ "IsEnabled",
+ "Id",
+ "IncludedObjectVersions",
+ "Schedule"
+ ],
+ "members":{
+ "Destination":{
+ "shape":"InventoryDestination",
"documentation":"<p>Contains information about where to publish the inventory results.</p>"
- },
- "IsEnabled":{
- "shape":"IsEnabled",
+ },
+ "IsEnabled":{
+ "shape":"IsEnabled",
"documentation":"<p>Specifies whether the inventory is enabled or disabled. If set to <code>True</code>, an inventory list is generated. If set to <code>False</code>, no inventory list is generated.</p>"
- },
- "Filter":{
- "shape":"InventoryFilter",
+ },
+ "Filter":{
+ "shape":"InventoryFilter",
"documentation":"<p>Specifies an inventory filter. The inventory only includes objects that meet the filter's criteria.</p>"
- },
- "Id":{
- "shape":"InventoryId",
+ },
+ "Id":{
+ "shape":"InventoryId",
"documentation":"<p>The ID used to identify the inventory configuration.</p>"
- },
- "IncludedObjectVersions":{
- "shape":"InventoryIncludedObjectVersions",
+ },
+ "IncludedObjectVersions":{
+ "shape":"InventoryIncludedObjectVersions",
"documentation":"<p>Object versions to include in the inventory list. If set to <code>All</code>, the list includes all the object versions, which adds the version-related fields <code>VersionId</code>, <code>IsLatest</code>, and <code>DeleteMarker</code> to the list. If set to <code>Current</code>, the list does not contain these version-related fields.</p>"
- },
- "OptionalFields":{
- "shape":"InventoryOptionalFields",
+ },
+ "OptionalFields":{
+ "shape":"InventoryOptionalFields",
"documentation":"<p>Contains the optional fields that are included in the inventory results.</p>"
- },
- "Schedule":{
- "shape":"InventorySchedule",
+ },
+ "Schedule":{
+ "shape":"InventorySchedule",
"documentation":"<p>Specifies the schedule for generating inventory results.</p>"
- }
+ }
},
"documentation":"<p>Specifies the inventory configuration for an Amazon S3 bucket. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketGETInventoryConfig.html\">GET Bucket inventory</a> in the <i>Amazon S3 API Reference</i>. </p>"
- },
- "InventoryConfigurationList":{
- "type":"list",
- "member":{"shape":"InventoryConfiguration"},
- "flattened":true
- },
- "InventoryDestination":{
- "type":"structure",
- "required":["S3BucketDestination"],
- "members":{
- "S3BucketDestination":{
- "shape":"InventoryS3BucketDestination",
+ },
+ "InventoryConfigurationList":{
+ "type":"list",
+ "member":{"shape":"InventoryConfiguration"},
+ "flattened":true
+ },
+ "InventoryDestination":{
+ "type":"structure",
+ "required":["S3BucketDestination"],
+ "members":{
+ "S3BucketDestination":{
+ "shape":"InventoryS3BucketDestination",
"documentation":"<p>Contains the bucket name, file format, bucket owner (optional), and prefix (optional) where inventory results are published.</p>"
- }
+ }
},
"documentation":"<p>Specifies the inventory configuration for an Amazon S3 bucket.</p>"
- },
- "InventoryEncryption":{
- "type":"structure",
- "members":{
- "SSES3":{
- "shape":"SSES3",
+ },
+ "InventoryEncryption":{
+ "type":"structure",
+ "members":{
+ "SSES3":{
+ "shape":"SSES3",
"documentation":"<p>Specifies the use of SSE-S3 to encrypt delivered inventory reports.</p>",
- "locationName":"SSE-S3"
- },
- "SSEKMS":{
- "shape":"SSEKMS",
+ "locationName":"SSE-S3"
+ },
+ "SSEKMS":{
+ "shape":"SSEKMS",
"documentation":"<p>Specifies the use of SSE-KMS to encrypt delivered inventory reports.</p>",
- "locationName":"SSE-KMS"
- }
- },
+ "locationName":"SSE-KMS"
+ }
+ },
"documentation":"<p>Contains the type of server-side encryption used to encrypt the inventory results.</p>"
- },
- "InventoryFilter":{
- "type":"structure",
- "required":["Prefix"],
- "members":{
- "Prefix":{
- "shape":"Prefix",
+ },
+ "InventoryFilter":{
+ "type":"structure",
+ "required":["Prefix"],
+ "members":{
+ "Prefix":{
+ "shape":"Prefix",
"documentation":"<p>The prefix that an object must have to be included in the inventory results.</p>"
- }
+ }
},
"documentation":"<p>Specifies an inventory filter. The inventory only includes objects that meet the filter's criteria.</p>"
- },
- "InventoryFormat":{
- "type":"string",
- "enum":[
- "CSV",
+ },
+ "InventoryFormat":{
+ "type":"string",
+ "enum":[
+ "CSV",
"ORC",
"Parquet"
- ]
- },
- "InventoryFrequency":{
- "type":"string",
- "enum":[
- "Daily",
- "Weekly"
- ]
- },
- "InventoryId":{"type":"string"},
- "InventoryIncludedObjectVersions":{
- "type":"string",
- "enum":[
- "All",
- "Current"
- ]
- },
- "InventoryOptionalField":{
- "type":"string",
- "enum":[
- "Size",
- "LastModifiedDate",
- "StorageClass",
- "ETag",
- "IsMultipartUploaded",
- "ReplicationStatus",
+ ]
+ },
+ "InventoryFrequency":{
+ "type":"string",
+ "enum":[
+ "Daily",
+ "Weekly"
+ ]
+ },
+ "InventoryId":{"type":"string"},
+ "InventoryIncludedObjectVersions":{
+ "type":"string",
+ "enum":[
+ "All",
+ "Current"
+ ]
+ },
+ "InventoryOptionalField":{
+ "type":"string",
+ "enum":[
+ "Size",
+ "LastModifiedDate",
+ "StorageClass",
+ "ETag",
+ "IsMultipartUploaded",
+ "ReplicationStatus",
"EncryptionStatus",
"ObjectLockRetainUntilDate",
"ObjectLockMode",
"ObjectLockLegalHoldStatus",
"IntelligentTieringAccessTier",
"BucketKeyStatus"
- ]
- },
- "InventoryOptionalFields":{
- "type":"list",
- "member":{
- "shape":"InventoryOptionalField",
- "locationName":"Field"
- }
- },
- "InventoryS3BucketDestination":{
- "type":"structure",
- "required":[
- "Bucket",
- "Format"
- ],
- "members":{
- "AccountId":{
- "shape":"AccountId",
+ ]
+ },
+ "InventoryOptionalFields":{
+ "type":"list",
+ "member":{
+ "shape":"InventoryOptionalField",
+ "locationName":"Field"
+ }
+ },
+ "InventoryS3BucketDestination":{
+ "type":"structure",
+ "required":[
+ "Bucket",
+ "Format"
+ ],
+ "members":{
+ "AccountId":{
+ "shape":"AccountId",
"documentation":"<p>The account ID that owns the destination S3 bucket. If no account ID is provided, the owner is not validated before exporting data. </p> <note> <p> Although this value is optional, we strongly recommend that you set it to help prevent problems if the destination bucket ownership changes. </p> </note>"
- },
- "Bucket":{
- "shape":"BucketName",
+ },
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The Amazon Resource Name (ARN) of the bucket where inventory results will be published.</p>"
- },
- "Format":{
- "shape":"InventoryFormat",
+ },
+ "Format":{
+ "shape":"InventoryFormat",
"documentation":"<p>Specifies the output format of the inventory results.</p>"
- },
- "Prefix":{
- "shape":"Prefix",
+ },
+ "Prefix":{
+ "shape":"Prefix",
"documentation":"<p>The prefix that is prepended to all inventory results.</p>"
- },
- "Encryption":{
- "shape":"InventoryEncryption",
+ },
+ "Encryption":{
+ "shape":"InventoryEncryption",
"documentation":"<p>Contains the type of server-side encryption used to encrypt the inventory results.</p>"
- }
+ }
},
"documentation":"<p>Contains the bucket name, file format, bucket owner (optional), and prefix (optional) where inventory results are published.</p>"
- },
- "InventorySchedule":{
- "type":"structure",
- "required":["Frequency"],
- "members":{
- "Frequency":{
- "shape":"InventoryFrequency",
+ },
+ "InventorySchedule":{
+ "type":"structure",
+ "required":["Frequency"],
+ "members":{
+ "Frequency":{
+ "shape":"InventoryFrequency",
"documentation":"<p>Specifies how frequently inventory results are produced.</p>"
- }
+ }
},
"documentation":"<p>Specifies the schedule for generating inventory results.</p>"
- },
- "IsEnabled":{"type":"boolean"},
- "IsLatest":{"type":"boolean"},
+ },
+ "IsEnabled":{"type":"boolean"},
+ "IsLatest":{"type":"boolean"},
"IsPublic":{"type":"boolean"},
- "IsTruncated":{"type":"boolean"},
- "JSONInput":{
- "type":"structure",
- "members":{
- "Type":{
- "shape":"JSONType",
+ "IsTruncated":{"type":"boolean"},
+ "JSONInput":{
+ "type":"structure",
+ "members":{
+ "Type":{
+ "shape":"JSONType",
"documentation":"<p>The type of JSON. Valid values: Document, Lines.</p>"
- }
+ }
},
"documentation":"<p>Specifies JSON as object's input serialization format.</p>"
- },
- "JSONOutput":{
- "type":"structure",
- "members":{
- "RecordDelimiter":{
- "shape":"RecordDelimiter",
+ },
+ "JSONOutput":{
+ "type":"structure",
+ "members":{
+ "RecordDelimiter":{
+ "shape":"RecordDelimiter",
"documentation":"<p>The value used to separate individual records in the output. If no value is specified, Amazon S3 uses a newline character ('\\n').</p>"
- }
+ }
},
"documentation":"<p>Specifies JSON as request's output serialization format.</p>"
- },
- "JSONType":{
- "type":"string",
- "enum":[
- "DOCUMENT",
- "LINES"
- ]
- },
- "KMSContext":{"type":"string"},
- "KeyCount":{"type":"integer"},
- "KeyMarker":{"type":"string"},
- "KeyPrefixEquals":{"type":"string"},
- "LambdaFunctionArn":{"type":"string"},
- "LambdaFunctionConfiguration":{
- "type":"structure",
- "required":[
- "LambdaFunctionArn",
- "Events"
- ],
- "members":{
- "Id":{"shape":"NotificationId"},
- "LambdaFunctionArn":{
- "shape":"LambdaFunctionArn",
+ },
+ "JSONType":{
+ "type":"string",
+ "enum":[
+ "DOCUMENT",
+ "LINES"
+ ]
+ },
+ "KMSContext":{"type":"string"},
+ "KeyCount":{"type":"integer"},
+ "KeyMarker":{"type":"string"},
+ "KeyPrefixEquals":{"type":"string"},
+ "LambdaFunctionArn":{"type":"string"},
+ "LambdaFunctionConfiguration":{
+ "type":"structure",
+ "required":[
+ "LambdaFunctionArn",
+ "Events"
+ ],
+ "members":{
+ "Id":{"shape":"NotificationId"},
+ "LambdaFunctionArn":{
+ "shape":"LambdaFunctionArn",
"documentation":"<p>The Amazon Resource Name (ARN) of the AWS Lambda function that Amazon S3 invokes when the specified event type occurs.</p>",
- "locationName":"CloudFunction"
- },
- "Events":{
- "shape":"EventList",
+ "locationName":"CloudFunction"
+ },
+ "Events":{
+ "shape":"EventList",
"documentation":"<p>The Amazon S3 bucket event for which to invoke the AWS Lambda function. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/NotificationHowTo.html\">Supported Event Types</a> in the <i>Amazon S3 User Guide</i>.</p>",
- "locationName":"Event"
- },
+ "locationName":"Event"
+ },
"Filter":{"shape":"NotificationConfigurationFilter"}
- },
+ },
"documentation":"<p>A container for specifying the configuration for AWS Lambda notifications.</p>"
- },
- "LambdaFunctionConfigurationList":{
- "type":"list",
- "member":{"shape":"LambdaFunctionConfiguration"},
- "flattened":true
- },
- "LastModified":{"type":"timestamp"},
- "LifecycleConfiguration":{
- "type":"structure",
- "required":["Rules"],
- "members":{
- "Rules":{
- "shape":"Rules",
+ },
+ "LambdaFunctionConfigurationList":{
+ "type":"list",
+ "member":{"shape":"LambdaFunctionConfiguration"},
+ "flattened":true
+ },
+ "LastModified":{"type":"timestamp"},
+ "LifecycleConfiguration":{
+ "type":"structure",
+ "required":["Rules"],
+ "members":{
+ "Rules":{
+ "shape":"Rules",
"documentation":"<p>Specifies lifecycle configuration rules for an Amazon S3 bucket. </p>",
- "locationName":"Rule"
- }
+ "locationName":"Rule"
+ }
},
"documentation":"<p>Container for lifecycle rules. You can add as many as 1000 rules.</p>"
- },
- "LifecycleExpiration":{
- "type":"structure",
- "members":{
- "Date":{
- "shape":"Date",
+ },
+ "LifecycleExpiration":{
+ "type":"structure",
+ "members":{
+ "Date":{
+ "shape":"Date",
"documentation":"<p>Indicates at what date the object is to be moved or deleted. Should be in GMT ISO 8601 Format.</p>"
- },
- "Days":{
- "shape":"Days",
+ },
+ "Days":{
+ "shape":"Days",
"documentation":"<p>Indicates the lifetime, in days, of the objects that are subject to the rule. The value must be a non-zero positive integer.</p>"
- },
- "ExpiredObjectDeleteMarker":{
- "shape":"ExpiredObjectDeleteMarker",
+ },
+ "ExpiredObjectDeleteMarker":{
+ "shape":"ExpiredObjectDeleteMarker",
"documentation":"<p>Indicates whether Amazon S3 will remove a delete marker with no noncurrent versions. If set to true, the delete marker will be expired; if set to false the policy takes no action. This cannot be specified with Days or Date in a Lifecycle Expiration Policy.</p>"
- }
+ }
},
"documentation":"<p>Container for the expiration for the lifecycle of the object.</p>"
- },
- "LifecycleRule":{
- "type":"structure",
- "required":["Status"],
- "members":{
+ },
+ "LifecycleRule":{
+ "type":"structure",
+ "required":["Status"],
+ "members":{
"Expiration":{
"shape":"LifecycleExpiration",
"documentation":"<p>Specifies the expiration for the lifecycle of the object in the form of date, days and, whether the object has a delete marker.</p>"
},
- "ID":{
- "shape":"ID",
+ "ID":{
+ "shape":"ID",
"documentation":"<p>Unique identifier for the rule. The value cannot be longer than 255 characters.</p>"
- },
- "Prefix":{
- "shape":"Prefix",
+ },
+ "Prefix":{
+ "shape":"Prefix",
"documentation":"<p>Prefix identifying one or more objects to which the rule applies. This is no longer used; use <code>Filter</code> instead.</p> <important> <p>Replacement must be made for object keys containing special characters (such as carriage returns) when using XML requests. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-keys.html#object-key-xml-related-constraints\"> XML related object key constraints</a>.</p> </important>",
- "deprecated":true
- },
+ "deprecated":true
+ },
"Filter":{
"shape":"LifecycleRuleFilter",
"documentation":"<p>The <code>Filter</code> is used to identify objects that a Lifecycle Rule applies to. A <code>Filter</code> must have exactly one of <code>Prefix</code>, <code>Tag</code>, or <code>And</code> specified. <code>Filter</code> is required if the <code>LifecycleRule</code> does not containt a <code>Prefix</code> element.</p>"
},
- "Status":{
- "shape":"ExpirationStatus",
+ "Status":{
+ "shape":"ExpirationStatus",
"documentation":"<p>If 'Enabled', the rule is currently being applied. If 'Disabled', the rule is not currently being applied.</p>"
- },
- "Transitions":{
- "shape":"TransitionList",
+ },
+ "Transitions":{
+ "shape":"TransitionList",
"documentation":"<p>Specifies when an Amazon S3 object transitions to a specified storage class.</p>",
- "locationName":"Transition"
- },
- "NoncurrentVersionTransitions":{
- "shape":"NoncurrentVersionTransitionList",
+ "locationName":"Transition"
+ },
+ "NoncurrentVersionTransitions":{
+ "shape":"NoncurrentVersionTransitionList",
"documentation":"<p> Specifies the transition rule for the lifecycle rule that describes when noncurrent objects transition to a specific storage class. If your bucket is versioning-enabled (or versioning is suspended), you can set this action to request that Amazon S3 transition noncurrent object versions to a specific storage class at a set period in the object's lifetime. </p>",
- "locationName":"NoncurrentVersionTransition"
- },
+ "locationName":"NoncurrentVersionTransition"
+ },
"NoncurrentVersionExpiration":{"shape":"NoncurrentVersionExpiration"},
"AbortIncompleteMultipartUpload":{"shape":"AbortIncompleteMultipartUpload"}
},
"documentation":"<p>A lifecycle rule for individual objects in an Amazon S3 bucket.</p>"
- },
- "LifecycleRuleAndOperator":{
- "type":"structure",
- "members":{
+ },
+ "LifecycleRuleAndOperator":{
+ "type":"structure",
+ "members":{
"Prefix":{
"shape":"Prefix",
"documentation":"<p>Prefix identifying one or more objects to which the rule applies.</p>"
},
- "Tags":{
- "shape":"TagSet",
+ "Tags":{
+ "shape":"TagSet",
"documentation":"<p>All of these tags must exist in the object's tag set in order for the rule to apply.</p>",
- "flattened":true,
- "locationName":"Tag"
- }
- },
+ "flattened":true,
+ "locationName":"Tag"
+ }
+ },
"documentation":"<p>This is used in a Lifecycle Rule Filter to apply a logical AND to two or more predicates. The Lifecycle Rule will apply to any object matching all of the predicates configured inside the And operator.</p>"
- },
- "LifecycleRuleFilter":{
- "type":"structure",
- "members":{
- "Prefix":{
- "shape":"Prefix",
+ },
+ "LifecycleRuleFilter":{
+ "type":"structure",
+ "members":{
+ "Prefix":{
+ "shape":"Prefix",
"documentation":"<p>Prefix identifying one or more objects to which the rule applies.</p> <important> <p>Replacement must be made for object keys containing special characters (such as carriage returns) when using XML requests. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-keys.html#object-key-xml-related-constraints\"> XML related object key constraints</a>.</p> </important>"
- },
- "Tag":{
- "shape":"Tag",
+ },
+ "Tag":{
+ "shape":"Tag",
"documentation":"<p>This tag must exist in the object's tag set in order for the rule to apply.</p>"
- },
+ },
"And":{"shape":"LifecycleRuleAndOperator"}
- },
+ },
"documentation":"<p>The <code>Filter</code> is used to identify objects that a Lifecycle Rule applies to. A <code>Filter</code> must have exactly one of <code>Prefix</code>, <code>Tag</code>, or <code>And</code> specified.</p>"
- },
- "LifecycleRules":{
- "type":"list",
- "member":{"shape":"LifecycleRule"},
- "flattened":true
- },
- "ListBucketAnalyticsConfigurationsOutput":{
- "type":"structure",
- "members":{
- "IsTruncated":{
- "shape":"IsTruncated",
+ },
+ "LifecycleRules":{
+ "type":"list",
+ "member":{"shape":"LifecycleRule"},
+ "flattened":true
+ },
+ "ListBucketAnalyticsConfigurationsOutput":{
+ "type":"structure",
+ "members":{
+ "IsTruncated":{
+ "shape":"IsTruncated",
"documentation":"<p>Indicates whether the returned list of analytics configurations is complete. A value of true indicates that the list is not complete and the NextContinuationToken will be provided for a subsequent request.</p>"
- },
- "ContinuationToken":{
- "shape":"Token",
+ },
+ "ContinuationToken":{
+ "shape":"Token",
"documentation":"<p>The marker that is used as a starting point for this analytics configuration list response. This value is present if it was sent in the request.</p>"
- },
- "NextContinuationToken":{
- "shape":"NextToken",
+ },
+ "NextContinuationToken":{
+ "shape":"NextToken",
"documentation":"<p> <code>NextContinuationToken</code> is sent when <code>isTruncated</code> is true, which indicates that there are more analytics configurations to list. The next request must include this <code>NextContinuationToken</code>. The token is obfuscated and is not a usable value.</p>"
- },
- "AnalyticsConfigurationList":{
- "shape":"AnalyticsConfigurationList",
+ },
+ "AnalyticsConfigurationList":{
+ "shape":"AnalyticsConfigurationList",
"documentation":"<p>The list of analytics configurations for a bucket.</p>",
- "locationName":"AnalyticsConfiguration"
- }
- }
- },
- "ListBucketAnalyticsConfigurationsRequest":{
- "type":"structure",
- "required":["Bucket"],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ "locationName":"AnalyticsConfiguration"
+ }
+ }
+ },
+ "ListBucketAnalyticsConfigurationsRequest":{
+ "type":"structure",
+ "required":["Bucket"],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The name of the bucket from which analytics configurations are retrieved.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "ContinuationToken":{
- "shape":"Token",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "ContinuationToken":{
+ "shape":"Token",
"documentation":"<p>The ContinuationToken that represents a placeholder from where this request should begin.</p>",
- "location":"querystring",
- "locationName":"continuation-token"
+ "location":"querystring",
+ "locationName":"continuation-token"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
+ }
+ }
+ },
"ListBucketIntelligentTieringConfigurationsOutput":{
"type":"structure",
"members":{
@@ -5462,101 +5462,101 @@
}
}
},
- "ListBucketInventoryConfigurationsOutput":{
- "type":"structure",
- "members":{
- "ContinuationToken":{
- "shape":"Token",
+ "ListBucketInventoryConfigurationsOutput":{
+ "type":"structure",
+ "members":{
+ "ContinuationToken":{
+ "shape":"Token",
"documentation":"<p>If sent in the request, the marker that is used as a starting point for this inventory configuration list response.</p>"
- },
- "InventoryConfigurationList":{
- "shape":"InventoryConfigurationList",
+ },
+ "InventoryConfigurationList":{
+ "shape":"InventoryConfigurationList",
"documentation":"<p>The list of inventory configurations for a bucket.</p>",
- "locationName":"InventoryConfiguration"
- },
- "IsTruncated":{
- "shape":"IsTruncated",
+ "locationName":"InventoryConfiguration"
+ },
+ "IsTruncated":{
+ "shape":"IsTruncated",
"documentation":"<p>Tells whether the returned list of inventory configurations is complete. A value of true indicates that the list is not complete and the NextContinuationToken is provided for a subsequent request.</p>"
- },
- "NextContinuationToken":{
- "shape":"NextToken",
+ },
+ "NextContinuationToken":{
+ "shape":"NextToken",
"documentation":"<p>The marker used to continue this inventory configuration listing. Use the <code>NextContinuationToken</code> from this response to continue the listing in a subsequent request. The continuation token is an opaque value that Amazon S3 understands.</p>"
- }
- }
- },
- "ListBucketInventoryConfigurationsRequest":{
- "type":"structure",
- "required":["Bucket"],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ }
+ }
+ },
+ "ListBucketInventoryConfigurationsRequest":{
+ "type":"structure",
+ "required":["Bucket"],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The name of the bucket containing the inventory configurations to retrieve.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "ContinuationToken":{
- "shape":"Token",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "ContinuationToken":{
+ "shape":"Token",
"documentation":"<p>The marker used to continue an inventory configuration listing that has been truncated. Use the NextContinuationToken from a previously truncated list response to continue the listing. The continuation token is an opaque value that Amazon S3 understands.</p>",
- "location":"querystring",
- "locationName":"continuation-token"
+ "location":"querystring",
+ "locationName":"continuation-token"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
- "ListBucketMetricsConfigurationsOutput":{
- "type":"structure",
- "members":{
- "IsTruncated":{
- "shape":"IsTruncated",
+ }
+ }
+ },
+ "ListBucketMetricsConfigurationsOutput":{
+ "type":"structure",
+ "members":{
+ "IsTruncated":{
+ "shape":"IsTruncated",
"documentation":"<p>Indicates whether the returned list of metrics configurations is complete. A value of true indicates that the list is not complete and the NextContinuationToken will be provided for a subsequent request.</p>"
- },
- "ContinuationToken":{
- "shape":"Token",
+ },
+ "ContinuationToken":{
+ "shape":"Token",
"documentation":"<p>The marker that is used as a starting point for this metrics configuration list response. This value is present if it was sent in the request.</p>"
- },
- "NextContinuationToken":{
- "shape":"NextToken",
+ },
+ "NextContinuationToken":{
+ "shape":"NextToken",
"documentation":"<p>The marker used to continue a metrics configuration listing that has been truncated. Use the <code>NextContinuationToken</code> from a previously truncated list response to continue the listing. The continuation token is an opaque value that Amazon S3 understands.</p>"
- },
- "MetricsConfigurationList":{
- "shape":"MetricsConfigurationList",
+ },
+ "MetricsConfigurationList":{
+ "shape":"MetricsConfigurationList",
"documentation":"<p>The list of metrics configurations for a bucket.</p>",
- "locationName":"MetricsConfiguration"
- }
- }
- },
- "ListBucketMetricsConfigurationsRequest":{
- "type":"structure",
- "required":["Bucket"],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ "locationName":"MetricsConfiguration"
+ }
+ }
+ },
+ "ListBucketMetricsConfigurationsRequest":{
+ "type":"structure",
+ "required":["Bucket"],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The name of the bucket containing the metrics configurations to retrieve.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "ContinuationToken":{
- "shape":"Token",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "ContinuationToken":{
+ "shape":"Token",
"documentation":"<p>The marker that is used to continue a metrics configuration listing that has been truncated. Use the NextContinuationToken from a previously truncated list response to continue the listing. The continuation token is an opaque value that Amazon S3 understands.</p>",
- "location":"querystring",
- "locationName":"continuation-token"
+ "location":"querystring",
+ "locationName":"continuation-token"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
- "ListBucketsOutput":{
- "type":"structure",
- "members":{
+ }
+ }
+ },
+ "ListBucketsOutput":{
+ "type":"structure",
+ "members":{
"Buckets":{
"shape":"Buckets",
"documentation":"<p>The list of buckets owned by the requestor.</p>"
@@ -5565,148 +5565,148 @@
"shape":"Owner",
"documentation":"<p>The owner of the buckets listed.</p>"
}
- }
- },
- "ListMultipartUploadsOutput":{
- "type":"structure",
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ }
+ },
+ "ListMultipartUploadsOutput":{
+ "type":"structure",
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The name of the bucket to which the multipart upload was initiated.</p>"
- },
- "KeyMarker":{
- "shape":"KeyMarker",
+ },
+ "KeyMarker":{
+ "shape":"KeyMarker",
"documentation":"<p>The key at or after which the listing began.</p>"
- },
- "UploadIdMarker":{
- "shape":"UploadIdMarker",
+ },
+ "UploadIdMarker":{
+ "shape":"UploadIdMarker",
"documentation":"<p>Upload ID after which listing began.</p>"
- },
- "NextKeyMarker":{
- "shape":"NextKeyMarker",
+ },
+ "NextKeyMarker":{
+ "shape":"NextKeyMarker",
"documentation":"<p>When a list is truncated, this element specifies the value that should be used for the key-marker request parameter in a subsequent request.</p>"
- },
- "Prefix":{
- "shape":"Prefix",
+ },
+ "Prefix":{
+ "shape":"Prefix",
"documentation":"<p>When a prefix is provided in the request, this field contains the specified prefix. The result contains only keys starting with the specified prefix.</p>"
- },
+ },
"Delimiter":{
"shape":"Delimiter",
"documentation":"<p>Contains the delimiter you specified in the request. If you don't specify a delimiter in your request, this element is absent from the response.</p>"
},
- "NextUploadIdMarker":{
- "shape":"NextUploadIdMarker",
+ "NextUploadIdMarker":{
+ "shape":"NextUploadIdMarker",
"documentation":"<p>When a list is truncated, this element specifies the value that should be used for the <code>upload-id-marker</code> request parameter in a subsequent request.</p>"
- },
- "MaxUploads":{
- "shape":"MaxUploads",
+ },
+ "MaxUploads":{
+ "shape":"MaxUploads",
"documentation":"<p>Maximum number of multipart uploads that could have been included in the response.</p>"
- },
- "IsTruncated":{
- "shape":"IsTruncated",
+ },
+ "IsTruncated":{
+ "shape":"IsTruncated",
"documentation":"<p>Indicates whether the returned list of multipart uploads is truncated. A value of true indicates that the list was truncated. The list can be truncated if the number of multipart uploads exceeds the limit allowed or specified by max uploads.</p>"
- },
- "Uploads":{
- "shape":"MultipartUploadList",
+ },
+ "Uploads":{
+ "shape":"MultipartUploadList",
"documentation":"<p>Container for elements related to a particular multipart upload. A response can contain zero or more <code>Upload</code> elements.</p>",
- "locationName":"Upload"
- },
+ "locationName":"Upload"
+ },
"CommonPrefixes":{
"shape":"CommonPrefixList",
"documentation":"<p>If you specify a delimiter in the request, then the result returns each distinct key prefix containing the delimiter in a <code>CommonPrefixes</code> element. The distinct key prefixes are returned in the <code>Prefix</code> child element.</p>"
},
- "EncodingType":{
- "shape":"EncodingType",
+ "EncodingType":{
+ "shape":"EncodingType",
"documentation":"<p>Encoding type used by Amazon S3 to encode object keys in the response.</p> <p>If you specify <code>encoding-type</code> request parameter, Amazon S3 includes this element in the response, and returns encoded key name values in the following response elements:</p> <p> <code>Delimiter</code>, <code>KeyMarker</code>, <code>Prefix</code>, <code>NextKeyMarker</code>, <code>Key</code>.</p>"
- }
- }
- },
- "ListMultipartUploadsRequest":{
- "type":"structure",
- "required":["Bucket"],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ }
+ }
+ },
+ "ListMultipartUploadsRequest":{
+ "type":"structure",
+ "required":["Bucket"],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The name of the bucket to which the multipart upload was initiated. </p> <p>When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.s3-accesspoint.<i>Region</i>.amazonaws.com. When using this action with an access point through the AWS SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\">Using access points</a> in the <i>Amazon S3 User Guide</i>.</p> <p>When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.<i>outpostID</i>.s3-outposts.<i>Region</i>.amazonaws.com. When using this action using S3 on Outposts through the AWS SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html\">Using S3 on Outposts</a> in the <i>Amazon S3 User Guide</i>.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "Delimiter":{
- "shape":"Delimiter",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "Delimiter":{
+ "shape":"Delimiter",
"documentation":"<p>Character you use to group keys.</p> <p>All keys that contain the same string between the prefix, if specified, and the first occurrence of the delimiter after the prefix are grouped under a single result element, <code>CommonPrefixes</code>. If you don't specify the prefix parameter, then the substring starts at the beginning of the key. The keys that are grouped under <code>CommonPrefixes</code> result element are not returned elsewhere in the response.</p>",
- "location":"querystring",
- "locationName":"delimiter"
- },
- "EncodingType":{
- "shape":"EncodingType",
- "location":"querystring",
- "locationName":"encoding-type"
- },
- "KeyMarker":{
- "shape":"KeyMarker",
+ "location":"querystring",
+ "locationName":"delimiter"
+ },
+ "EncodingType":{
+ "shape":"EncodingType",
+ "location":"querystring",
+ "locationName":"encoding-type"
+ },
+ "KeyMarker":{
+ "shape":"KeyMarker",
"documentation":"<p>Together with upload-id-marker, this parameter specifies the multipart upload after which listing should begin.</p> <p>If <code>upload-id-marker</code> is not specified, only the keys lexicographically greater than the specified <code>key-marker</code> will be included in the list.</p> <p>If <code>upload-id-marker</code> is specified, any multipart uploads for a key equal to the <code>key-marker</code> might also be included, provided those multipart uploads have upload IDs lexicographically greater than the specified <code>upload-id-marker</code>.</p>",
- "location":"querystring",
- "locationName":"key-marker"
- },
- "MaxUploads":{
- "shape":"MaxUploads",
+ "location":"querystring",
+ "locationName":"key-marker"
+ },
+ "MaxUploads":{
+ "shape":"MaxUploads",
"documentation":"<p>Sets the maximum number of multipart uploads, from 1 to 1,000, to return in the response body. 1,000 is the maximum number of uploads that can be returned in a response.</p>",
- "location":"querystring",
- "locationName":"max-uploads"
- },
- "Prefix":{
- "shape":"Prefix",
+ "location":"querystring",
+ "locationName":"max-uploads"
+ },
+ "Prefix":{
+ "shape":"Prefix",
"documentation":"<p>Lists in-progress uploads only for those keys that begin with the specified prefix. You can use prefixes to separate a bucket into different grouping of keys. (You can think of using prefix to make groups in the same way you'd use a folder in a file system.)</p>",
- "location":"querystring",
- "locationName":"prefix"
- },
- "UploadIdMarker":{
- "shape":"UploadIdMarker",
+ "location":"querystring",
+ "locationName":"prefix"
+ },
+ "UploadIdMarker":{
+ "shape":"UploadIdMarker",
"documentation":"<p>Together with key-marker, specifies the multipart upload after which listing should begin. If key-marker is not specified, the upload-id-marker parameter is ignored. Otherwise, any multipart uploads for a key equal to the key-marker might be included in the list only if they have an upload ID lexicographically greater than the specified <code>upload-id-marker</code>.</p>",
- "location":"querystring",
- "locationName":"upload-id-marker"
+ "location":"querystring",
+ "locationName":"upload-id-marker"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
- "ListObjectVersionsOutput":{
- "type":"structure",
- "members":{
- "IsTruncated":{
- "shape":"IsTruncated",
+ }
+ }
+ },
+ "ListObjectVersionsOutput":{
+ "type":"structure",
+ "members":{
+ "IsTruncated":{
+ "shape":"IsTruncated",
"documentation":"<p>A flag that indicates whether Amazon S3 returned all of the results that satisfied the search criteria. If your results were truncated, you can make a follow-up paginated request using the NextKeyMarker and NextVersionIdMarker response parameters as a starting place in another request to return the rest of the results.</p>"
- },
- "KeyMarker":{
- "shape":"KeyMarker",
+ },
+ "KeyMarker":{
+ "shape":"KeyMarker",
"documentation":"<p>Marks the last key returned in a truncated response.</p>"
- },
+ },
"VersionIdMarker":{
"shape":"VersionIdMarker",
"documentation":"<p>Marks the last version of the key returned in a truncated response.</p>"
},
- "NextKeyMarker":{
- "shape":"NextKeyMarker",
+ "NextKeyMarker":{
+ "shape":"NextKeyMarker",
"documentation":"<p>When the number of responses exceeds the value of <code>MaxKeys</code>, <code>NextKeyMarker</code> specifies the first key not returned that satisfies the search criteria. Use this value for the key-marker request parameter in a subsequent request.</p>"
- },
- "NextVersionIdMarker":{
- "shape":"NextVersionIdMarker",
+ },
+ "NextVersionIdMarker":{
+ "shape":"NextVersionIdMarker",
"documentation":"<p>When the number of responses exceeds the value of <code>MaxKeys</code>, <code>NextVersionIdMarker</code> specifies the first object version not returned that satisfies the search criteria. Use this value for the version-id-marker request parameter in a subsequent request.</p>"
- },
- "Versions":{
- "shape":"ObjectVersionList",
+ },
+ "Versions":{
+ "shape":"ObjectVersionList",
"documentation":"<p>Container for version information.</p>",
- "locationName":"Version"
- },
- "DeleteMarkers":{
- "shape":"DeleteMarkers",
+ "locationName":"Version"
+ },
+ "DeleteMarkers":{
+ "shape":"DeleteMarkers",
"documentation":"<p>Container for an object that is a delete marker.</p>",
- "locationName":"DeleteMarker"
- },
+ "locationName":"DeleteMarker"
+ },
"Name":{
"shape":"BucketName",
"documentation":"<p>The bucket name.</p>"
@@ -5727,80 +5727,80 @@
"shape":"CommonPrefixList",
"documentation":"<p>All of the keys rolled up into a common prefix count as a single return when calculating the number of returns.</p>"
},
- "EncodingType":{
- "shape":"EncodingType",
+ "EncodingType":{
+ "shape":"EncodingType",
"documentation":"<p> Encoding type used by Amazon S3 to encode object key names in the XML response.</p> <p>If you specify encoding-type request parameter, Amazon S3 includes this element in the response, and returns encoded key name values in the following response elements:</p> <p> <code>KeyMarker, NextKeyMarker, Prefix, Key</code>, and <code>Delimiter</code>.</p>"
- }
- }
- },
- "ListObjectVersionsRequest":{
- "type":"structure",
- "required":["Bucket"],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ }
+ }
+ },
+ "ListObjectVersionsRequest":{
+ "type":"structure",
+ "required":["Bucket"],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The bucket name that contains the objects. </p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "Delimiter":{
- "shape":"Delimiter",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "Delimiter":{
+ "shape":"Delimiter",
"documentation":"<p>A delimiter is a character that you specify to group keys. All keys that contain the same string between the <code>prefix</code> and the first occurrence of the delimiter are grouped under a single result element in CommonPrefixes. These groups are counted as one result against the max-keys limitation. These keys are not returned elsewhere in the response.</p>",
- "location":"querystring",
- "locationName":"delimiter"
- },
- "EncodingType":{
- "shape":"EncodingType",
- "location":"querystring",
- "locationName":"encoding-type"
- },
- "KeyMarker":{
- "shape":"KeyMarker",
+ "location":"querystring",
+ "locationName":"delimiter"
+ },
+ "EncodingType":{
+ "shape":"EncodingType",
+ "location":"querystring",
+ "locationName":"encoding-type"
+ },
+ "KeyMarker":{
+ "shape":"KeyMarker",
"documentation":"<p>Specifies the key to start with when listing objects in a bucket.</p>",
- "location":"querystring",
- "locationName":"key-marker"
- },
- "MaxKeys":{
- "shape":"MaxKeys",
+ "location":"querystring",
+ "locationName":"key-marker"
+ },
+ "MaxKeys":{
+ "shape":"MaxKeys",
"documentation":"<p>Sets the maximum number of keys returned in the response. By default the action returns up to 1,000 key names. The response might contain fewer keys but will never contain more. If additional keys satisfy the search criteria, but were not returned because max-keys was exceeded, the response contains &lt;isTruncated&gt;true&lt;/isTruncated&gt;. To return the additional keys, see key-marker and version-id-marker.</p>",
- "location":"querystring",
- "locationName":"max-keys"
- },
- "Prefix":{
- "shape":"Prefix",
+ "location":"querystring",
+ "locationName":"max-keys"
+ },
+ "Prefix":{
+ "shape":"Prefix",
"documentation":"<p>Use this parameter to select only those keys that begin with the specified prefix. You can use prefixes to separate a bucket into different groupings of keys. (You can think of using prefix to make groups in the same way you'd use a folder in a file system.) You can use prefix with delimiter to roll up numerous objects into a single result under CommonPrefixes. </p>",
- "location":"querystring",
- "locationName":"prefix"
- },
- "VersionIdMarker":{
- "shape":"VersionIdMarker",
+ "location":"querystring",
+ "locationName":"prefix"
+ },
+ "VersionIdMarker":{
+ "shape":"VersionIdMarker",
"documentation":"<p>Specifies the object version you want to start listing from.</p>",
- "location":"querystring",
- "locationName":"version-id-marker"
+ "location":"querystring",
+ "locationName":"version-id-marker"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
- "ListObjectsOutput":{
- "type":"structure",
- "members":{
- "IsTruncated":{
- "shape":"IsTruncated",
+ }
+ }
+ },
+ "ListObjectsOutput":{
+ "type":"structure",
+ "members":{
+ "IsTruncated":{
+ "shape":"IsTruncated",
"documentation":"<p>A flag that indicates whether Amazon S3 returned all of the results that satisfied the search criteria.</p>"
- },
+ },
"Marker":{
"shape":"Marker",
"documentation":"<p>Indicates where in the bucket listing begins. Marker is included in the response if it was sent with the request.</p>"
},
- "NextMarker":{
- "shape":"NextMarker",
+ "NextMarker":{
+ "shape":"NextMarker",
"documentation":"<p>When response is truncated (the IsTruncated element value in the response is true), you can use the key name in this field as marker in the subsequent request to get next set of objects. Amazon S3 lists objects in alphabetical order Note: This element is returned only if you have delimiter request parameter specified. If response does not include the NextMarker and it is truncated, you can use the value of the last Key in the response as the marker in the subsequent request to get the next set of object keys.</p>"
- },
+ },
"Contents":{
"shape":"ObjectList",
"documentation":"<p>Metadata about each object returned.</p>"
@@ -5825,184 +5825,184 @@
"shape":"CommonPrefixList",
"documentation":"<p>All of the keys (up to 1,000) rolled up in a common prefix count as a single return when calculating the number of returns. </p> <p>A response can contain CommonPrefixes only if you specify a delimiter.</p> <p>CommonPrefixes contains all (if there are any) keys between Prefix and the next occurrence of the string specified by the delimiter.</p> <p> CommonPrefixes lists keys that act like subdirectories in the directory specified by Prefix.</p> <p>For example, if the prefix is notes/ and the delimiter is a slash (/) as in notes/summer/july, the common prefix is notes/summer/. All of the keys that roll up into a common prefix count as a single return when calculating the number of returns.</p>"
},
- "EncodingType":{
- "shape":"EncodingType",
+ "EncodingType":{
+ "shape":"EncodingType",
"documentation":"<p>Encoding type used by Amazon S3 to encode object keys in the response.</p>"
- }
- }
- },
- "ListObjectsRequest":{
- "type":"structure",
- "required":["Bucket"],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ }
+ }
+ },
+ "ListObjectsRequest":{
+ "type":"structure",
+ "required":["Bucket"],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The name of the bucket containing the objects.</p> <p>When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.s3-accesspoint.<i>Region</i>.amazonaws.com. When using this action with an access point through the AWS SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\">Using access points</a> in the <i>Amazon S3 User Guide</i>.</p> <p>When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.<i>outpostID</i>.s3-outposts.<i>Region</i>.amazonaws.com. When using this action using S3 on Outposts through the AWS SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html\">Using S3 on Outposts</a> in the <i>Amazon S3 User Guide</i>.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "Delimiter":{
- "shape":"Delimiter",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "Delimiter":{
+ "shape":"Delimiter",
"documentation":"<p>A delimiter is a character you use to group keys.</p>",
- "location":"querystring",
- "locationName":"delimiter"
- },
- "EncodingType":{
- "shape":"EncodingType",
- "location":"querystring",
- "locationName":"encoding-type"
- },
- "Marker":{
- "shape":"Marker",
+ "location":"querystring",
+ "locationName":"delimiter"
+ },
+ "EncodingType":{
+ "shape":"EncodingType",
+ "location":"querystring",
+ "locationName":"encoding-type"
+ },
+ "Marker":{
+ "shape":"Marker",
"documentation":"<p>Specifies the key to start with when listing objects in a bucket.</p>",
- "location":"querystring",
- "locationName":"marker"
- },
- "MaxKeys":{
- "shape":"MaxKeys",
+ "location":"querystring",
+ "locationName":"marker"
+ },
+ "MaxKeys":{
+ "shape":"MaxKeys",
"documentation":"<p>Sets the maximum number of keys returned in the response. By default the action returns up to 1,000 key names. The response might contain fewer keys but will never contain more. </p>",
- "location":"querystring",
- "locationName":"max-keys"
- },
- "Prefix":{
- "shape":"Prefix",
+ "location":"querystring",
+ "locationName":"max-keys"
+ },
+ "Prefix":{
+ "shape":"Prefix",
"documentation":"<p>Limits the response to keys that begin with the specified prefix.</p>",
- "location":"querystring",
- "locationName":"prefix"
- },
- "RequestPayer":{
- "shape":"RequestPayer",
+ "location":"querystring",
+ "locationName":"prefix"
+ },
+ "RequestPayer":{
+ "shape":"RequestPayer",
"documentation":"<p>Confirms that the requester knows that she or he will be charged for the list objects request. Bucket owners need not specify this parameter in their requests.</p>",
- "location":"header",
- "locationName":"x-amz-request-payer"
+ "location":"header",
+ "locationName":"x-amz-request-payer"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
- "ListObjectsV2Output":{
- "type":"structure",
- "members":{
- "IsTruncated":{
- "shape":"IsTruncated",
+ }
+ }
+ },
+ "ListObjectsV2Output":{
+ "type":"structure",
+ "members":{
+ "IsTruncated":{
+ "shape":"IsTruncated",
"documentation":"<p>Set to false if all of the results were returned. Set to true if more keys are available to return. If the number of results exceeds that specified by MaxKeys, all of the results might not be returned.</p>"
- },
- "Contents":{
- "shape":"ObjectList",
+ },
+ "Contents":{
+ "shape":"ObjectList",
"documentation":"<p>Metadata about each object returned.</p>"
- },
- "Name":{
- "shape":"BucketName",
+ },
+ "Name":{
+ "shape":"BucketName",
"documentation":"<p>The bucket name.</p> <p>When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.s3-accesspoint.<i>Region</i>.amazonaws.com. When using this action with an access point through the AWS SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\">Using access points</a> in the <i>Amazon S3 User Guide</i>.</p> <p>When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.<i>outpostID</i>.s3-outposts.<i>Region</i>.amazonaws.com. When using this action using S3 on Outposts through the AWS SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html\">Using S3 on Outposts</a> in the <i>Amazon S3 User Guide</i>.</p>"
- },
- "Prefix":{
- "shape":"Prefix",
+ },
+ "Prefix":{
+ "shape":"Prefix",
"documentation":"<p> Keys that begin with the indicated prefix.</p>"
- },
- "Delimiter":{
- "shape":"Delimiter",
+ },
+ "Delimiter":{
+ "shape":"Delimiter",
"documentation":"<p>Causes keys that contain the same string between the prefix and the first occurrence of the delimiter to be rolled up into a single result element in the CommonPrefixes collection. These rolled-up keys are not returned elsewhere in the response. Each rolled-up result counts as only one return against the <code>MaxKeys</code> value.</p>"
- },
- "MaxKeys":{
- "shape":"MaxKeys",
+ },
+ "MaxKeys":{
+ "shape":"MaxKeys",
"documentation":"<p>Sets the maximum number of keys returned in the response. By default the action returns up to 1,000 key names. The response might contain fewer keys but will never contain more.</p>"
- },
- "CommonPrefixes":{
- "shape":"CommonPrefixList",
+ },
+ "CommonPrefixes":{
+ "shape":"CommonPrefixList",
"documentation":"<p>All of the keys (up to 1,000) rolled up into a common prefix count as a single return when calculating the number of returns.</p> <p>A response can contain <code>CommonPrefixes</code> only if you specify a delimiter.</p> <p> <code>CommonPrefixes</code> contains all (if there are any) keys between <code>Prefix</code> and the next occurrence of the string specified by a delimiter.</p> <p> <code>CommonPrefixes</code> lists keys that act like subdirectories in the directory specified by <code>Prefix</code>.</p> <p>For example, if the prefix is <code>notes/</code> and the delimiter is a slash (<code>/</code>) as in <code>notes/summer/july</code>, the common prefix is <code>notes/summer/</code>. All of the keys that roll up into a common prefix count as a single return when calculating the number of returns. </p>"
- },
- "EncodingType":{
- "shape":"EncodingType",
+ },
+ "EncodingType":{
+ "shape":"EncodingType",
"documentation":"<p>Encoding type used by Amazon S3 to encode object key names in the XML response.</p> <p>If you specify the encoding-type request parameter, Amazon S3 includes this element in the response, and returns encoded key name values in the following response elements:</p> <p> <code>Delimiter, Prefix, Key,</code> and <code>StartAfter</code>.</p>"
- },
- "KeyCount":{
- "shape":"KeyCount",
+ },
+ "KeyCount":{
+ "shape":"KeyCount",
"documentation":"<p>KeyCount is the number of keys returned with this request. KeyCount will always be less than or equals to MaxKeys field. Say you ask for 50 keys, your result will include less than equals 50 keys </p>"
- },
- "ContinuationToken":{
- "shape":"Token",
+ },
+ "ContinuationToken":{
+ "shape":"Token",
"documentation":"<p> If ContinuationToken was sent with the request, it is included in the response.</p>"
- },
- "NextContinuationToken":{
- "shape":"NextToken",
+ },
+ "NextContinuationToken":{
+ "shape":"NextToken",
"documentation":"<p> <code>NextContinuationToken</code> is sent when <code>isTruncated</code> is true, which means there are more keys in the bucket that can be listed. The next list requests to Amazon S3 can be continued with this <code>NextContinuationToken</code>. <code>NextContinuationToken</code> is obfuscated and is not a real key</p>"
- },
- "StartAfter":{
- "shape":"StartAfter",
+ },
+ "StartAfter":{
+ "shape":"StartAfter",
"documentation":"<p>If StartAfter was sent with the request, it is included in the response.</p>"
- }
- }
- },
- "ListObjectsV2Request":{
- "type":"structure",
- "required":["Bucket"],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ }
+ }
+ },
+ "ListObjectsV2Request":{
+ "type":"structure",
+ "required":["Bucket"],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>Bucket name to list. </p> <p>When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.s3-accesspoint.<i>Region</i>.amazonaws.com. When using this action with an access point through the AWS SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\">Using access points</a> in the <i>Amazon S3 User Guide</i>.</p> <p>When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.<i>outpostID</i>.s3-outposts.<i>Region</i>.amazonaws.com. When using this action using S3 on Outposts through the AWS SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html\">Using S3 on Outposts</a> in the <i>Amazon S3 User Guide</i>.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "Delimiter":{
- "shape":"Delimiter",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "Delimiter":{
+ "shape":"Delimiter",
"documentation":"<p>A delimiter is a character you use to group keys.</p>",
- "location":"querystring",
- "locationName":"delimiter"
- },
- "EncodingType":{
- "shape":"EncodingType",
+ "location":"querystring",
+ "locationName":"delimiter"
+ },
+ "EncodingType":{
+ "shape":"EncodingType",
"documentation":"<p>Encoding type used by Amazon S3 to encode object keys in the response.</p>",
- "location":"querystring",
- "locationName":"encoding-type"
- },
- "MaxKeys":{
- "shape":"MaxKeys",
+ "location":"querystring",
+ "locationName":"encoding-type"
+ },
+ "MaxKeys":{
+ "shape":"MaxKeys",
"documentation":"<p>Sets the maximum number of keys returned in the response. By default the action returns up to 1,000 key names. The response might contain fewer keys but will never contain more.</p>",
- "location":"querystring",
- "locationName":"max-keys"
- },
- "Prefix":{
- "shape":"Prefix",
+ "location":"querystring",
+ "locationName":"max-keys"
+ },
+ "Prefix":{
+ "shape":"Prefix",
"documentation":"<p>Limits the response to keys that begin with the specified prefix.</p>",
- "location":"querystring",
- "locationName":"prefix"
- },
- "ContinuationToken":{
- "shape":"Token",
+ "location":"querystring",
+ "locationName":"prefix"
+ },
+ "ContinuationToken":{
+ "shape":"Token",
"documentation":"<p>ContinuationToken indicates Amazon S3 that the list is being continued on this bucket with a token. ContinuationToken is obfuscated and is not a real key.</p>",
- "location":"querystring",
- "locationName":"continuation-token"
- },
- "FetchOwner":{
- "shape":"FetchOwner",
+ "location":"querystring",
+ "locationName":"continuation-token"
+ },
+ "FetchOwner":{
+ "shape":"FetchOwner",
"documentation":"<p>The owner field is not present in listV2 by default, if you want to return owner field with each key in the result then set the fetch owner field to true.</p>",
- "location":"querystring",
- "locationName":"fetch-owner"
- },
- "StartAfter":{
- "shape":"StartAfter",
+ "location":"querystring",
+ "locationName":"fetch-owner"
+ },
+ "StartAfter":{
+ "shape":"StartAfter",
"documentation":"<p>StartAfter is where you want Amazon S3 to start listing from. Amazon S3 starts listing after this specified key. StartAfter can be any key in the bucket.</p>",
- "location":"querystring",
- "locationName":"start-after"
- },
- "RequestPayer":{
- "shape":"RequestPayer",
+ "location":"querystring",
+ "locationName":"start-after"
+ },
+ "RequestPayer":{
+ "shape":"RequestPayer",
"documentation":"<p>Confirms that the requester knows that she or he will be charged for the list objects request in V2 style. Bucket owners need not specify this parameter in their requests.</p>",
- "location":"header",
- "locationName":"x-amz-request-payer"
+ "location":"header",
+ "locationName":"x-amz-request-payer"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
+ }
+ }
+ },
"ListObjectsV1ExtOutput":{
"type":"structure",
"members":{
@@ -6056,190 +6056,190 @@
}
}
},
- "ListPartsOutput":{
- "type":"structure",
- "members":{
- "AbortDate":{
- "shape":"AbortDate",
+ "ListPartsOutput":{
+ "type":"structure",
+ "members":{
+ "AbortDate":{
+ "shape":"AbortDate",
"documentation":"<p>If the bucket has a lifecycle rule configured with an action to abort incomplete multipart uploads and the prefix in the lifecycle rule matches the object name in the request, then the response includes this header indicating when the initiated multipart upload will become eligible for abort operation. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/mpuoverview.html#mpu-abort-incomplete-mpu-lifecycle-config\">Aborting Incomplete Multipart Uploads Using a Bucket Lifecycle Policy</a>.</p> <p>The response will also include the <code>x-amz-abort-rule-id</code> header that will provide the ID of the lifecycle configuration rule that defines this action.</p>",
- "location":"header",
- "locationName":"x-amz-abort-date"
- },
- "AbortRuleId":{
- "shape":"AbortRuleId",
+ "location":"header",
+ "locationName":"x-amz-abort-date"
+ },
+ "AbortRuleId":{
+ "shape":"AbortRuleId",
"documentation":"<p>This header is returned along with the <code>x-amz-abort-date</code> header. It identifies applicable lifecycle configuration rule that defines the action to abort incomplete multipart uploads.</p>",
- "location":"header",
- "locationName":"x-amz-abort-rule-id"
- },
- "Bucket":{
- "shape":"BucketName",
+ "location":"header",
+ "locationName":"x-amz-abort-rule-id"
+ },
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The name of the bucket to which the multipart upload was initiated.</p>"
- },
- "Key":{
- "shape":"ObjectKey",
+ },
+ "Key":{
+ "shape":"ObjectKey",
"documentation":"<p>Object key for which the multipart upload was initiated.</p>"
- },
- "UploadId":{
- "shape":"MultipartUploadId",
+ },
+ "UploadId":{
+ "shape":"MultipartUploadId",
"documentation":"<p>Upload ID identifying the multipart upload whose parts are being listed.</p>"
- },
- "PartNumberMarker":{
- "shape":"PartNumberMarker",
+ },
+ "PartNumberMarker":{
+ "shape":"PartNumberMarker",
"documentation":"<p>When a list is truncated, this element specifies the last part in the list, as well as the value to use for the part-number-marker request parameter in a subsequent request.</p>"
- },
- "NextPartNumberMarker":{
- "shape":"NextPartNumberMarker",
+ },
+ "NextPartNumberMarker":{
+ "shape":"NextPartNumberMarker",
"documentation":"<p>When a list is truncated, this element specifies the last part in the list, as well as the value to use for the part-number-marker request parameter in a subsequent request.</p>"
- },
- "MaxParts":{
- "shape":"MaxParts",
+ },
+ "MaxParts":{
+ "shape":"MaxParts",
"documentation":"<p>Maximum number of parts that were allowed in the response.</p>"
- },
- "IsTruncated":{
- "shape":"IsTruncated",
+ },
+ "IsTruncated":{
+ "shape":"IsTruncated",
"documentation":"<p> Indicates whether the returned list of parts is truncated. A true value indicates that the list was truncated. A list can be truncated if the number of parts exceeds the limit returned in the MaxParts element.</p>"
- },
- "Parts":{
- "shape":"Parts",
+ },
+ "Parts":{
+ "shape":"Parts",
"documentation":"<p> Container for elements related to a particular part. A response can contain zero or more <code>Part</code> elements.</p>",
- "locationName":"Part"
- },
- "Initiator":{
- "shape":"Initiator",
+ "locationName":"Part"
+ },
+ "Initiator":{
+ "shape":"Initiator",
"documentation":"<p>Container element that identifies who initiated the multipart upload. If the initiator is an AWS account, this element provides the same information as the <code>Owner</code> element. If the initiator is an IAM User, this element provides the user ARN and display name.</p>"
- },
+ },
"Owner":{
"shape":"Owner",
"documentation":"<p> Container element that identifies the object owner, after the object is created. If multipart upload is initiated by an IAM user, this element provides the parent account ID and display name.</p>"
},
- "StorageClass":{
- "shape":"StorageClass",
+ "StorageClass":{
+ "shape":"StorageClass",
"documentation":"<p>Class of storage (STANDARD or REDUCED_REDUNDANCY) used to store the uploaded object.</p>"
- },
- "RequestCharged":{
- "shape":"RequestCharged",
- "location":"header",
- "locationName":"x-amz-request-charged"
- }
- }
- },
- "ListPartsRequest":{
- "type":"structure",
- "required":[
- "Bucket",
- "Key",
- "UploadId"
- ],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ },
+ "RequestCharged":{
+ "shape":"RequestCharged",
+ "location":"header",
+ "locationName":"x-amz-request-charged"
+ }
+ }
+ },
+ "ListPartsRequest":{
+ "type":"structure",
+ "required":[
+ "Bucket",
+ "Key",
+ "UploadId"
+ ],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The name of the bucket to which the parts are being uploaded. </p> <p>When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.s3-accesspoint.<i>Region</i>.amazonaws.com. When using this action with an access point through the AWS SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\">Using access points</a> in the <i>Amazon S3 User Guide</i>.</p> <p>When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.<i>outpostID</i>.s3-outposts.<i>Region</i>.amazonaws.com. When using this action using S3 on Outposts through the AWS SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html\">Using S3 on Outposts</a> in the <i>Amazon S3 User Guide</i>.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "Key":{
- "shape":"ObjectKey",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "Key":{
+ "shape":"ObjectKey",
"documentation":"<p>Object key for which the multipart upload was initiated.</p>",
- "location":"uri",
- "locationName":"Key"
- },
- "MaxParts":{
- "shape":"MaxParts",
+ "location":"uri",
+ "locationName":"Key"
+ },
+ "MaxParts":{
+ "shape":"MaxParts",
"documentation":"<p>Sets the maximum number of parts to return.</p>",
- "location":"querystring",
- "locationName":"max-parts"
- },
- "PartNumberMarker":{
- "shape":"PartNumberMarker",
+ "location":"querystring",
+ "locationName":"max-parts"
+ },
+ "PartNumberMarker":{
+ "shape":"PartNumberMarker",
"documentation":"<p>Specifies the part after which listing should begin. Only parts with higher part numbers will be listed.</p>",
- "location":"querystring",
- "locationName":"part-number-marker"
- },
- "UploadId":{
- "shape":"MultipartUploadId",
+ "location":"querystring",
+ "locationName":"part-number-marker"
+ },
+ "UploadId":{
+ "shape":"MultipartUploadId",
"documentation":"<p>Upload ID identifying the multipart upload whose parts are being listed.</p>",
- "location":"querystring",
- "locationName":"uploadId"
- },
- "RequestPayer":{
- "shape":"RequestPayer",
- "location":"header",
- "locationName":"x-amz-request-payer"
+ "location":"querystring",
+ "locationName":"uploadId"
+ },
+ "RequestPayer":{
+ "shape":"RequestPayer",
+ "location":"header",
+ "locationName":"x-amz-request-payer"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- }
- },
- "Location":{"type":"string"},
- "LocationPrefix":{"type":"string"},
- "LoggingEnabled":{
- "type":"structure",
- "required":[
- "TargetBucket",
- "TargetPrefix"
- ],
- "members":{
- "TargetBucket":{
- "shape":"TargetBucket",
+ }
+ }
+ },
+ "Location":{"type":"string"},
+ "LocationPrefix":{"type":"string"},
+ "LoggingEnabled":{
+ "type":"structure",
+ "required":[
+ "TargetBucket",
+ "TargetPrefix"
+ ],
+ "members":{
+ "TargetBucket":{
+ "shape":"TargetBucket",
"documentation":"<p>Specifies the bucket where you want Amazon S3 to store server access logs. You can have your logs delivered to any bucket that you own, including the same bucket that is being logged. You can also configure multiple buckets to deliver their logs to the same target bucket. In this case, you should choose a different <code>TargetPrefix</code> for each source bucket so that the delivered log files can be distinguished by key.</p>"
- },
+ },
"TargetGrants":{
"shape":"TargetGrants",
"documentation":"<p>Container for granting information.</p>"
},
- "TargetPrefix":{
- "shape":"TargetPrefix",
+ "TargetPrefix":{
+ "shape":"TargetPrefix",
"documentation":"<p>A prefix for all log object keys. If you store log files from multiple Amazon S3 buckets in a single bucket, you can use a prefix to distinguish which log files came from which bucket.</p>"
- }
- },
+ }
+ },
"documentation":"<p>Describes where logs are stored and the prefix that Amazon S3 assigns to all log object keys for a bucket. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketPUTlogging.html\">PUT Bucket logging</a> in the <i>Amazon S3 API Reference</i>.</p>"
- },
- "MFA":{"type":"string"},
- "MFADelete":{
- "type":"string",
- "enum":[
- "Enabled",
- "Disabled"
- ]
- },
- "MFADeleteStatus":{
- "type":"string",
- "enum":[
- "Enabled",
- "Disabled"
- ]
- },
- "Marker":{"type":"string"},
- "MaxAgeSeconds":{"type":"integer"},
- "MaxKeys":{"type":"integer"},
- "MaxParts":{"type":"integer"},
- "MaxUploads":{"type":"integer"},
- "Message":{"type":"string"},
- "Metadata":{
- "type":"map",
- "key":{"shape":"MetadataKey"},
- "value":{"shape":"MetadataValue"}
- },
+ },
+ "MFA":{"type":"string"},
+ "MFADelete":{
+ "type":"string",
+ "enum":[
+ "Enabled",
+ "Disabled"
+ ]
+ },
+ "MFADeleteStatus":{
+ "type":"string",
+ "enum":[
+ "Enabled",
+ "Disabled"
+ ]
+ },
+ "Marker":{"type":"string"},
+ "MaxAgeSeconds":{"type":"integer"},
+ "MaxKeys":{"type":"integer"},
+ "MaxParts":{"type":"integer"},
+ "MaxUploads":{"type":"integer"},
+ "Message":{"type":"string"},
+ "Metadata":{
+ "type":"map",
+ "key":{"shape":"MetadataKey"},
+ "value":{"shape":"MetadataValue"}
+ },
"MetadataMap":{
"type":"map",
"flattened":true,
"key":{"shape":"MetadataKey","locationName":"Name"},
"value":{"shape":"MetadataValue","locationName":"Value"}
},
- "MetadataDirective":{
- "type":"string",
- "enum":[
- "COPY",
- "REPLACE"
- ]
- },
- "MetadataEntry":{
- "type":"structure",
- "members":{
+ "MetadataDirective":{
+ "type":"string",
+ "enum":[
+ "COPY",
+ "REPLACE"
+ ]
+ },
+ "MetadataEntry":{
+ "type":"structure",
+ "members":{
"Name":{
"shape":"MetadataKey",
"documentation":"<p>Name of the Object.</p>"
@@ -6248,11 +6248,11 @@
"shape":"MetadataValue",
"documentation":"<p>Value of the Object.</p>"
}
- },
+ },
"documentation":"<p>A metadata key-value pair to store with an object.</p>"
- },
- "MetadataKey":{"type":"string"},
- "MetadataValue":{"type":"string"},
+ },
+ "MetadataKey":{"type":"string"},
+ "MetadataValue":{"type":"string"},
"Metrics":{
"type":"structure",
"required":["Status"],
@@ -6268,61 +6268,61 @@
},
"documentation":"<p> A container specifying replication metrics-related settings enabling replication metrics and events.</p>"
},
- "MetricsAndOperator":{
- "type":"structure",
- "members":{
- "Prefix":{
- "shape":"Prefix",
+ "MetricsAndOperator":{
+ "type":"structure",
+ "members":{
+ "Prefix":{
+ "shape":"Prefix",
"documentation":"<p>The prefix used when evaluating an AND predicate.</p>"
- },
- "Tags":{
- "shape":"TagSet",
+ },
+ "Tags":{
+ "shape":"TagSet",
"documentation":"<p>The list of tags used when evaluating an AND predicate.</p>",
- "flattened":true,
- "locationName":"Tag"
- }
+ "flattened":true,
+ "locationName":"Tag"
+ }
},
"documentation":"<p>A conjunction (logical AND) of predicates, which is used in evaluating a metrics filter. The operator must have at least two predicates, and an object must match all of the predicates in order for the filter to apply.</p>"
- },
- "MetricsConfiguration":{
- "type":"structure",
- "required":["Id"],
- "members":{
- "Id":{
- "shape":"MetricsId",
+ },
+ "MetricsConfiguration":{
+ "type":"structure",
+ "required":["Id"],
+ "members":{
+ "Id":{
+ "shape":"MetricsId",
"documentation":"<p>The ID used to identify the metrics configuration.</p>"
- },
- "Filter":{
- "shape":"MetricsFilter",
+ },
+ "Filter":{
+ "shape":"MetricsFilter",
"documentation":"<p>Specifies a metrics configuration filter. The metrics configuration will only include objects that meet the filter's criteria. A filter must be a prefix, a tag, or a conjunction (MetricsAndOperator).</p>"
- }
+ }
},
"documentation":"<p>Specifies a metrics configuration for the CloudWatch request metrics (specified by the metrics configuration ID) from an Amazon S3 bucket. If you're updating an existing metrics configuration, note that this is a full replacement of the existing metrics configuration. If you don't include the elements you want to keep, they are erased. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketPUTMetricConfiguration.html\"> PUT Bucket metrics</a> in the <i>Amazon S3 API Reference</i>.</p>"
- },
- "MetricsConfigurationList":{
- "type":"list",
- "member":{"shape":"MetricsConfiguration"},
- "flattened":true
- },
- "MetricsFilter":{
- "type":"structure",
- "members":{
- "Prefix":{
- "shape":"Prefix",
+ },
+ "MetricsConfigurationList":{
+ "type":"list",
+ "member":{"shape":"MetricsConfiguration"},
+ "flattened":true
+ },
+ "MetricsFilter":{
+ "type":"structure",
+ "members":{
+ "Prefix":{
+ "shape":"Prefix",
"documentation":"<p>The prefix used when evaluating a metrics filter.</p>"
- },
- "Tag":{
- "shape":"Tag",
+ },
+ "Tag":{
+ "shape":"Tag",
"documentation":"<p>The tag used when evaluating a metrics filter.</p>"
- },
- "And":{
- "shape":"MetricsAndOperator",
+ },
+ "And":{
+ "shape":"MetricsAndOperator",
"documentation":"<p>A conjunction (logical AND) of predicates, which is used in evaluating a metrics filter. The operator must have at least two predicates, and an object must match all of the predicates in order for the filter to apply.</p>"
- }
+ }
},
"documentation":"<p>Specifies a metrics configuration filter. The metrics configuration only includes objects that meet the filter's criteria. A filter must be a prefix, a tag, or a conjunction (MetricsAndOperator).</p>"
- },
- "MetricsId":{"type":"string"},
+ },
+ "MetricsId":{"type":"string"},
"MetricsStatus":{
"type":"string",
"enum":[
@@ -6331,123 +6331,123 @@
]
},
"Minutes":{"type":"integer"},
- "MissingMeta":{"type":"integer"},
- "MultipartUpload":{
- "type":"structure",
- "members":{
- "UploadId":{
- "shape":"MultipartUploadId",
+ "MissingMeta":{"type":"integer"},
+ "MultipartUpload":{
+ "type":"structure",
+ "members":{
+ "UploadId":{
+ "shape":"MultipartUploadId",
"documentation":"<p>Upload ID that identifies the multipart upload.</p>"
- },
- "Key":{
- "shape":"ObjectKey",
+ },
+ "Key":{
+ "shape":"ObjectKey",
"documentation":"<p>Key of the object for which the multipart upload was initiated.</p>"
- },
- "Initiated":{
- "shape":"Initiated",
+ },
+ "Initiated":{
+ "shape":"Initiated",
"documentation":"<p>Date and time at which the multipart upload was initiated.</p>"
- },
- "StorageClass":{
- "shape":"StorageClass",
+ },
+ "StorageClass":{
+ "shape":"StorageClass",
"documentation":"<p>The class of storage used to store the object.</p>"
- },
+ },
"Owner":{
"shape":"Owner",
"documentation":"<p>Specifies the owner of the object that is part of the multipart upload. </p>"
},
- "Initiator":{
- "shape":"Initiator",
+ "Initiator":{
+ "shape":"Initiator",
"documentation":"<p>Identifies who initiated the multipart upload.</p>"
- }
+ }
},
"documentation":"<p>Container for the <code>MultipartUpload</code> for the Amazon S3 object.</p>"
- },
- "MultipartUploadId":{"type":"string"},
- "MultipartUploadList":{
- "type":"list",
- "member":{"shape":"MultipartUpload"},
- "flattened":true
- },
- "NextKeyMarker":{"type":"string"},
- "NextMarker":{"type":"string"},
- "NextPartNumberMarker":{"type":"integer"},
- "NextToken":{"type":"string"},
- "NextUploadIdMarker":{"type":"string"},
- "NextVersionIdMarker":{"type":"string"},
- "NoSuchBucket":{
- "type":"structure",
- "members":{
- },
+ },
+ "MultipartUploadId":{"type":"string"},
+ "MultipartUploadList":{
+ "type":"list",
+ "member":{"shape":"MultipartUpload"},
+ "flattened":true
+ },
+ "NextKeyMarker":{"type":"string"},
+ "NextMarker":{"type":"string"},
+ "NextPartNumberMarker":{"type":"integer"},
+ "NextToken":{"type":"string"},
+ "NextUploadIdMarker":{"type":"string"},
+ "NextVersionIdMarker":{"type":"string"},
+ "NoSuchBucket":{
+ "type":"structure",
+ "members":{
+ },
"documentation":"<p>The specified bucket does not exist.</p>",
- "exception":true
- },
- "NoSuchKey":{
- "type":"structure",
- "members":{
- },
+ "exception":true
+ },
+ "NoSuchKey":{
+ "type":"structure",
+ "members":{
+ },
"documentation":"<p>The specified key does not exist.</p>",
- "exception":true
- },
- "NoSuchUpload":{
- "type":"structure",
- "members":{
- },
+ "exception":true
+ },
+ "NoSuchUpload":{
+ "type":"structure",
+ "members":{
+ },
"documentation":"<p>The specified multipart upload does not exist.</p>",
- "exception":true
- },
- "NoncurrentVersionExpiration":{
- "type":"structure",
- "members":{
- "NoncurrentDays":{
- "shape":"Days",
+ "exception":true
+ },
+ "NoncurrentVersionExpiration":{
+ "type":"structure",
+ "members":{
+ "NoncurrentDays":{
+ "shape":"Days",
"documentation":"<p>Specifies the number of days an object is noncurrent before Amazon S3 can perform the associated action. For information about the noncurrent days calculations, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/intro-lifecycle-rules.html#non-current-days-calculations\">How Amazon S3 Calculates When an Object Became Noncurrent</a> in the <i>Amazon S3 User Guide</i>.</p>"
- }
- },
+ }
+ },
"documentation":"<p>Specifies when noncurrent object versions expire. Upon expiration, Amazon S3 permanently deletes the noncurrent object versions. You set this lifecycle configuration action on a bucket that has versioning enabled (or suspended) to request that Amazon S3 delete noncurrent object versions at a specific period in the object's lifetime.</p>"
- },
- "NoncurrentVersionTransition":{
- "type":"structure",
- "members":{
- "NoncurrentDays":{
- "shape":"Days",
+ },
+ "NoncurrentVersionTransition":{
+ "type":"structure",
+ "members":{
+ "NoncurrentDays":{
+ "shape":"Days",
"documentation":"<p>Specifies the number of days an object is noncurrent before Amazon S3 can perform the associated action. For information about the noncurrent days calculations, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/intro-lifecycle-rules.html#non-current-days-calculations\">How Amazon S3 Calculates How Long an Object Has Been Noncurrent</a> in the <i>Amazon S3 User Guide</i>.</p>"
- },
- "StorageClass":{
- "shape":"TransitionStorageClass",
+ },
+ "StorageClass":{
+ "shape":"TransitionStorageClass",
"documentation":"<p>The class of storage used to store the object.</p>"
- }
- },
+ }
+ },
"documentation":"<p>Container for the transition rule that describes when noncurrent objects transition to the <code>STANDARD_IA</code>, <code>ONEZONE_IA</code>, <code>INTELLIGENT_TIERING</code>, <code>GLACIER</code>, or <code>DEEP_ARCHIVE</code> storage class. If your bucket is versioning-enabled (or versioning is suspended), you can set this action to request that Amazon S3 transition noncurrent object versions to the <code>STANDARD_IA</code>, <code>ONEZONE_IA</code>, <code>INTELLIGENT_TIERING</code>, <code>GLACIER</code>, or <code>DEEP_ARCHIVE</code> storage class at a specific period in the object's lifetime.</p>"
- },
- "NoncurrentVersionTransitionList":{
- "type":"list",
- "member":{"shape":"NoncurrentVersionTransition"},
- "flattened":true
- },
- "NotificationConfiguration":{
- "type":"structure",
- "members":{
- "TopicConfigurations":{
- "shape":"TopicConfigurationList",
+ },
+ "NoncurrentVersionTransitionList":{
+ "type":"list",
+ "member":{"shape":"NoncurrentVersionTransition"},
+ "flattened":true
+ },
+ "NotificationConfiguration":{
+ "type":"structure",
+ "members":{
+ "TopicConfigurations":{
+ "shape":"TopicConfigurationList",
"documentation":"<p>The topic to which notifications are sent and the events for which notifications are generated.</p>",
- "locationName":"TopicConfiguration"
- },
- "QueueConfigurations":{
- "shape":"QueueConfigurationList",
+ "locationName":"TopicConfiguration"
+ },
+ "QueueConfigurations":{
+ "shape":"QueueConfigurationList",
"documentation":"<p>The Amazon Simple Queue Service queues to publish messages to and the events for which to publish messages.</p>",
- "locationName":"QueueConfiguration"
- },
- "LambdaFunctionConfigurations":{
- "shape":"LambdaFunctionConfigurationList",
+ "locationName":"QueueConfiguration"
+ },
+ "LambdaFunctionConfigurations":{
+ "shape":"LambdaFunctionConfigurationList",
"documentation":"<p>Describes the AWS Lambda functions to invoke and the events for which to invoke them.</p>",
- "locationName":"CloudFunctionConfiguration"
- }
- },
+ "locationName":"CloudFunctionConfiguration"
+ }
+ },
"documentation":"<p>A container for specifying the notification configuration of the bucket. If this element is empty, notifications are turned off for the bucket.</p>"
- },
- "NotificationConfigurationDeprecated":{
- "type":"structure",
- "members":{
+ },
+ "NotificationConfigurationDeprecated":{
+ "type":"structure",
+ "members":{
"TopicConfiguration":{
"shape":"TopicConfigurationDeprecated",
"documentation":"<p>This data type is deprecated. A container for specifying the configuration for publication of messages to an Amazon Simple Notification Service (Amazon SNS) topic when Amazon S3 detects specified events. </p>"
@@ -6460,25 +6460,25 @@
"shape":"CloudFunctionConfiguration",
"documentation":"<p>Container for specifying the AWS Lambda notification configuration.</p>"
}
- }
- },
- "NotificationConfigurationFilter":{
- "type":"structure",
- "members":{
- "Key":{
- "shape":"S3KeyFilter",
- "locationName":"S3Key"
- }
- },
+ }
+ },
+ "NotificationConfigurationFilter":{
+ "type":"structure",
+ "members":{
+ "Key":{
+ "shape":"S3KeyFilter",
+ "locationName":"S3Key"
+ }
+ },
"documentation":"<p>Specifies object key name filtering rules. For information about key name filtering, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/NotificationHowTo.html\">Configuring Event Notifications</a> in the <i>Amazon S3 User Guide</i>.</p>"
- },
- "NotificationId":{
- "type":"string",
+ },
+ "NotificationId":{
+ "type":"string",
"documentation":"<p>An optional unique identifier for configurations in a notification configuration. If you don't provide one, Amazon S3 will assign an ID.</p>"
- },
- "Object":{
- "type":"structure",
- "members":{
+ },
+ "Object":{
+ "type":"structure",
+ "members":{
"Key":{
"shape":"ObjectKey",
"documentation":"<p>The name that you assign to an object. You use the object key to retrieve the object.</p>"
@@ -6495,17 +6495,17 @@
"shape":"Size",
"documentation":"<p>Size in bytes of the object</p>"
},
- "StorageClass":{
- "shape":"ObjectStorageClass",
+ "StorageClass":{
+ "shape":"ObjectStorageClass",
"documentation":"<p>The class of storage used to store the object.</p>"
- },
+ },
"Owner":{
"shape":"Owner",
"documentation":"<p>The owner of the object</p>"
}
},
"documentation":"<p>An object consists of data and its descriptive metadata.</p>"
- },
+ },
"ObjectV1Ext":{
"type":"structure",
"members":{
@@ -6540,54 +6540,54 @@
},
"documentation":"<p>An object consists of data and its descriptive metadata.</p>"
},
- "ObjectAlreadyInActiveTierError":{
- "type":"structure",
- "members":{
- },
+ "ObjectAlreadyInActiveTierError":{
+ "type":"structure",
+ "members":{
+ },
"documentation":"<p>This action is not allowed against this storage tier.</p>",
- "exception":true
- },
- "ObjectCannedACL":{
- "type":"string",
- "enum":[
- "private",
- "public-read",
- "public-read-write",
- "authenticated-read",
- "aws-exec-read",
- "bucket-owner-read",
- "bucket-owner-full-control"
- ]
- },
- "ObjectIdentifier":{
- "type":"structure",
- "required":["Key"],
- "members":{
- "Key":{
- "shape":"ObjectKey",
+ "exception":true
+ },
+ "ObjectCannedACL":{
+ "type":"string",
+ "enum":[
+ "private",
+ "public-read",
+ "public-read-write",
+ "authenticated-read",
+ "aws-exec-read",
+ "bucket-owner-read",
+ "bucket-owner-full-control"
+ ]
+ },
+ "ObjectIdentifier":{
+ "type":"structure",
+ "required":["Key"],
+ "members":{
+ "Key":{
+ "shape":"ObjectKey",
"documentation":"<p>Key name of the object.</p> <important> <p>Replacement must be made for object keys containing special characters (such as carriage returns) when using XML requests. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-keys.html#object-key-xml-related-constraints\"> XML related object key constraints</a>.</p> </important>"
- },
- "VersionId":{
- "shape":"ObjectVersionId",
+ },
+ "VersionId":{
+ "shape":"ObjectVersionId",
"documentation":"<p>VersionId for the specific version of the object to delete.</p>"
- }
+ }
},
"documentation":"<p>Object Identifier is unique value to identify objects.</p>"
- },
- "ObjectIdentifierList":{
- "type":"list",
- "member":{"shape":"ObjectIdentifier"},
- "flattened":true
- },
- "ObjectKey":{
- "type":"string",
- "min":1
- },
- "ObjectList":{
- "type":"list",
- "member":{"shape":"Object"},
- "flattened":true
- },
+ },
+ "ObjectIdentifierList":{
+ "type":"list",
+ "member":{"shape":"ObjectIdentifier"},
+ "flattened":true
+ },
+ "ObjectKey":{
+ "type":"string",
+ "min":1
+ },
+ "ObjectList":{
+ "type":"list",
+ "member":{"shape":"Object"},
+ "flattened":true
+ },
"ObjectListV1Ext":{
"type":"list",
"member":{"shape":"ObjectV1Ext"},
@@ -6672,13 +6672,13 @@
"documentation":"<p>The container element for an Object Lock rule.</p>"
},
"ObjectLockToken":{"type":"string"},
- "ObjectNotInActiveTierError":{
- "type":"structure",
- "members":{
- },
+ "ObjectNotInActiveTierError":{
+ "type":"structure",
+ "members":{
+ },
"documentation":"<p>The source object of the COPY action is not in the active tier and is only stored in Amazon S3 Glacier.</p>",
- "exception":true
- },
+ "exception":true
+ },
"ObjectOwnership":{
"type":"string",
"documentation":"<p>The container element for object ownership for a bucket's ownership controls.</p> <p>BucketOwnerPreferred - Objects uploaded to the bucket change ownership to the bucket owner if the objects are uploaded with the <code>bucket-owner-full-control</code> canned ACL.</p> <p>ObjectWriter - The uploading account will own the object if the object is uploaded with the <code>bucket-owner-full-control</code> canned ACL.</p>",
@@ -6687,94 +6687,94 @@
"ObjectWriter"
]
},
- "ObjectStorageClass":{
- "type":"string",
- "enum":[
- "STANDARD",
- "REDUCED_REDUNDANCY",
- "GLACIER",
- "STANDARD_IA",
+ "ObjectStorageClass":{
+ "type":"string",
+ "enum":[
+ "STANDARD",
+ "REDUCED_REDUNDANCY",
+ "GLACIER",
+ "STANDARD_IA",
"ONEZONE_IA",
"INTELLIGENT_TIERING",
"DEEP_ARCHIVE",
"OUTPOSTS"
- ]
- },
- "ObjectVersion":{
- "type":"structure",
- "members":{
+ ]
+ },
+ "ObjectVersion":{
+ "type":"structure",
+ "members":{
"ETag":{
"shape":"ETag",
"documentation":"<p>The entity tag is an MD5 hash of that version of the object.</p>"
},
- "Size":{
- "shape":"Size",
+ "Size":{
+ "shape":"Size",
"documentation":"<p>Size in bytes of the object.</p>"
- },
- "StorageClass":{
- "shape":"ObjectVersionStorageClass",
+ },
+ "StorageClass":{
+ "shape":"ObjectVersionStorageClass",
"documentation":"<p>The class of storage used to store the object.</p>"
- },
- "Key":{
- "shape":"ObjectKey",
+ },
+ "Key":{
+ "shape":"ObjectKey",
"documentation":"<p>The object key.</p>"
- },
- "VersionId":{
- "shape":"ObjectVersionId",
+ },
+ "VersionId":{
+ "shape":"ObjectVersionId",
"documentation":"<p>Version ID of an object.</p>"
- },
- "IsLatest":{
- "shape":"IsLatest",
+ },
+ "IsLatest":{
+ "shape":"IsLatest",
"documentation":"<p>Specifies whether the object is (true) or is not (false) the latest version of an object.</p>"
- },
- "LastModified":{
- "shape":"LastModified",
+ },
+ "LastModified":{
+ "shape":"LastModified",
"documentation":"<p>Date and time the object was last modified.</p>"
- },
+ },
"Owner":{
"shape":"Owner",
"documentation":"<p>Specifies the owner of the object.</p>"
}
},
"documentation":"<p>The version of an object.</p>"
- },
- "ObjectVersionId":{"type":"string"},
- "ObjectVersionList":{
- "type":"list",
- "member":{"shape":"ObjectVersion"},
- "flattened":true
- },
- "ObjectVersionStorageClass":{
- "type":"string",
- "enum":["STANDARD"]
- },
- "OutputLocation":{
- "type":"structure",
- "members":{
- "S3":{
- "shape":"S3Location",
+ },
+ "ObjectVersionId":{"type":"string"},
+ "ObjectVersionList":{
+ "type":"list",
+ "member":{"shape":"ObjectVersion"},
+ "flattened":true
+ },
+ "ObjectVersionStorageClass":{
+ "type":"string",
+ "enum":["STANDARD"]
+ },
+ "OutputLocation":{
+ "type":"structure",
+ "members":{
+ "S3":{
+ "shape":"S3Location",
"documentation":"<p>Describes an S3 location that will receive the results of the restore request.</p>"
- }
- },
+ }
+ },
"documentation":"<p>Describes the location where the restore job's output is stored.</p>"
- },
- "OutputSerialization":{
- "type":"structure",
- "members":{
- "CSV":{
- "shape":"CSVOutput",
+ },
+ "OutputSerialization":{
+ "type":"structure",
+ "members":{
+ "CSV":{
+ "shape":"CSVOutput",
"documentation":"<p>Describes the serialization of CSV-encoded Select results.</p>"
- },
- "JSON":{
- "shape":"JSONOutput",
+ },
+ "JSON":{
+ "shape":"JSONOutput",
"documentation":"<p>Specifies JSON as request's output serialization format.</p>"
- }
- },
+ }
+ },
"documentation":"<p>Describes how results of the Select job are serialized.</p>"
- },
- "Owner":{
- "type":"structure",
- "members":{
+ },
+ "Owner":{
+ "type":"structure",
+ "members":{
"DisplayName":{
"shape":"DisplayName",
"documentation":"<p>Container for the display name of the owner.</p>"
@@ -6785,11 +6785,11 @@
}
},
"documentation":"<p>Container for the owner's display name and ID.</p>"
- },
- "OwnerOverride":{
- "type":"string",
- "enum":["Destination"]
- },
+ },
+ "OwnerOverride":{
+ "type":"string",
+ "enum":["Destination"]
+ },
"OwnershipControls":{
"type":"structure",
"required":["Rules"],
@@ -6821,54 +6821,54 @@
},
"documentation":"<p>Container for Parquet.</p>"
},
- "Part":{
- "type":"structure",
- "members":{
- "PartNumber":{
- "shape":"PartNumber",
+ "Part":{
+ "type":"structure",
+ "members":{
+ "PartNumber":{
+ "shape":"PartNumber",
"documentation":"<p>Part number identifying the part. This is a positive integer between 1 and 10,000.</p>"
- },
- "LastModified":{
- "shape":"LastModified",
+ },
+ "LastModified":{
+ "shape":"LastModified",
"documentation":"<p>Date and time at which the part was uploaded.</p>"
- },
- "ETag":{
- "shape":"ETag",
+ },
+ "ETag":{
+ "shape":"ETag",
"documentation":"<p>Entity tag returned when the part was uploaded.</p>"
- },
- "Size":{
- "shape":"Size",
+ },
+ "Size":{
+ "shape":"Size",
"documentation":"<p>Size in bytes of the uploaded part data.</p>"
- }
+ }
},
"documentation":"<p>Container for elements related to a part.</p>"
- },
- "PartNumber":{"type":"integer"},
- "PartNumberMarker":{"type":"integer"},
- "Parts":{
- "type":"list",
- "member":{"shape":"Part"},
- "flattened":true
- },
- "PartsCount":{"type":"integer"},
- "Payer":{
- "type":"string",
- "enum":[
- "Requester",
- "BucketOwner"
- ]
- },
- "Permission":{
- "type":"string",
- "enum":[
- "FULL_CONTROL",
- "WRITE",
- "WRITE_ACP",
- "READ",
- "READ_ACP"
- ]
- },
- "Policy":{"type":"string"},
+ },
+ "PartNumber":{"type":"integer"},
+ "PartNumberMarker":{"type":"integer"},
+ "Parts":{
+ "type":"list",
+ "member":{"shape":"Part"},
+ "flattened":true
+ },
+ "PartsCount":{"type":"integer"},
+ "Payer":{
+ "type":"string",
+ "enum":[
+ "Requester",
+ "BucketOwner"
+ ]
+ },
+ "Permission":{
+ "type":"string",
+ "enum":[
+ "FULL_CONTROL",
+ "WRITE",
+ "WRITE_ACP",
+ "READ",
+ "READ_ACP"
+ ]
+ },
+ "Policy":{"type":"string"},
"PolicyStatus":{
"type":"structure",
"members":{
@@ -6880,45 +6880,45 @@
},
"documentation":"<p>The container element for a bucket's policy status.</p>"
},
- "Prefix":{"type":"string"},
+ "Prefix":{"type":"string"},
"Priority":{"type":"integer"},
- "Progress":{
- "type":"structure",
- "members":{
- "BytesScanned":{
- "shape":"BytesScanned",
+ "Progress":{
+ "type":"structure",
+ "members":{
+ "BytesScanned":{
+ "shape":"BytesScanned",
"documentation":"<p>The current number of object bytes scanned.</p>"
- },
- "BytesProcessed":{
- "shape":"BytesProcessed",
+ },
+ "BytesProcessed":{
+ "shape":"BytesProcessed",
"documentation":"<p>The current number of uncompressed object bytes processed.</p>"
- },
- "BytesReturned":{
- "shape":"BytesReturned",
+ },
+ "BytesReturned":{
+ "shape":"BytesReturned",
"documentation":"<p>The current number of bytes of records payload data returned.</p>"
- }
+ }
},
"documentation":"<p>This data type contains information about progress of an operation.</p>"
- },
- "ProgressEvent":{
- "type":"structure",
- "members":{
- "Details":{
- "shape":"Progress",
+ },
+ "ProgressEvent":{
+ "type":"structure",
+ "members":{
+ "Details":{
+ "shape":"Progress",
"documentation":"<p>The Progress event details.</p>",
- "eventpayload":true
- }
- },
+ "eventpayload":true
+ }
+ },
"documentation":"<p>This data type contains information about the progress event of an operation.</p>",
- "event":true
- },
- "Protocol":{
- "type":"string",
- "enum":[
- "http",
- "https"
- ]
- },
+ "event":true
+ },
+ "Protocol":{
+ "type":"string",
+ "enum":[
+ "http",
+ "https"
+ ]
+ },
"PublicAccessBlockConfiguration":{
"type":"structure",
"members":{
@@ -6945,203 +6945,203 @@
},
"documentation":"<p>The PublicAccessBlock configuration that you want to apply to this Amazon S3 bucket. You can enable the configuration options in any combination. For more information about when Amazon S3 considers a bucket or object public, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/access-control-block-public-access.html#access-control-block-public-access-policy-status\">The Meaning of \"Public\"</a> in the <i>Amazon S3 User Guide</i>. </p>"
},
- "PutBucketAccelerateConfigurationRequest":{
- "type":"structure",
- "required":[
- "Bucket",
- "AccelerateConfiguration"
- ],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ "PutBucketAccelerateConfigurationRequest":{
+ "type":"structure",
+ "required":[
+ "Bucket",
+ "AccelerateConfiguration"
+ ],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The name of the bucket for which the accelerate configuration is set.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "AccelerateConfiguration":{
- "shape":"AccelerateConfiguration",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "AccelerateConfiguration":{
+ "shape":"AccelerateConfiguration",
"documentation":"<p>Container for setting the transfer acceleration state.</p>",
- "locationName":"AccelerateConfiguration",
- "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
+ "locationName":"AccelerateConfiguration",
+ "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- },
- "payload":"AccelerateConfiguration"
- },
- "PutBucketAclRequest":{
- "type":"structure",
- "required":["Bucket"],
- "members":{
- "ACL":{
- "shape":"BucketCannedACL",
+ }
+ },
+ "payload":"AccelerateConfiguration"
+ },
+ "PutBucketAclRequest":{
+ "type":"structure",
+ "required":["Bucket"],
+ "members":{
+ "ACL":{
+ "shape":"BucketCannedACL",
"documentation":"<p>The canned ACL to apply to the bucket.</p>",
- "location":"header",
- "locationName":"x-amz-acl"
- },
- "AccessControlPolicy":{
- "shape":"AccessControlPolicy",
+ "location":"header",
+ "locationName":"x-amz-acl"
+ },
+ "AccessControlPolicy":{
+ "shape":"AccessControlPolicy",
"documentation":"<p>Contains the elements that set the ACL permissions for an object per grantee.</p>",
- "locationName":"AccessControlPolicy",
- "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
- },
- "Bucket":{
- "shape":"BucketName",
+ "locationName":"AccessControlPolicy",
+ "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
+ },
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The bucket to which to apply the ACL.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "ContentMD5":{
- "shape":"ContentMD5",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "ContentMD5":{
+ "shape":"ContentMD5",
"documentation":"<p>The base64-encoded 128-bit MD5 digest of the data. This header must be used as a message integrity check to verify that the request body was not corrupted in transit. For more information, go to <a href=\"http://www.ietf.org/rfc/rfc1864.txt\">RFC 1864.</a> </p> <p>For requests made using the AWS Command Line Interface (CLI) or AWS SDKs, this field is calculated automatically.</p>",
- "location":"header",
- "locationName":"Content-MD5"
- },
- "GrantFullControl":{
- "shape":"GrantFullControl",
+ "location":"header",
+ "locationName":"Content-MD5"
+ },
+ "GrantFullControl":{
+ "shape":"GrantFullControl",
"documentation":"<p>Allows grantee the read, write, read ACP, and write ACP permissions on the bucket.</p>",
- "location":"header",
- "locationName":"x-amz-grant-full-control"
- },
- "GrantRead":{
- "shape":"GrantRead",
+ "location":"header",
+ "locationName":"x-amz-grant-full-control"
+ },
+ "GrantRead":{
+ "shape":"GrantRead",
"documentation":"<p>Allows grantee to list the objects in the bucket.</p>",
- "location":"header",
- "locationName":"x-amz-grant-read"
- },
- "GrantReadACP":{
- "shape":"GrantReadACP",
+ "location":"header",
+ "locationName":"x-amz-grant-read"
+ },
+ "GrantReadACP":{
+ "shape":"GrantReadACP",
"documentation":"<p>Allows grantee to read the bucket ACL.</p>",
- "location":"header",
- "locationName":"x-amz-grant-read-acp"
- },
- "GrantWrite":{
- "shape":"GrantWrite",
+ "location":"header",
+ "locationName":"x-amz-grant-read-acp"
+ },
+ "GrantWrite":{
+ "shape":"GrantWrite",
"documentation":"<p>Allows grantee to create new objects in the bucket.</p> <p>For the bucket and object owners of existing objects, also allows deletions and overwrites of those objects.</p>",
- "location":"header",
- "locationName":"x-amz-grant-write"
- },
- "GrantWriteACP":{
- "shape":"GrantWriteACP",
+ "location":"header",
+ "locationName":"x-amz-grant-write"
+ },
+ "GrantWriteACP":{
+ "shape":"GrantWriteACP",
"documentation":"<p>Allows grantee to write the ACL for the applicable bucket.</p>",
- "location":"header",
- "locationName":"x-amz-grant-write-acp"
+ "location":"header",
+ "locationName":"x-amz-grant-write-acp"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- },
- "payload":"AccessControlPolicy"
- },
- "PutBucketAnalyticsConfigurationRequest":{
- "type":"structure",
- "required":[
- "Bucket",
- "Id",
- "AnalyticsConfiguration"
- ],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ }
+ },
+ "payload":"AccessControlPolicy"
+ },
+ "PutBucketAnalyticsConfigurationRequest":{
+ "type":"structure",
+ "required":[
+ "Bucket",
+ "Id",
+ "AnalyticsConfiguration"
+ ],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The name of the bucket to which an analytics configuration is stored.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "Id":{
- "shape":"AnalyticsId",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "Id":{
+ "shape":"AnalyticsId",
"documentation":"<p>The ID that identifies the analytics configuration.</p>",
- "location":"querystring",
- "locationName":"id"
- },
- "AnalyticsConfiguration":{
- "shape":"AnalyticsConfiguration",
+ "location":"querystring",
+ "locationName":"id"
+ },
+ "AnalyticsConfiguration":{
+ "shape":"AnalyticsConfiguration",
"documentation":"<p>The configuration and any analyses for the analytics filter.</p>",
- "locationName":"AnalyticsConfiguration",
- "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
+ "locationName":"AnalyticsConfiguration",
+ "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- },
- "payload":"AnalyticsConfiguration"
- },
- "PutBucketCorsRequest":{
- "type":"structure",
- "required":[
- "Bucket",
- "CORSConfiguration"
- ],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ }
+ },
+ "payload":"AnalyticsConfiguration"
+ },
+ "PutBucketCorsRequest":{
+ "type":"structure",
+ "required":[
+ "Bucket",
+ "CORSConfiguration"
+ ],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>Specifies the bucket impacted by the <code>cors</code>configuration.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "CORSConfiguration":{
- "shape":"CORSConfiguration",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "CORSConfiguration":{
+ "shape":"CORSConfiguration",
"documentation":"<p>Describes the cross-origin access configuration for objects in an Amazon S3 bucket. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/cors.html\">Enabling Cross-Origin Resource Sharing</a> in the <i>Amazon S3 User Guide</i>.</p>",
- "locationName":"CORSConfiguration",
- "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
- },
- "ContentMD5":{
- "shape":"ContentMD5",
+ "locationName":"CORSConfiguration",
+ "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
+ },
+ "ContentMD5":{
+ "shape":"ContentMD5",
"documentation":"<p>The base64-encoded 128-bit MD5 digest of the data. This header must be used as a message integrity check to verify that the request body was not corrupted in transit. For more information, go to <a href=\"http://www.ietf.org/rfc/rfc1864.txt\">RFC 1864.</a> </p> <p>For requests made using the AWS Command Line Interface (CLI) or AWS SDKs, this field is calculated automatically.</p>",
- "location":"header",
- "locationName":"Content-MD5"
+ "location":"header",
+ "locationName":"Content-MD5"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- },
- "payload":"CORSConfiguration"
- },
- "PutBucketEncryptionRequest":{
- "type":"structure",
- "required":[
- "Bucket",
- "ServerSideEncryptionConfiguration"
- ],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ }
+ },
+ "payload":"CORSConfiguration"
+ },
+ "PutBucketEncryptionRequest":{
+ "type":"structure",
+ "required":[
+ "Bucket",
+ "ServerSideEncryptionConfiguration"
+ ],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>Specifies default encryption for a bucket using server-side encryption with Amazon S3-managed keys (SSE-S3) or customer master keys stored in AWS KMS (SSE-KMS). For information about the Amazon S3 default encryption feature, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/bucket-encryption.html\">Amazon S3 Default Bucket Encryption</a> in the <i>Amazon S3 User Guide</i>.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "ContentMD5":{
- "shape":"ContentMD5",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "ContentMD5":{
+ "shape":"ContentMD5",
"documentation":"<p>The base64-encoded 128-bit MD5 digest of the server-side encryption configuration.</p> <p>For requests made using the AWS Command Line Interface (CLI) or AWS SDKs, this field is calculated automatically.</p>",
- "location":"header",
- "locationName":"Content-MD5"
- },
- "ServerSideEncryptionConfiguration":{
- "shape":"ServerSideEncryptionConfiguration",
- "locationName":"ServerSideEncryptionConfiguration",
- "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
+ "location":"header",
+ "locationName":"Content-MD5"
+ },
+ "ServerSideEncryptionConfiguration":{
+ "shape":"ServerSideEncryptionConfiguration",
+ "locationName":"ServerSideEncryptionConfiguration",
+ "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- },
- "payload":"ServerSideEncryptionConfiguration"
- },
+ }
+ },
+ "payload":"ServerSideEncryptionConfiguration"
+ },
"PutBucketIntelligentTieringConfigurationRequest":{
"type":"structure",
"required":[
@@ -7171,227 +7171,227 @@
},
"payload":"IntelligentTieringConfiguration"
},
- "PutBucketInventoryConfigurationRequest":{
- "type":"structure",
- "required":[
- "Bucket",
- "Id",
- "InventoryConfiguration"
- ],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ "PutBucketInventoryConfigurationRequest":{
+ "type":"structure",
+ "required":[
+ "Bucket",
+ "Id",
+ "InventoryConfiguration"
+ ],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The name of the bucket where the inventory configuration will be stored.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "Id":{
- "shape":"InventoryId",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "Id":{
+ "shape":"InventoryId",
"documentation":"<p>The ID used to identify the inventory configuration.</p>",
- "location":"querystring",
- "locationName":"id"
- },
- "InventoryConfiguration":{
- "shape":"InventoryConfiguration",
+ "location":"querystring",
+ "locationName":"id"
+ },
+ "InventoryConfiguration":{
+ "shape":"InventoryConfiguration",
"documentation":"<p>Specifies the inventory configuration.</p>",
- "locationName":"InventoryConfiguration",
- "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
+ "locationName":"InventoryConfiguration",
+ "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- },
- "payload":"InventoryConfiguration"
- },
- "PutBucketLifecycleConfigurationRequest":{
- "type":"structure",
- "required":["Bucket"],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ }
+ },
+ "payload":"InventoryConfiguration"
+ },
+ "PutBucketLifecycleConfigurationRequest":{
+ "type":"structure",
+ "required":["Bucket"],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The name of the bucket for which to set the configuration.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "LifecycleConfiguration":{
- "shape":"BucketLifecycleConfiguration",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "LifecycleConfiguration":{
+ "shape":"BucketLifecycleConfiguration",
"documentation":"<p>Container for lifecycle rules. You can add as many as 1,000 rules.</p>",
- "locationName":"LifecycleConfiguration",
- "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
+ "locationName":"LifecycleConfiguration",
+ "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- },
- "payload":"LifecycleConfiguration"
- },
- "PutBucketLifecycleRequest":{
- "type":"structure",
- "required":["Bucket"],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ }
+ },
+ "payload":"LifecycleConfiguration"
+ },
+ "PutBucketLifecycleRequest":{
+ "type":"structure",
+ "required":["Bucket"],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p/>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "ContentMD5":{
- "shape":"ContentMD5",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "ContentMD5":{
+ "shape":"ContentMD5",
"documentation":"<p/> <p>For requests made using the AWS Command Line Interface (CLI) or AWS SDKs, this field is calculated automatically.</p>",
- "location":"header",
- "locationName":"Content-MD5"
- },
- "LifecycleConfiguration":{
- "shape":"LifecycleConfiguration",
+ "location":"header",
+ "locationName":"Content-MD5"
+ },
+ "LifecycleConfiguration":{
+ "shape":"LifecycleConfiguration",
"documentation":"<p/>",
- "locationName":"LifecycleConfiguration",
- "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
+ "locationName":"LifecycleConfiguration",
+ "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- },
- "payload":"LifecycleConfiguration"
- },
- "PutBucketLoggingRequest":{
- "type":"structure",
- "required":[
- "Bucket",
- "BucketLoggingStatus"
- ],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ }
+ },
+ "payload":"LifecycleConfiguration"
+ },
+ "PutBucketLoggingRequest":{
+ "type":"structure",
+ "required":[
+ "Bucket",
+ "BucketLoggingStatus"
+ ],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The name of the bucket for which to set the logging parameters.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "BucketLoggingStatus":{
- "shape":"BucketLoggingStatus",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "BucketLoggingStatus":{
+ "shape":"BucketLoggingStatus",
"documentation":"<p>Container for logging status information.</p>",
- "locationName":"BucketLoggingStatus",
- "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
- },
- "ContentMD5":{
- "shape":"ContentMD5",
+ "locationName":"BucketLoggingStatus",
+ "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
+ },
+ "ContentMD5":{
+ "shape":"ContentMD5",
"documentation":"<p>The MD5 hash of the <code>PutBucketLogging</code> request body.</p> <p>For requests made using the AWS Command Line Interface (CLI) or AWS SDKs, this field is calculated automatically.</p>",
- "location":"header",
- "locationName":"Content-MD5"
+ "location":"header",
+ "locationName":"Content-MD5"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- },
- "payload":"BucketLoggingStatus"
- },
- "PutBucketMetricsConfigurationRequest":{
- "type":"structure",
- "required":[
- "Bucket",
- "Id",
- "MetricsConfiguration"
- ],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ }
+ },
+ "payload":"BucketLoggingStatus"
+ },
+ "PutBucketMetricsConfigurationRequest":{
+ "type":"structure",
+ "required":[
+ "Bucket",
+ "Id",
+ "MetricsConfiguration"
+ ],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The name of the bucket for which the metrics configuration is set.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "Id":{
- "shape":"MetricsId",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "Id":{
+ "shape":"MetricsId",
"documentation":"<p>The ID used to identify the metrics configuration.</p>",
- "location":"querystring",
- "locationName":"id"
- },
- "MetricsConfiguration":{
- "shape":"MetricsConfiguration",
+ "location":"querystring",
+ "locationName":"id"
+ },
+ "MetricsConfiguration":{
+ "shape":"MetricsConfiguration",
"documentation":"<p>Specifies the metrics configuration.</p>",
- "locationName":"MetricsConfiguration",
- "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
+ "locationName":"MetricsConfiguration",
+ "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- },
- "payload":"MetricsConfiguration"
- },
- "PutBucketNotificationConfigurationRequest":{
- "type":"structure",
- "required":[
- "Bucket",
- "NotificationConfiguration"
- ],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ }
+ },
+ "payload":"MetricsConfiguration"
+ },
+ "PutBucketNotificationConfigurationRequest":{
+ "type":"structure",
+ "required":[
+ "Bucket",
+ "NotificationConfiguration"
+ ],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The name of the bucket.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "NotificationConfiguration":{
- "shape":"NotificationConfiguration",
- "locationName":"NotificationConfiguration",
- "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "NotificationConfiguration":{
+ "shape":"NotificationConfiguration",
+ "locationName":"NotificationConfiguration",
+ "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- },
- "payload":"NotificationConfiguration"
- },
- "PutBucketNotificationRequest":{
- "type":"structure",
- "required":[
- "Bucket",
- "NotificationConfiguration"
- ],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ }
+ },
+ "payload":"NotificationConfiguration"
+ },
+ "PutBucketNotificationRequest":{
+ "type":"structure",
+ "required":[
+ "Bucket",
+ "NotificationConfiguration"
+ ],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The name of the bucket.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "ContentMD5":{
- "shape":"ContentMD5",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "ContentMD5":{
+ "shape":"ContentMD5",
"documentation":"<p>The MD5 hash of the <code>PutPublicAccessBlock</code> request body.</p> <p>For requests made using the AWS Command Line Interface (CLI) or AWS SDKs, this field is calculated automatically.</p>",
- "location":"header",
- "locationName":"Content-MD5"
- },
- "NotificationConfiguration":{
- "shape":"NotificationConfigurationDeprecated",
+ "location":"header",
+ "locationName":"Content-MD5"
+ },
+ "NotificationConfiguration":{
+ "shape":"NotificationConfigurationDeprecated",
"documentation":"<p>The container for the configuration.</p>",
- "locationName":"NotificationConfiguration",
- "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
+ "locationName":"NotificationConfiguration",
+ "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- },
- "payload":"NotificationConfiguration"
- },
+ }
+ },
+ "payload":"NotificationConfiguration"
+ },
"PutBucketOwnershipControlsRequest":{
"type":"structure",
"required":[
@@ -7426,33 +7426,33 @@
},
"payload":"OwnershipControls"
},
- "PutBucketPolicyRequest":{
- "type":"structure",
- "required":[
- "Bucket",
- "Policy"
- ],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ "PutBucketPolicyRequest":{
+ "type":"structure",
+ "required":[
+ "Bucket",
+ "Policy"
+ ],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The name of the bucket.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "ContentMD5":{
- "shape":"ContentMD5",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "ContentMD5":{
+ "shape":"ContentMD5",
"documentation":"<p>The MD5 hash of the request body.</p> <p>For requests made using the AWS Command Line Interface (CLI) or AWS SDKs, this field is calculated automatically.</p>",
- "location":"header",
- "locationName":"Content-MD5"
- },
- "ConfirmRemoveSelfBucketAccess":{
- "shape":"ConfirmRemoveSelfBucketAccess",
+ "location":"header",
+ "locationName":"Content-MD5"
+ },
+ "ConfirmRemoveSelfBucketAccess":{
+ "shape":"ConfirmRemoveSelfBucketAccess",
"documentation":"<p>Set this parameter to true to confirm that you want to remove your permissions to change this bucket policy in the future.</p>",
- "location":"header",
- "locationName":"x-amz-confirm-remove-self-bucket-access"
- },
- "Policy":{
- "shape":"Policy",
+ "location":"header",
+ "locationName":"x-amz-confirm-remove-self-bucket-access"
+ },
+ "Policy":{
+ "shape":"Policy",
"documentation":"<p>The bucket policy as a JSON document.</p>"
},
"ExpectedBucketOwner":{
@@ -7460,33 +7460,33 @@
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- },
- "payload":"Policy"
- },
- "PutBucketReplicationRequest":{
- "type":"structure",
- "required":[
- "Bucket",
- "ReplicationConfiguration"
- ],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ }
+ },
+ "payload":"Policy"
+ },
+ "PutBucketReplicationRequest":{
+ "type":"structure",
+ "required":[
+ "Bucket",
+ "ReplicationConfiguration"
+ ],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The name of the bucket</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "ContentMD5":{
- "shape":"ContentMD5",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "ContentMD5":{
+ "shape":"ContentMD5",
"documentation":"<p>The base64-encoded 128-bit MD5 digest of the data. You must use this header as a message integrity check to verify that the request body was not corrupted in transit. For more information, see <a href=\"http://www.ietf.org/rfc/rfc1864.txt\">RFC 1864</a>.</p> <p>For requests made using the AWS Command Line Interface (CLI) or AWS SDKs, this field is calculated automatically.</p>",
- "location":"header",
- "locationName":"Content-MD5"
- },
- "ReplicationConfiguration":{
- "shape":"ReplicationConfiguration",
- "locationName":"ReplicationConfiguration",
- "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
+ "location":"header",
+ "locationName":"Content-MD5"
+ },
+ "ReplicationConfiguration":{
+ "shape":"ReplicationConfiguration",
+ "locationName":"ReplicationConfiguration",
+ "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
},
"Token":{
"shape":"ObjectLockToken",
@@ -7499,249 +7499,249 @@
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- },
- "payload":"ReplicationConfiguration"
- },
- "PutBucketRequestPaymentRequest":{
- "type":"structure",
- "required":[
- "Bucket",
- "RequestPaymentConfiguration"
- ],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ }
+ },
+ "payload":"ReplicationConfiguration"
+ },
+ "PutBucketRequestPaymentRequest":{
+ "type":"structure",
+ "required":[
+ "Bucket",
+ "RequestPaymentConfiguration"
+ ],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The bucket name.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "ContentMD5":{
- "shape":"ContentMD5",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "ContentMD5":{
+ "shape":"ContentMD5",
"documentation":"<p>The base64-encoded 128-bit MD5 digest of the data. You must use this header as a message integrity check to verify that the request body was not corrupted in transit. For more information, see <a href=\"http://www.ietf.org/rfc/rfc1864.txt\">RFC 1864</a>.</p> <p>For requests made using the AWS Command Line Interface (CLI) or AWS SDKs, this field is calculated automatically.</p>",
- "location":"header",
- "locationName":"Content-MD5"
- },
- "RequestPaymentConfiguration":{
- "shape":"RequestPaymentConfiguration",
+ "location":"header",
+ "locationName":"Content-MD5"
+ },
+ "RequestPaymentConfiguration":{
+ "shape":"RequestPaymentConfiguration",
"documentation":"<p>Container for Payer.</p>",
- "locationName":"RequestPaymentConfiguration",
- "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
+ "locationName":"RequestPaymentConfiguration",
+ "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- },
- "payload":"RequestPaymentConfiguration"
- },
- "PutBucketTaggingRequest":{
- "type":"structure",
- "required":[
- "Bucket",
- "Tagging"
- ],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ }
+ },
+ "payload":"RequestPaymentConfiguration"
+ },
+ "PutBucketTaggingRequest":{
+ "type":"structure",
+ "required":[
+ "Bucket",
+ "Tagging"
+ ],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The bucket name.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "ContentMD5":{
- "shape":"ContentMD5",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "ContentMD5":{
+ "shape":"ContentMD5",
"documentation":"<p>The base64-encoded 128-bit MD5 digest of the data. You must use this header as a message integrity check to verify that the request body was not corrupted in transit. For more information, see <a href=\"http://www.ietf.org/rfc/rfc1864.txt\">RFC 1864</a>.</p> <p>For requests made using the AWS Command Line Interface (CLI) or AWS SDKs, this field is calculated automatically.</p>",
- "location":"header",
- "locationName":"Content-MD5"
- },
- "Tagging":{
- "shape":"Tagging",
+ "location":"header",
+ "locationName":"Content-MD5"
+ },
+ "Tagging":{
+ "shape":"Tagging",
"documentation":"<p>Container for the <code>TagSet</code> and <code>Tag</code> elements.</p>",
- "locationName":"Tagging",
- "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
+ "locationName":"Tagging",
+ "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- },
- "payload":"Tagging"
- },
- "PutBucketVersioningRequest":{
- "type":"structure",
- "required":[
- "Bucket",
- "VersioningConfiguration"
- ],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ }
+ },
+ "payload":"Tagging"
+ },
+ "PutBucketVersioningRequest":{
+ "type":"structure",
+ "required":[
+ "Bucket",
+ "VersioningConfiguration"
+ ],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The bucket name.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "ContentMD5":{
- "shape":"ContentMD5",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "ContentMD5":{
+ "shape":"ContentMD5",
"documentation":"<p>&gt;The base64-encoded 128-bit MD5 digest of the data. You must use this header as a message integrity check to verify that the request body was not corrupted in transit. For more information, see <a href=\"http://www.ietf.org/rfc/rfc1864.txt\">RFC 1864</a>.</p> <p>For requests made using the AWS Command Line Interface (CLI) or AWS SDKs, this field is calculated automatically.</p>",
- "location":"header",
- "locationName":"Content-MD5"
- },
- "MFA":{
- "shape":"MFA",
+ "location":"header",
+ "locationName":"Content-MD5"
+ },
+ "MFA":{
+ "shape":"MFA",
"documentation":"<p>The concatenation of the authentication device's serial number, a space, and the value that is displayed on your authentication device.</p>",
- "location":"header",
- "locationName":"x-amz-mfa"
- },
- "VersioningConfiguration":{
- "shape":"VersioningConfiguration",
+ "location":"header",
+ "locationName":"x-amz-mfa"
+ },
+ "VersioningConfiguration":{
+ "shape":"VersioningConfiguration",
"documentation":"<p>Container for setting the versioning state.</p>",
- "locationName":"VersioningConfiguration",
- "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
+ "locationName":"VersioningConfiguration",
+ "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- },
- "payload":"VersioningConfiguration"
- },
- "PutBucketWebsiteRequest":{
- "type":"structure",
- "required":[
- "Bucket",
- "WebsiteConfiguration"
- ],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ }
+ },
+ "payload":"VersioningConfiguration"
+ },
+ "PutBucketWebsiteRequest":{
+ "type":"structure",
+ "required":[
+ "Bucket",
+ "WebsiteConfiguration"
+ ],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The bucket name.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "ContentMD5":{
- "shape":"ContentMD5",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "ContentMD5":{
+ "shape":"ContentMD5",
"documentation":"<p>The base64-encoded 128-bit MD5 digest of the data. You must use this header as a message integrity check to verify that the request body was not corrupted in transit. For more information, see <a href=\"http://www.ietf.org/rfc/rfc1864.txt\">RFC 1864</a>.</p> <p>For requests made using the AWS Command Line Interface (CLI) or AWS SDKs, this field is calculated automatically.</p>",
- "location":"header",
- "locationName":"Content-MD5"
- },
- "WebsiteConfiguration":{
- "shape":"WebsiteConfiguration",
+ "location":"header",
+ "locationName":"Content-MD5"
+ },
+ "WebsiteConfiguration":{
+ "shape":"WebsiteConfiguration",
"documentation":"<p>Container for the request.</p>",
- "locationName":"WebsiteConfiguration",
- "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
+ "locationName":"WebsiteConfiguration",
+ "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- },
- "payload":"WebsiteConfiguration"
- },
- "PutObjectAclOutput":{
- "type":"structure",
- "members":{
- "RequestCharged":{
- "shape":"RequestCharged",
- "location":"header",
- "locationName":"x-amz-request-charged"
- }
- }
- },
- "PutObjectAclRequest":{
- "type":"structure",
- "required":[
- "Bucket",
- "Key"
- ],
- "members":{
- "ACL":{
- "shape":"ObjectCannedACL",
+ }
+ },
+ "payload":"WebsiteConfiguration"
+ },
+ "PutObjectAclOutput":{
+ "type":"structure",
+ "members":{
+ "RequestCharged":{
+ "shape":"RequestCharged",
+ "location":"header",
+ "locationName":"x-amz-request-charged"
+ }
+ }
+ },
+ "PutObjectAclRequest":{
+ "type":"structure",
+ "required":[
+ "Bucket",
+ "Key"
+ ],
+ "members":{
+ "ACL":{
+ "shape":"ObjectCannedACL",
"documentation":"<p>The canned ACL to apply to the object. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#CannedACL\">Canned ACL</a>.</p>",
- "location":"header",
- "locationName":"x-amz-acl"
- },
- "AccessControlPolicy":{
- "shape":"AccessControlPolicy",
+ "location":"header",
+ "locationName":"x-amz-acl"
+ },
+ "AccessControlPolicy":{
+ "shape":"AccessControlPolicy",
"documentation":"<p>Contains the elements that set the ACL permissions for an object per grantee.</p>",
- "locationName":"AccessControlPolicy",
- "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
- },
- "Bucket":{
- "shape":"BucketName",
+ "locationName":"AccessControlPolicy",
+ "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
+ },
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The bucket name that contains the object to which you want to attach the ACL. </p> <p>When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.s3-accesspoint.<i>Region</i>.amazonaws.com. When using this action with an access point through the AWS SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\">Using access points</a> in the <i>Amazon S3 User Guide</i>.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "ContentMD5":{
- "shape":"ContentMD5",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "ContentMD5":{
+ "shape":"ContentMD5",
"documentation":"<p>The base64-encoded 128-bit MD5 digest of the data. This header must be used as a message integrity check to verify that the request body was not corrupted in transit. For more information, go to <a href=\"http://www.ietf.org/rfc/rfc1864.txt\">RFC 1864.&gt;</a> </p> <p>For requests made using the AWS Command Line Interface (CLI) or AWS SDKs, this field is calculated automatically.</p>",
- "location":"header",
- "locationName":"Content-MD5"
- },
- "GrantFullControl":{
- "shape":"GrantFullControl",
+ "location":"header",
+ "locationName":"Content-MD5"
+ },
+ "GrantFullControl":{
+ "shape":"GrantFullControl",
"documentation":"<p>Allows grantee the read, write, read ACP, and write ACP permissions on the bucket.</p> <p>This action is not supported by Amazon S3 on Outposts.</p>",
- "location":"header",
- "locationName":"x-amz-grant-full-control"
- },
- "GrantRead":{
- "shape":"GrantRead",
+ "location":"header",
+ "locationName":"x-amz-grant-full-control"
+ },
+ "GrantRead":{
+ "shape":"GrantRead",
"documentation":"<p>Allows grantee to list the objects in the bucket.</p> <p>This action is not supported by Amazon S3 on Outposts.</p>",
- "location":"header",
- "locationName":"x-amz-grant-read"
- },
- "GrantReadACP":{
- "shape":"GrantReadACP",
+ "location":"header",
+ "locationName":"x-amz-grant-read"
+ },
+ "GrantReadACP":{
+ "shape":"GrantReadACP",
"documentation":"<p>Allows grantee to read the bucket ACL.</p> <p>This action is not supported by Amazon S3 on Outposts.</p>",
- "location":"header",
- "locationName":"x-amz-grant-read-acp"
- },
- "GrantWrite":{
- "shape":"GrantWrite",
+ "location":"header",
+ "locationName":"x-amz-grant-read-acp"
+ },
+ "GrantWrite":{
+ "shape":"GrantWrite",
"documentation":"<p>Allows grantee to create new objects in the bucket.</p> <p>For the bucket and object owners of existing objects, also allows deletions and overwrites of those objects.</p>",
- "location":"header",
- "locationName":"x-amz-grant-write"
- },
- "GrantWriteACP":{
- "shape":"GrantWriteACP",
+ "location":"header",
+ "locationName":"x-amz-grant-write"
+ },
+ "GrantWriteACP":{
+ "shape":"GrantWriteACP",
"documentation":"<p>Allows grantee to write the ACL for the applicable bucket.</p> <p>This action is not supported by Amazon S3 on Outposts.</p>",
- "location":"header",
- "locationName":"x-amz-grant-write-acp"
- },
- "Key":{
- "shape":"ObjectKey",
+ "location":"header",
+ "locationName":"x-amz-grant-write-acp"
+ },
+ "Key":{
+ "shape":"ObjectKey",
"documentation":"<p>Key for which the PUT action was initiated.</p> <p>When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.s3-accesspoint.<i>Region</i>.amazonaws.com. When using this action with an access point through the AWS SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\">Using access points</a> in the <i>Amazon S3 User Guide</i>.</p> <p>When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.<i>outpostID</i>.s3-outposts.<i>Region</i>.amazonaws.com. When using this action using S3 on Outposts through the AWS SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html\">Using S3 on Outposts</a> in the <i>Amazon S3 User Guide</i>.</p>",
- "location":"uri",
- "locationName":"Key"
- },
- "RequestPayer":{
- "shape":"RequestPayer",
- "location":"header",
- "locationName":"x-amz-request-payer"
- },
- "VersionId":{
- "shape":"ObjectVersionId",
+ "location":"uri",
+ "locationName":"Key"
+ },
+ "RequestPayer":{
+ "shape":"RequestPayer",
+ "location":"header",
+ "locationName":"x-amz-request-payer"
+ },
+ "VersionId":{
+ "shape":"ObjectVersionId",
"documentation":"<p>VersionId used to reference a specific version of the object.</p>",
- "location":"querystring",
- "locationName":"versionId"
+ "location":"querystring",
+ "locationName":"versionId"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- },
- "payload":"AccessControlPolicy"
- },
+ }
+ },
+ "payload":"AccessControlPolicy"
+ },
"PutObjectLegalHoldOutput":{
"type":"structure",
"members":{
@@ -7855,51 +7855,51 @@
},
"payload":"ObjectLockConfiguration"
},
- "PutObjectOutput":{
- "type":"structure",
- "members":{
- "Expiration":{
- "shape":"Expiration",
+ "PutObjectOutput":{
+ "type":"structure",
+ "members":{
+ "Expiration":{
+ "shape":"Expiration",
"documentation":"<p> If the expiration is configured for the object (see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketLifecycleConfiguration.html\">PutBucketLifecycleConfiguration</a>), the response includes this header. It includes the expiry-date and rule-id key-value pairs that provide information about object expiration. The value of the rule-id is URL encoded.</p>",
- "location":"header",
- "locationName":"x-amz-expiration"
- },
- "ETag":{
- "shape":"ETag",
+ "location":"header",
+ "locationName":"x-amz-expiration"
+ },
+ "ETag":{
+ "shape":"ETag",
"documentation":"<p>Entity tag for the uploaded object.</p>",
- "location":"header",
- "locationName":"ETag"
- },
- "ServerSideEncryption":{
- "shape":"ServerSideEncryption",
+ "location":"header",
+ "locationName":"ETag"
+ },
+ "ServerSideEncryption":{
+ "shape":"ServerSideEncryption",
"documentation":"<p>If you specified server-side encryption either with an AWS KMS customer master key (CMK) or Amazon S3-managed encryption key in your PUT request, the response includes this header. It confirms the encryption algorithm that Amazon S3 used to encrypt the object.</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption"
- },
- "VersionId":{
- "shape":"ObjectVersionId",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption"
+ },
+ "VersionId":{
+ "shape":"ObjectVersionId",
"documentation":"<p>Version of the object.</p>",
- "location":"header",
- "locationName":"x-amz-version-id"
- },
- "SSECustomerAlgorithm":{
- "shape":"SSECustomerAlgorithm",
+ "location":"header",
+ "locationName":"x-amz-version-id"
+ },
+ "SSECustomerAlgorithm":{
+ "shape":"SSECustomerAlgorithm",
"documentation":"<p>If server-side encryption with a customer-provided encryption key was requested, the response will include this header confirming the encryption algorithm used.</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-customer-algorithm"
- },
- "SSECustomerKeyMD5":{
- "shape":"SSECustomerKeyMD5",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-customer-algorithm"
+ },
+ "SSECustomerKeyMD5":{
+ "shape":"SSECustomerKeyMD5",
"documentation":"<p>If server-side encryption with a customer-provided encryption key was requested, the response will include this header to provide round-trip message integrity verification of the customer-provided encryption key.</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-customer-key-MD5"
- },
- "SSEKMSKeyId":{
- "shape":"SSEKMSKeyId",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-customer-key-MD5"
+ },
+ "SSEKMSKeyId":{
+ "shape":"SSEKMSKeyId",
"documentation":"<p>If <code>x-amz-server-side-encryption</code> is present and has the value of <code>aws:kms</code>, this header specifies the ID of the AWS Key Management Service (AWS KMS) symmetric customer managed customer master key (CMK) that was used for the object. </p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-aws-kms-key-id"
- },
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-aws-kms-key-id"
+ },
"SSEKMSEncryptionContext":{
"shape":"SSEKMSEncryptionContext",
"documentation":"<p>If present, specifies the AWS KMS Encryption Context to use for object encryption. The value of this header is a base64-encoded UTF-8 string holding JSON with the encryption context key-value pairs.</p>",
@@ -7912,163 +7912,163 @@
"location":"header",
"locationName":"x-amz-server-side-encryption-bucket-key-enabled"
},
- "RequestCharged":{
- "shape":"RequestCharged",
- "location":"header",
- "locationName":"x-amz-request-charged"
- }
- }
- },
- "PutObjectRequest":{
- "type":"structure",
- "required":[
- "Bucket",
- "Key"
- ],
- "members":{
- "ACL":{
- "shape":"ObjectCannedACL",
+ "RequestCharged":{
+ "shape":"RequestCharged",
+ "location":"header",
+ "locationName":"x-amz-request-charged"
+ }
+ }
+ },
+ "PutObjectRequest":{
+ "type":"structure",
+ "required":[
+ "Bucket",
+ "Key"
+ ],
+ "members":{
+ "ACL":{
+ "shape":"ObjectCannedACL",
"documentation":"<p>The canned ACL to apply to the object. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#CannedACL\">Canned ACL</a>.</p> <p>This action is not supported by Amazon S3 on Outposts.</p>",
- "location":"header",
- "locationName":"x-amz-acl"
- },
- "Body":{
- "shape":"Body",
+ "location":"header",
+ "locationName":"x-amz-acl"
+ },
+ "Body":{
+ "shape":"Body",
"documentation":"<p>Object data.</p>",
- "streaming":true
- },
- "Bucket":{
- "shape":"BucketName",
+ "streaming":true
+ },
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The bucket name to which the PUT action was initiated. </p> <p>When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.s3-accesspoint.<i>Region</i>.amazonaws.com. When using this action with an access point through the AWS SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\">Using access points</a> in the <i>Amazon S3 User Guide</i>.</p> <p>When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.<i>outpostID</i>.s3-outposts.<i>Region</i>.amazonaws.com. When using this action using S3 on Outposts through the AWS SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html\">Using S3 on Outposts</a> in the <i>Amazon S3 User Guide</i>.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "CacheControl":{
- "shape":"CacheControl",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "CacheControl":{
+ "shape":"CacheControl",
"documentation":"<p> Can be used to specify caching behavior along the request/reply chain. For more information, see <a href=\"http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9\">http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9</a>.</p>",
- "location":"header",
- "locationName":"Cache-Control"
- },
- "ContentDisposition":{
- "shape":"ContentDisposition",
+ "location":"header",
+ "locationName":"Cache-Control"
+ },
+ "ContentDisposition":{
+ "shape":"ContentDisposition",
"documentation":"<p>Specifies presentational information for the object. For more information, see <a href=\"http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.5.1\">http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.5.1</a>.</p>",
- "location":"header",
- "locationName":"Content-Disposition"
- },
- "ContentEncoding":{
- "shape":"ContentEncoding",
+ "location":"header",
+ "locationName":"Content-Disposition"
+ },
+ "ContentEncoding":{
+ "shape":"ContentEncoding",
"documentation":"<p>Specifies what content encodings have been applied to the object and thus what decoding mechanisms must be applied to obtain the media-type referenced by the Content-Type header field. For more information, see <a href=\"http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.11\">http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.11</a>.</p>",
- "location":"header",
- "locationName":"Content-Encoding"
- },
- "ContentLanguage":{
- "shape":"ContentLanguage",
+ "location":"header",
+ "locationName":"Content-Encoding"
+ },
+ "ContentLanguage":{
+ "shape":"ContentLanguage",
"documentation":"<p>The language the content is in.</p>",
- "location":"header",
- "locationName":"Content-Language"
- },
- "ContentLength":{
- "shape":"ContentLength",
+ "location":"header",
+ "locationName":"Content-Language"
+ },
+ "ContentLength":{
+ "shape":"ContentLength",
"documentation":"<p>Size of the body in bytes. This parameter is useful when the size of the body cannot be determined automatically. For more information, see <a href=\"http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.13\">http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.13</a>.</p>",
- "location":"header",
- "locationName":"Content-Length"
- },
- "ContentMD5":{
- "shape":"ContentMD5",
+ "location":"header",
+ "locationName":"Content-Length"
+ },
+ "ContentMD5":{
+ "shape":"ContentMD5",
"documentation":"<p>The base64-encoded 128-bit MD5 digest of the message (without the headers) according to RFC 1864. This header can be used as a message integrity check to verify that the data is the same data that was originally sent. Although it is optional, we recommend using the Content-MD5 mechanism as an end-to-end integrity check. For more information about REST request authentication, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html\">REST Authentication</a>.</p>",
- "location":"header",
- "locationName":"Content-MD5"
- },
- "ContentType":{
- "shape":"ContentType",
+ "location":"header",
+ "locationName":"Content-MD5"
+ },
+ "ContentType":{
+ "shape":"ContentType",
"documentation":"<p>A standard MIME type describing the format of the contents. For more information, see <a href=\"http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17\">http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17</a>.</p>",
- "location":"header",
- "locationName":"Content-Type"
- },
- "Expires":{
- "shape":"Expires",
+ "location":"header",
+ "locationName":"Content-Type"
+ },
+ "Expires":{
+ "shape":"Expires",
"documentation":"<p>The date and time at which the object is no longer cacheable. For more information, see <a href=\"http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.21\">http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.21</a>.</p>",
- "location":"header",
- "locationName":"Expires"
- },
- "GrantFullControl":{
- "shape":"GrantFullControl",
+ "location":"header",
+ "locationName":"Expires"
+ },
+ "GrantFullControl":{
+ "shape":"GrantFullControl",
"documentation":"<p>Gives the grantee READ, READ_ACP, and WRITE_ACP permissions on the object.</p> <p>This action is not supported by Amazon S3 on Outposts.</p>",
- "location":"header",
- "locationName":"x-amz-grant-full-control"
- },
- "GrantRead":{
- "shape":"GrantRead",
+ "location":"header",
+ "locationName":"x-amz-grant-full-control"
+ },
+ "GrantRead":{
+ "shape":"GrantRead",
"documentation":"<p>Allows grantee to read the object data and its metadata.</p> <p>This action is not supported by Amazon S3 on Outposts.</p>",
- "location":"header",
- "locationName":"x-amz-grant-read"
- },
- "GrantReadACP":{
- "shape":"GrantReadACP",
+ "location":"header",
+ "locationName":"x-amz-grant-read"
+ },
+ "GrantReadACP":{
+ "shape":"GrantReadACP",
"documentation":"<p>Allows grantee to read the object ACL.</p> <p>This action is not supported by Amazon S3 on Outposts.</p>",
- "location":"header",
- "locationName":"x-amz-grant-read-acp"
- },
- "GrantWriteACP":{
- "shape":"GrantWriteACP",
+ "location":"header",
+ "locationName":"x-amz-grant-read-acp"
+ },
+ "GrantWriteACP":{
+ "shape":"GrantWriteACP",
"documentation":"<p>Allows grantee to write the ACL for the applicable object.</p> <p>This action is not supported by Amazon S3 on Outposts.</p>",
- "location":"header",
- "locationName":"x-amz-grant-write-acp"
- },
- "Key":{
- "shape":"ObjectKey",
+ "location":"header",
+ "locationName":"x-amz-grant-write-acp"
+ },
+ "Key":{
+ "shape":"ObjectKey",
"documentation":"<p>Object key for which the PUT action was initiated.</p>",
- "location":"uri",
- "locationName":"Key"
- },
- "Metadata":{
- "shape":"Metadata",
+ "location":"uri",
+ "locationName":"Key"
+ },
+ "Metadata":{
+ "shape":"Metadata",
"documentation":"<p>A map of metadata to store with the object in S3.</p>",
- "location":"headers",
- "locationName":"x-amz-meta-"
- },
- "ServerSideEncryption":{
- "shape":"ServerSideEncryption",
+ "location":"headers",
+ "locationName":"x-amz-meta-"
+ },
+ "ServerSideEncryption":{
+ "shape":"ServerSideEncryption",
"documentation":"<p>The server-side encryption algorithm used when storing this object in Amazon S3 (for example, AES256, aws:kms).</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption"
- },
- "StorageClass":{
- "shape":"StorageClass",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption"
+ },
+ "StorageClass":{
+ "shape":"StorageClass",
"documentation":"<p>By default, Amazon S3 uses the STANDARD Storage Class to store newly created objects. The STANDARD storage class provides high durability and high availability. Depending on performance needs, you can specify a different Storage Class. Amazon S3 on Outposts only uses the OUTPOSTS Storage Class. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/storage-class-intro.html\">Storage Classes</a> in the <i>Amazon S3 User Guide</i>.</p>",
- "location":"header",
- "locationName":"x-amz-storage-class"
- },
- "WebsiteRedirectLocation":{
- "shape":"WebsiteRedirectLocation",
+ "location":"header",
+ "locationName":"x-amz-storage-class"
+ },
+ "WebsiteRedirectLocation":{
+ "shape":"WebsiteRedirectLocation",
"documentation":"<p>If the bucket is configured as a website, redirects requests for this object to another object in the same bucket or to an external URL. Amazon S3 stores the value of this header in the object metadata. For information about object metadata, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html\">Object Key and Metadata</a>.</p> <p>In the following example, the request header sets the redirect to an object (anotherPage.html) in the same bucket:</p> <p> <code>x-amz-website-redirect-location: /anotherPage.html</code> </p> <p>In the following example, the request header sets the object redirect to another website:</p> <p> <code>x-amz-website-redirect-location: http://www.example.com/</code> </p> <p>For more information about website hosting in Amazon S3, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/WebsiteHosting.html\">Hosting Websites on Amazon S3</a> and <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/how-to-page-redirect.html\">How to Configure Website Page Redirects</a>. </p>",
- "location":"header",
- "locationName":"x-amz-website-redirect-location"
- },
- "SSECustomerAlgorithm":{
- "shape":"SSECustomerAlgorithm",
+ "location":"header",
+ "locationName":"x-amz-website-redirect-location"
+ },
+ "SSECustomerAlgorithm":{
+ "shape":"SSECustomerAlgorithm",
"documentation":"<p>Specifies the algorithm to use to when encrypting the object (for example, AES256).</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-customer-algorithm"
- },
- "SSECustomerKey":{
- "shape":"SSECustomerKey",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-customer-algorithm"
+ },
+ "SSECustomerKey":{
+ "shape":"SSECustomerKey",
"documentation":"<p>Specifies the customer-provided encryption key for Amazon S3 to use in encrypting data. This value is used to store the object and then it is discarded; Amazon S3 does not store the encryption key. The key must be appropriate for use with the algorithm specified in the <code>x-amz-server-side-encryption-customer-algorithm</code> header.</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-customer-key"
- },
- "SSECustomerKeyMD5":{
- "shape":"SSECustomerKeyMD5",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-customer-key"
+ },
+ "SSECustomerKeyMD5":{
+ "shape":"SSECustomerKeyMD5",
"documentation":"<p>Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. Amazon S3 uses this header for a message integrity check to ensure that the encryption key was transmitted without error.</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-customer-key-MD5"
- },
- "SSEKMSKeyId":{
- "shape":"SSEKMSKeyId",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-customer-key-MD5"
+ },
+ "SSEKMSKeyId":{
+ "shape":"SSEKMSKeyId",
"documentation":"<p>If <code>x-amz-server-side-encryption</code> is present and has the value of <code>aws:kms</code>, this header specifies the ID of the AWS Key Management Service (AWS KMS) symmetrical customer managed customer master key (CMK) that was used for the object. If you specify <code>x-amz-server-side-encryption:aws:kms</code>, but do not provide<code> x-amz-server-side-encryption-aws-kms-key-id</code>, Amazon S3 uses the AWS managed CMK in AWS to protect the data. If the KMS key does not exist in the same account issuing the command, you must use the full ARN and not just the ID. </p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-aws-kms-key-id"
- },
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-aws-kms-key-id"
+ },
"SSEKMSEncryptionContext":{
"shape":"SSEKMSEncryptionContext",
"documentation":"<p>Specifies the AWS KMS Encryption Context to use for object encryption. The value of this header is a base64-encoded UTF-8 string holding JSON with the encryption context key-value pairs.</p>",
@@ -8081,16 +8081,16 @@
"location":"header",
"locationName":"x-amz-server-side-encryption-bucket-key-enabled"
},
- "RequestPayer":{
- "shape":"RequestPayer",
- "location":"header",
- "locationName":"x-amz-request-payer"
- },
- "Tagging":{
- "shape":"TaggingHeader",
+ "RequestPayer":{
+ "shape":"RequestPayer",
+ "location":"header",
+ "locationName":"x-amz-request-payer"
+ },
+ "Tagging":{
+ "shape":"TaggingHeader",
"documentation":"<p>The tag-set for the object. The tag-set must be encoded as URL Query parameters. (For example, \"Key1=Value1\")</p>",
- "location":"header",
- "locationName":"x-amz-tagging"
+ "location":"header",
+ "locationName":"x-amz-tagging"
},
"ObjectLockMode":{
"shape":"ObjectLockMode",
@@ -8115,10 +8115,10 @@
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- },
- "payload":"Body"
- },
+ }
+ },
+ "payload":"Body"
+ },
"PutObjectRetentionOutput":{
"type":"structure",
"members":{
@@ -8186,54 +8186,54 @@
},
"payload":"Retention"
},
- "PutObjectTaggingOutput":{
- "type":"structure",
- "members":{
- "VersionId":{
- "shape":"ObjectVersionId",
+ "PutObjectTaggingOutput":{
+ "type":"structure",
+ "members":{
+ "VersionId":{
+ "shape":"ObjectVersionId",
"documentation":"<p>The versionId of the object the tag-set was added to.</p>",
- "location":"header",
- "locationName":"x-amz-version-id"
- }
- }
- },
- "PutObjectTaggingRequest":{
- "type":"structure",
- "required":[
- "Bucket",
- "Key",
- "Tagging"
- ],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ "location":"header",
+ "locationName":"x-amz-version-id"
+ }
+ }
+ },
+ "PutObjectTaggingRequest":{
+ "type":"structure",
+ "required":[
+ "Bucket",
+ "Key",
+ "Tagging"
+ ],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The bucket name containing the object. </p> <p>When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.s3-accesspoint.<i>Region</i>.amazonaws.com. When using this action with an access point through the AWS SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\">Using access points</a> in the <i>Amazon S3 User Guide</i>.</p> <p>When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.<i>outpostID</i>.s3-outposts.<i>Region</i>.amazonaws.com. When using this action using S3 on Outposts through the AWS SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html\">Using S3 on Outposts</a> in the <i>Amazon S3 User Guide</i>.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "Key":{
- "shape":"ObjectKey",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "Key":{
+ "shape":"ObjectKey",
"documentation":"<p>Name of the object key.</p>",
- "location":"uri",
- "locationName":"Key"
- },
- "VersionId":{
- "shape":"ObjectVersionId",
+ "location":"uri",
+ "locationName":"Key"
+ },
+ "VersionId":{
+ "shape":"ObjectVersionId",
"documentation":"<p>The versionId of the object that the tag-set will be added to.</p>",
- "location":"querystring",
- "locationName":"versionId"
- },
- "ContentMD5":{
- "shape":"ContentMD5",
+ "location":"querystring",
+ "locationName":"versionId"
+ },
+ "ContentMD5":{
+ "shape":"ContentMD5",
"documentation":"<p>The MD5 hash for the request body.</p> <p>For requests made using the AWS Command Line Interface (CLI) or AWS SDKs, this field is calculated automatically.</p>",
- "location":"header",
- "locationName":"Content-MD5"
- },
- "Tagging":{
- "shape":"Tagging",
+ "location":"header",
+ "locationName":"Content-MD5"
+ },
+ "Tagging":{
+ "shape":"Tagging",
"documentation":"<p>Container for the <code>TagSet</code> and <code>Tag</code> elements</p>",
- "locationName":"Tagging",
- "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
+ "locationName":"Tagging",
+ "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
},
"ExpectedBucketOwner":{
"shape":"AccountId",
@@ -8245,10 +8245,10 @@
"shape":"RequestPayer",
"location":"header",
"locationName":"x-amz-request-payer"
- }
- },
- "payload":"Tagging"
- },
+ }
+ },
+ "payload":"Tagging"
+ },
"PutPublicAccessBlockRequest":{
"type":"structure",
"required":[
@@ -8283,122 +8283,122 @@
},
"payload":"PublicAccessBlockConfiguration"
},
- "QueueArn":{"type":"string"},
- "QueueConfiguration":{
- "type":"structure",
- "required":[
- "QueueArn",
- "Events"
- ],
- "members":{
- "Id":{"shape":"NotificationId"},
- "QueueArn":{
- "shape":"QueueArn",
+ "QueueArn":{"type":"string"},
+ "QueueConfiguration":{
+ "type":"structure",
+ "required":[
+ "QueueArn",
+ "Events"
+ ],
+ "members":{
+ "Id":{"shape":"NotificationId"},
+ "QueueArn":{
+ "shape":"QueueArn",
"documentation":"<p>The Amazon Resource Name (ARN) of the Amazon SQS queue to which Amazon S3 publishes a message when it detects events of the specified type.</p>",
- "locationName":"Queue"
- },
- "Events":{
- "shape":"EventList",
+ "locationName":"Queue"
+ },
+ "Events":{
+ "shape":"EventList",
"documentation":"<p>A collection of bucket events for which to send notifications</p>",
- "locationName":"Event"
- },
+ "locationName":"Event"
+ },
"Filter":{"shape":"NotificationConfigurationFilter"}
- },
+ },
"documentation":"<p>Specifies the configuration for publishing messages to an Amazon Simple Queue Service (Amazon SQS) queue when Amazon S3 detects specified events.</p>"
- },
- "QueueConfigurationDeprecated":{
- "type":"structure",
- "members":{
- "Id":{"shape":"NotificationId"},
- "Event":{
- "shape":"Event",
- "deprecated":true
- },
- "Events":{
- "shape":"EventList",
+ },
+ "QueueConfigurationDeprecated":{
+ "type":"structure",
+ "members":{
+ "Id":{"shape":"NotificationId"},
+ "Event":{
+ "shape":"Event",
+ "deprecated":true
+ },
+ "Events":{
+ "shape":"EventList",
"documentation":"<p>A collection of bucket events for which to send notifications.</p>",
- "locationName":"Event"
- },
+ "locationName":"Event"
+ },
"Queue":{
"shape":"QueueArn",
"documentation":"<p>The Amazon Resource Name (ARN) of the Amazon SQS queue to which Amazon S3 publishes a message when it detects events of the specified type. </p>"
}
},
"documentation":"<p>This data type is deprecated. Use <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_QueueConfiguration.html\">QueueConfiguration</a> for the same purposes. This data type specifies the configuration for publishing messages to an Amazon Simple Queue Service (Amazon SQS) queue when Amazon S3 detects specified events. </p>"
- },
- "QueueConfigurationList":{
- "type":"list",
- "member":{"shape":"QueueConfiguration"},
- "flattened":true
- },
- "Quiet":{"type":"boolean"},
- "QuoteCharacter":{"type":"string"},
- "QuoteEscapeCharacter":{"type":"string"},
- "QuoteFields":{
- "type":"string",
- "enum":[
- "ALWAYS",
- "ASNEEDED"
- ]
- },
- "Range":{"type":"string"},
- "RecordDelimiter":{"type":"string"},
- "RecordsEvent":{
- "type":"structure",
- "members":{
- "Payload":{
- "shape":"Body",
+ },
+ "QueueConfigurationList":{
+ "type":"list",
+ "member":{"shape":"QueueConfiguration"},
+ "flattened":true
+ },
+ "Quiet":{"type":"boolean"},
+ "QuoteCharacter":{"type":"string"},
+ "QuoteEscapeCharacter":{"type":"string"},
+ "QuoteFields":{
+ "type":"string",
+ "enum":[
+ "ALWAYS",
+ "ASNEEDED"
+ ]
+ },
+ "Range":{"type":"string"},
+ "RecordDelimiter":{"type":"string"},
+ "RecordsEvent":{
+ "type":"structure",
+ "members":{
+ "Payload":{
+ "shape":"Body",
"documentation":"<p>The byte array of partial, one or more result records.</p>",
- "eventpayload":true
- }
- },
+ "eventpayload":true
+ }
+ },
"documentation":"<p>The container for the records event.</p>",
- "event":true
- },
- "Redirect":{
- "type":"structure",
- "members":{
- "HostName":{
- "shape":"HostName",
+ "event":true
+ },
+ "Redirect":{
+ "type":"structure",
+ "members":{
+ "HostName":{
+ "shape":"HostName",
"documentation":"<p>The host name to use in the redirect request.</p>"
- },
- "HttpRedirectCode":{
- "shape":"HttpRedirectCode",
+ },
+ "HttpRedirectCode":{
+ "shape":"HttpRedirectCode",
"documentation":"<p>The HTTP redirect code to use on the response. Not required if one of the siblings is present.</p>"
- },
- "Protocol":{
- "shape":"Protocol",
+ },
+ "Protocol":{
+ "shape":"Protocol",
"documentation":"<p>Protocol to use when redirecting requests. The default is the protocol that is used in the original request.</p>"
- },
- "ReplaceKeyPrefixWith":{
- "shape":"ReplaceKeyPrefixWith",
+ },
+ "ReplaceKeyPrefixWith":{
+ "shape":"ReplaceKeyPrefixWith",
"documentation":"<p>The object key prefix to use in the redirect request. For example, to redirect requests for all pages with prefix <code>docs/</code> (objects in the <code>docs/</code> folder) to <code>documents/</code>, you can set a condition block with <code>KeyPrefixEquals</code> set to <code>docs/</code> and in the Redirect set <code>ReplaceKeyPrefixWith</code> to <code>/documents</code>. Not required if one of the siblings is present. Can be present only if <code>ReplaceKeyWith</code> is not provided.</p> <important> <p>Replacement must be made for object keys containing special characters (such as carriage returns) when using XML requests. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-keys.html#object-key-xml-related-constraints\"> XML related object key constraints</a>.</p> </important>"
- },
- "ReplaceKeyWith":{
- "shape":"ReplaceKeyWith",
+ },
+ "ReplaceKeyWith":{
+ "shape":"ReplaceKeyWith",
"documentation":"<p>The specific object key to use in the redirect request. For example, redirect request to <code>error.html</code>. Not required if one of the siblings is present. Can be present only if <code>ReplaceKeyPrefixWith</code> is not provided.</p> <important> <p>Replacement must be made for object keys containing special characters (such as carriage returns) when using XML requests. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-keys.html#object-key-xml-related-constraints\"> XML related object key constraints</a>.</p> </important>"
- }
+ }
},
"documentation":"<p>Specifies how requests are redirected. In the event of an error, you can specify a different error code to return.</p>"
- },
- "RedirectAllRequestsTo":{
- "type":"structure",
- "required":["HostName"],
- "members":{
- "HostName":{
- "shape":"HostName",
+ },
+ "RedirectAllRequestsTo":{
+ "type":"structure",
+ "required":["HostName"],
+ "members":{
+ "HostName":{
+ "shape":"HostName",
"documentation":"<p>Name of the host where requests are redirected.</p>"
- },
- "Protocol":{
- "shape":"Protocol",
+ },
+ "Protocol":{
+ "shape":"Protocol",
"documentation":"<p>Protocol to use when redirecting requests. The default is the protocol that is used in the original request.</p>"
- }
+ }
},
"documentation":"<p>Specifies the redirect behavior of all requests to a website endpoint of an Amazon S3 bucket.</p>"
- },
- "ReplaceKeyPrefixWith":{"type":"string"},
- "ReplaceKeyWith":{"type":"string"},
- "ReplicaKmsKeyID":{"type":"string"},
+ },
+ "ReplaceKeyPrefixWith":{"type":"string"},
+ "ReplaceKeyWith":{"type":"string"},
+ "ReplicaKmsKeyID":{"type":"string"},
"ReplicaModifications":{
"type":"structure",
"required":["Status"],
@@ -8417,60 +8417,60 @@
"Disabled"
]
},
- "ReplicationConfiguration":{
- "type":"structure",
- "required":[
- "Role",
- "Rules"
- ],
- "members":{
- "Role":{
- "shape":"Role",
+ "ReplicationConfiguration":{
+ "type":"structure",
+ "required":[
+ "Role",
+ "Rules"
+ ],
+ "members":{
+ "Role":{
+ "shape":"Role",
"documentation":"<p>The Amazon Resource Name (ARN) of the AWS Identity and Access Management (IAM) role that Amazon S3 assumes when replicating objects. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/replication-how-setup.html\">How to Set Up Replication</a> in the <i>Amazon S3 User Guide</i>.</p>"
- },
- "Rules":{
- "shape":"ReplicationRules",
+ },
+ "Rules":{
+ "shape":"ReplicationRules",
"documentation":"<p>A container for one or more replication rules. A replication configuration must have at least one rule and can contain a maximum of 1,000 rules. </p>",
- "locationName":"Rule"
- }
- },
+ "locationName":"Rule"
+ }
+ },
"documentation":"<p>A container for replication rules. You can add up to 1,000 rules. The maximum size of a replication configuration is 2 MB.</p>"
- },
- "ReplicationRule":{
- "type":"structure",
- "required":[
- "Status",
- "Destination"
- ],
- "members":{
- "ID":{
- "shape":"ID",
+ },
+ "ReplicationRule":{
+ "type":"structure",
+ "required":[
+ "Status",
+ "Destination"
+ ],
+ "members":{
+ "ID":{
+ "shape":"ID",
"documentation":"<p>A unique identifier for the rule. The maximum value is 255 characters.</p>"
- },
+ },
"Priority":{
"shape":"Priority",
"documentation":"<p>The priority indicates which rule has precedence whenever two or more replication rules conflict. Amazon S3 will attempt to replicate objects according to all replication rules. However, if there are two or more rules with the same destination bucket, then objects will be replicated according to the rule with the highest priority. The higher the number, the higher the priority. </p> <p>For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/replication.html\">Replication</a> in the <i>Amazon S3 User Guide</i>.</p>"
},
- "Prefix":{
- "shape":"Prefix",
+ "Prefix":{
+ "shape":"Prefix",
"documentation":"<p>An object key name prefix that identifies the object or objects to which the rule applies. The maximum prefix length is 1,024 characters. To include all objects in a bucket, specify an empty string. </p> <important> <p>Replacement must be made for object keys containing special characters (such as carriage returns) when using XML requests. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-keys.html#object-key-xml-related-constraints\"> XML related object key constraints</a>.</p> </important>",
"deprecated":true
- },
+ },
"Filter":{"shape":"ReplicationRuleFilter"},
- "Status":{
- "shape":"ReplicationRuleStatus",
+ "Status":{
+ "shape":"ReplicationRuleStatus",
"documentation":"<p>Specifies whether the rule is enabled.</p>"
- },
- "SourceSelectionCriteria":{
- "shape":"SourceSelectionCriteria",
+ },
+ "SourceSelectionCriteria":{
+ "shape":"SourceSelectionCriteria",
"documentation":"<p>A container that describes additional filters for identifying the source objects that you want to replicate. You can choose to enable or disable the replication of these objects. Currently, Amazon S3 supports only the filter that you can specify for objects created with server-side encryption using a customer master key (CMK) stored in AWS Key Management Service (SSE-KMS).</p>"
- },
+ },
"ExistingObjectReplication":{
"shape":"ExistingObjectReplication",
"documentation":"<p/>"
},
- "Destination":{
- "shape":"Destination",
+ "Destination":{
+ "shape":"Destination",
"documentation":"<p>A container for information about the replication destination and its configurations including enabling the S3 Replication Time Control (S3 RTC).</p>"
},
"DeleteMarkerReplication":{"shape":"DeleteMarkerReplication"}
@@ -8489,10 +8489,10 @@
"documentation":"<p>An array of tags containing key and value pairs.</p>",
"flattened":true,
"locationName":"Tag"
- }
- },
+ }
+ },
"documentation":"<p>A container for specifying rule filters. The filters determine the subset of objects to which the rule applies. This element is required only if you specify more than one filter. </p> <p>For example:</p> <ul> <li> <p>If you specify both a <code>Prefix</code> and a <code>Tag</code> filter, wrap these filters in an <code>And</code> tag. </p> </li> <li> <p>If you specify a filter based on multiple tags, wrap the <code>Tag</code> elements in an <code>And</code> tag.</p> </li> </ul>"
- },
+ },
"ReplicationRuleFilter":{
"type":"structure",
"members":{
@@ -8511,27 +8511,27 @@
},
"documentation":"<p>A filter that identifies the subset of objects to which the replication rule applies. A <code>Filter</code> must specify exactly one <code>Prefix</code>, <code>Tag</code>, or an <code>And</code> child element.</p>"
},
- "ReplicationRuleStatus":{
- "type":"string",
- "enum":[
- "Enabled",
- "Disabled"
- ]
- },
- "ReplicationRules":{
- "type":"list",
- "member":{"shape":"ReplicationRule"},
- "flattened":true
- },
- "ReplicationStatus":{
- "type":"string",
- "enum":[
- "COMPLETE",
- "PENDING",
- "FAILED",
- "REPLICA"
- ]
- },
+ "ReplicationRuleStatus":{
+ "type":"string",
+ "enum":[
+ "Enabled",
+ "Disabled"
+ ]
+ },
+ "ReplicationRules":{
+ "type":"list",
+ "member":{"shape":"ReplicationRule"},
+ "flattened":true
+ },
+ "ReplicationStatus":{
+ "type":"string",
+ "enum":[
+ "COMPLETE",
+ "PENDING",
+ "FAILED",
+ "REPLICA"
+ ]
+ },
"ReplicationTime":{
"type":"structure",
"required":[
@@ -8567,194 +8567,194 @@
},
"documentation":"<p> A container specifying the time value for S3 Replication Time Control (S3 RTC) and replication metrics <code>EventThreshold</code>. </p>"
},
- "RequestCharged":{
- "type":"string",
+ "RequestCharged":{
+ "type":"string",
"documentation":"<p>If present, indicates that the requester was successfully charged for the request.</p>",
- "enum":["requester"]
- },
- "RequestPayer":{
- "type":"string",
+ "enum":["requester"]
+ },
+ "RequestPayer":{
+ "type":"string",
"documentation":"<p>Confirms that the requester knows that they will be charged for the request. Bucket owners need not specify this parameter in their requests. For information about downloading objects from requester pays buckets, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectsinRequesterPaysBuckets.html\">Downloading Objects in Requestor Pays Buckets</a> in the <i>Amazon S3 User Guide</i>.</p>",
- "enum":["requester"]
- },
- "RequestPaymentConfiguration":{
- "type":"structure",
- "required":["Payer"],
- "members":{
- "Payer":{
- "shape":"Payer",
+ "enum":["requester"]
+ },
+ "RequestPaymentConfiguration":{
+ "type":"structure",
+ "required":["Payer"],
+ "members":{
+ "Payer":{
+ "shape":"Payer",
"documentation":"<p>Specifies who pays for the download and request fees.</p>"
- }
+ }
},
"documentation":"<p>Container for Payer.</p>"
- },
- "RequestProgress":{
- "type":"structure",
- "members":{
- "Enabled":{
- "shape":"EnableRequestProgress",
+ },
+ "RequestProgress":{
+ "type":"structure",
+ "members":{
+ "Enabled":{
+ "shape":"EnableRequestProgress",
"documentation":"<p>Specifies whether periodic QueryProgress frames should be sent. Valid values: TRUE, FALSE. Default value: FALSE.</p>"
- }
+ }
},
"documentation":"<p>Container for specifying if periodic <code>QueryProgress</code> messages should be sent.</p>"
- },
+ },
"RequestRoute":{"type":"string"},
"RequestToken":{"type":"string"},
- "ResponseCacheControl":{"type":"string"},
- "ResponseContentDisposition":{"type":"string"},
- "ResponseContentEncoding":{"type":"string"},
- "ResponseContentLanguage":{"type":"string"},
- "ResponseContentType":{"type":"string"},
+ "ResponseCacheControl":{"type":"string"},
+ "ResponseContentDisposition":{"type":"string"},
+ "ResponseContentEncoding":{"type":"string"},
+ "ResponseContentLanguage":{"type":"string"},
+ "ResponseContentType":{"type":"string"},
"ResponseExpires":{
"type":"timestamp",
"timestampFormat":"rfc822"
},
- "Restore":{"type":"string"},
- "RestoreObjectOutput":{
- "type":"structure",
- "members":{
- "RequestCharged":{
- "shape":"RequestCharged",
- "location":"header",
- "locationName":"x-amz-request-charged"
- },
- "RestoreOutputPath":{
- "shape":"RestoreOutputPath",
+ "Restore":{"type":"string"},
+ "RestoreObjectOutput":{
+ "type":"structure",
+ "members":{
+ "RequestCharged":{
+ "shape":"RequestCharged",
+ "location":"header",
+ "locationName":"x-amz-request-charged"
+ },
+ "RestoreOutputPath":{
+ "shape":"RestoreOutputPath",
"documentation":"<p>Indicates the path in the provided S3 output location where Select results will be restored to.</p>",
- "location":"header",
- "locationName":"x-amz-restore-output-path"
- }
- }
- },
- "RestoreObjectRequest":{
- "type":"structure",
- "required":[
- "Bucket",
- "Key"
- ],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ "location":"header",
+ "locationName":"x-amz-restore-output-path"
+ }
+ }
+ },
+ "RestoreObjectRequest":{
+ "type":"structure",
+ "required":[
+ "Bucket",
+ "Key"
+ ],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The bucket name containing the object to restore. </p> <p>When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.s3-accesspoint.<i>Region</i>.amazonaws.com. When using this action with an access point through the AWS SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\">Using access points</a> in the <i>Amazon S3 User Guide</i>.</p> <p>When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.<i>outpostID</i>.s3-outposts.<i>Region</i>.amazonaws.com. When using this action using S3 on Outposts through the AWS SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html\">Using S3 on Outposts</a> in the <i>Amazon S3 User Guide</i>.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "Key":{
- "shape":"ObjectKey",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "Key":{
+ "shape":"ObjectKey",
"documentation":"<p>Object key for which the action was initiated.</p>",
- "location":"uri",
- "locationName":"Key"
- },
- "VersionId":{
- "shape":"ObjectVersionId",
+ "location":"uri",
+ "locationName":"Key"
+ },
+ "VersionId":{
+ "shape":"ObjectVersionId",
"documentation":"<p>VersionId used to reference a specific version of the object.</p>",
- "location":"querystring",
- "locationName":"versionId"
- },
- "RestoreRequest":{
- "shape":"RestoreRequest",
- "locationName":"RestoreRequest",
- "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
- },
- "RequestPayer":{
- "shape":"RequestPayer",
- "location":"header",
- "locationName":"x-amz-request-payer"
+ "location":"querystring",
+ "locationName":"versionId"
+ },
+ "RestoreRequest":{
+ "shape":"RestoreRequest",
+ "locationName":"RestoreRequest",
+ "xmlNamespace":{"uri":"http://s3.amazonaws.com/doc/2006-03-01/"}
+ },
+ "RequestPayer":{
+ "shape":"RequestPayer",
+ "location":"header",
+ "locationName":"x-amz-request-payer"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- },
- "payload":"RestoreRequest"
- },
- "RestoreOutputPath":{"type":"string"},
- "RestoreRequest":{
- "type":"structure",
- "members":{
- "Days":{
- "shape":"Days",
+ }
+ },
+ "payload":"RestoreRequest"
+ },
+ "RestoreOutputPath":{"type":"string"},
+ "RestoreRequest":{
+ "type":"structure",
+ "members":{
+ "Days":{
+ "shape":"Days",
"documentation":"<p>Lifetime of the active copy in days. Do not use with restores that specify <code>OutputLocation</code>.</p> <p>The Days element is required for regular restores, and must not be provided for select requests.</p>"
- },
- "GlacierJobParameters":{
- "shape":"GlacierJobParameters",
+ },
+ "GlacierJobParameters":{
+ "shape":"GlacierJobParameters",
"documentation":"<p>S3 Glacier related parameters pertaining to this job. Do not use with restores that specify <code>OutputLocation</code>.</p>"
- },
- "Type":{
- "shape":"RestoreRequestType",
+ },
+ "Type":{
+ "shape":"RestoreRequestType",
"documentation":"<p>Type of restore request.</p>"
- },
- "Tier":{
- "shape":"Tier",
+ },
+ "Tier":{
+ "shape":"Tier",
"documentation":"<p>Retrieval tier at which the restore will be processed.</p>"
- },
- "Description":{
- "shape":"Description",
+ },
+ "Description":{
+ "shape":"Description",
"documentation":"<p>The optional description for the job.</p>"
- },
- "SelectParameters":{
- "shape":"SelectParameters",
+ },
+ "SelectParameters":{
+ "shape":"SelectParameters",
"documentation":"<p>Describes the parameters for Select job types.</p>"
- },
- "OutputLocation":{
- "shape":"OutputLocation",
+ },
+ "OutputLocation":{
+ "shape":"OutputLocation",
"documentation":"<p>Describes the location where the restore job's output is stored.</p>"
- }
- },
+ }
+ },
"documentation":"<p>Container for restore job parameters.</p>"
- },
- "RestoreRequestType":{
- "type":"string",
- "enum":["SELECT"]
- },
- "Role":{"type":"string"},
- "RoutingRule":{
- "type":"structure",
- "required":["Redirect"],
- "members":{
- "Condition":{
- "shape":"Condition",
+ },
+ "RestoreRequestType":{
+ "type":"string",
+ "enum":["SELECT"]
+ },
+ "Role":{"type":"string"},
+ "RoutingRule":{
+ "type":"structure",
+ "required":["Redirect"],
+ "members":{
+ "Condition":{
+ "shape":"Condition",
"documentation":"<p>A container for describing a condition that must be met for the specified redirect to apply. For example, 1. If request is for pages in the <code>/docs</code> folder, redirect to the <code>/documents</code> folder. 2. If request results in HTTP error 4xx, redirect request to another host where you might process the error.</p>"
- },
- "Redirect":{
- "shape":"Redirect",
+ },
+ "Redirect":{
+ "shape":"Redirect",
"documentation":"<p>Container for redirect information. You can redirect requests to another host, to another page, or with another protocol. In the event of an error, you can specify a different error code to return.</p>"
- }
+ }
},
"documentation":"<p>Specifies the redirect behavior and when a redirect is applied. For more information about routing rules, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/how-to-page-redirect.html#advanced-conditional-redirects\">Configuring advanced conditional redirects</a> in the <i>Amazon S3 User Guide</i>.</p>"
- },
- "RoutingRules":{
- "type":"list",
- "member":{
- "shape":"RoutingRule",
- "locationName":"RoutingRule"
- }
- },
- "Rule":{
- "type":"structure",
- "required":[
- "Prefix",
- "Status"
- ],
- "members":{
+ },
+ "RoutingRules":{
+ "type":"list",
+ "member":{
+ "shape":"RoutingRule",
+ "locationName":"RoutingRule"
+ }
+ },
+ "Rule":{
+ "type":"structure",
+ "required":[
+ "Prefix",
+ "Status"
+ ],
+ "members":{
"Expiration":{
"shape":"LifecycleExpiration",
"documentation":"<p>Specifies the expiration for the lifecycle of the object.</p>"
},
- "ID":{
- "shape":"ID",
+ "ID":{
+ "shape":"ID",
"documentation":"<p>Unique identifier for the rule. The value can't be longer than 255 characters.</p>"
- },
- "Prefix":{
- "shape":"Prefix",
+ },
+ "Prefix":{
+ "shape":"Prefix",
"documentation":"<p>Object key prefix that identifies one or more objects to which this rule applies.</p> <important> <p>Replacement must be made for object keys containing special characters (such as carriage returns) when using XML requests. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-keys.html#object-key-xml-related-constraints\"> XML related object key constraints</a>.</p> </important>"
- },
- "Status":{
- "shape":"ExpirationStatus",
+ },
+ "Status":{
+ "shape":"ExpirationStatus",
"documentation":"<p>If <code>Enabled</code>, the rule is currently being applied. If <code>Disabled</code>, the rule is not currently being applied.</p>"
- },
+ },
"Transition":{
"shape":"Transition",
"documentation":"<p>Specifies when an object transitions to a specified storage class. For more information about Amazon S3 lifecycle configuration rules, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/lifecycle-transition-general-considerations.html\">Transitioning Objects Using Amazon S3 Lifecycle</a> in the <i>Amazon S3 User Guide</i>.</p>"
@@ -8764,94 +8764,94 @@
"AbortIncompleteMultipartUpload":{"shape":"AbortIncompleteMultipartUpload"}
},
"documentation":"<p>Specifies lifecycle rules for an Amazon S3 bucket. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketPUTlifecycle.html\">Put Bucket Lifecycle Configuration</a> in the <i>Amazon S3 API Reference</i>. For examples, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketLifecycleConfiguration.html#API_PutBucketLifecycleConfiguration_Examples\">Put Bucket Lifecycle Configuration Examples</a>.</p>"
- },
- "Rules":{
- "type":"list",
- "member":{"shape":"Rule"},
- "flattened":true
- },
- "S3KeyFilter":{
- "type":"structure",
- "members":{
- "FilterRules":{
- "shape":"FilterRuleList",
- "locationName":"FilterRule"
- }
- },
+ },
+ "Rules":{
+ "type":"list",
+ "member":{"shape":"Rule"},
+ "flattened":true
+ },
+ "S3KeyFilter":{
+ "type":"structure",
+ "members":{
+ "FilterRules":{
+ "shape":"FilterRuleList",
+ "locationName":"FilterRule"
+ }
+ },
"documentation":"<p>A container for object key name prefix and suffix filtering rules.</p>"
- },
- "S3Location":{
- "type":"structure",
- "required":[
- "BucketName",
- "Prefix"
- ],
- "members":{
- "BucketName":{
- "shape":"BucketName",
+ },
+ "S3Location":{
+ "type":"structure",
+ "required":[
+ "BucketName",
+ "Prefix"
+ ],
+ "members":{
+ "BucketName":{
+ "shape":"BucketName",
"documentation":"<p>The name of the bucket where the restore results will be placed.</p>"
- },
- "Prefix":{
- "shape":"LocationPrefix",
+ },
+ "Prefix":{
+ "shape":"LocationPrefix",
"documentation":"<p>The prefix that is prepended to the restore results for this request.</p>"
- },
+ },
"Encryption":{"shape":"Encryption"},
- "CannedACL":{
- "shape":"ObjectCannedACL",
+ "CannedACL":{
+ "shape":"ObjectCannedACL",
"documentation":"<p>The canned ACL to apply to the restore results.</p>"
- },
- "AccessControlList":{
- "shape":"Grants",
+ },
+ "AccessControlList":{
+ "shape":"Grants",
"documentation":"<p>A list of grants that control access to the staged results.</p>"
- },
- "Tagging":{
- "shape":"Tagging",
+ },
+ "Tagging":{
+ "shape":"Tagging",
"documentation":"<p>The tag-set that is applied to the restore results.</p>"
- },
- "UserMetadata":{
- "shape":"UserMetadata",
+ },
+ "UserMetadata":{
+ "shape":"UserMetadata",
"documentation":"<p>A list of metadata to store with the restore results in S3.</p>"
- },
- "StorageClass":{
- "shape":"StorageClass",
+ },
+ "StorageClass":{
+ "shape":"StorageClass",
"documentation":"<p>The class of storage used to store the restore results.</p>"
- }
- },
+ }
+ },
"documentation":"<p>Describes an Amazon S3 location that will receive the results of the restore request.</p>"
- },
- "SSECustomerAlgorithm":{"type":"string"},
- "SSECustomerKey":{
- "type":"string",
- "sensitive":true
- },
- "SSECustomerKeyMD5":{"type":"string"},
- "SSEKMS":{
- "type":"structure",
- "required":["KeyId"],
- "members":{
- "KeyId":{
- "shape":"SSEKMSKeyId",
+ },
+ "SSECustomerAlgorithm":{"type":"string"},
+ "SSECustomerKey":{
+ "type":"string",
+ "sensitive":true
+ },
+ "SSECustomerKeyMD5":{"type":"string"},
+ "SSEKMS":{
+ "type":"structure",
+ "required":["KeyId"],
+ "members":{
+ "KeyId":{
+ "shape":"SSEKMSKeyId",
"documentation":"<p>Specifies the ID of the AWS Key Management Service (AWS KMS) symmetric customer managed customer master key (CMK) to use for encrypting inventory reports.</p>"
- }
- },
+ }
+ },
"documentation":"<p>Specifies the use of SSE-KMS to encrypt delivered inventory reports.</p>",
- "locationName":"SSE-KMS"
- },
+ "locationName":"SSE-KMS"
+ },
"SSEKMSEncryptionContext":{
"type":"string",
"sensitive":true
},
- "SSEKMSKeyId":{
- "type":"string",
- "sensitive":true
- },
- "SSES3":{
- "type":"structure",
- "members":{
- },
+ "SSEKMSKeyId":{
+ "type":"string",
+ "sensitive":true
+ },
+ "SSES3":{
+ "type":"structure",
+ "members":{
+ },
"documentation":"<p>Specifies the use of SSE-S3 to encrypt delivered inventory reports.</p>",
- "locationName":"SSE-S3"
- },
+ "locationName":"SSE-S3"
+ },
"ScanRange":{
"type":"structure",
"members":{
@@ -8866,102 +8866,102 @@
},
"documentation":"<p>Specifies the byte range of the object to get the records from. A record is processed when its first byte is contained by the range. This parameter is optional, but when specified, it must not be empty. See RFC 2616, Section 14.35.1 about how to specify the start and end of the range.</p>"
},
- "SelectObjectContentEventStream":{
- "type":"structure",
- "members":{
- "Records":{
- "shape":"RecordsEvent",
+ "SelectObjectContentEventStream":{
+ "type":"structure",
+ "members":{
+ "Records":{
+ "shape":"RecordsEvent",
"documentation":"<p>The Records Event.</p>"
- },
- "Stats":{
- "shape":"StatsEvent",
+ },
+ "Stats":{
+ "shape":"StatsEvent",
"documentation":"<p>The Stats Event.</p>"
- },
- "Progress":{
- "shape":"ProgressEvent",
+ },
+ "Progress":{
+ "shape":"ProgressEvent",
"documentation":"<p>The Progress Event.</p>"
- },
- "Cont":{
- "shape":"ContinuationEvent",
+ },
+ "Cont":{
+ "shape":"ContinuationEvent",
"documentation":"<p>The Continuation Event.</p>"
- },
- "End":{
- "shape":"EndEvent",
+ },
+ "End":{
+ "shape":"EndEvent",
"documentation":"<p>The End Event.</p>"
- }
- },
+ }
+ },
"documentation":"<p>The container for selecting objects from a content event stream.</p>",
- "eventstream":true
- },
- "SelectObjectContentOutput":{
- "type":"structure",
- "members":{
+ "eventstream":true
+ },
+ "SelectObjectContentOutput":{
+ "type":"structure",
+ "members":{
"Payload":{
"shape":"SelectObjectContentEventStream",
"documentation":"<p>The array of results.</p>"
}
- },
- "payload":"Payload"
- },
- "SelectObjectContentRequest":{
- "type":"structure",
- "required":[
- "Bucket",
- "Key",
- "Expression",
- "ExpressionType",
- "InputSerialization",
- "OutputSerialization"
- ],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ },
+ "payload":"Payload"
+ },
+ "SelectObjectContentRequest":{
+ "type":"structure",
+ "required":[
+ "Bucket",
+ "Key",
+ "Expression",
+ "ExpressionType",
+ "InputSerialization",
+ "OutputSerialization"
+ ],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The S3 bucket.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "Key":{
- "shape":"ObjectKey",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "Key":{
+ "shape":"ObjectKey",
"documentation":"<p>The object key.</p>",
- "location":"uri",
- "locationName":"Key"
- },
- "SSECustomerAlgorithm":{
- "shape":"SSECustomerAlgorithm",
+ "location":"uri",
+ "locationName":"Key"
+ },
+ "SSECustomerAlgorithm":{
+ "shape":"SSECustomerAlgorithm",
"documentation":"<p>The SSE Algorithm used to encrypt the object. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html\">Server-Side Encryption (Using Customer-Provided Encryption Keys</a>. </p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-customer-algorithm"
- },
- "SSECustomerKey":{
- "shape":"SSECustomerKey",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-customer-algorithm"
+ },
+ "SSECustomerKey":{
+ "shape":"SSECustomerKey",
"documentation":"<p>The SSE Customer Key. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html\">Server-Side Encryption (Using Customer-Provided Encryption Keys</a>. </p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-customer-key"
- },
- "SSECustomerKeyMD5":{
- "shape":"SSECustomerKeyMD5",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-customer-key"
+ },
+ "SSECustomerKeyMD5":{
+ "shape":"SSECustomerKeyMD5",
"documentation":"<p>The SSE Customer Key MD5. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html\">Server-Side Encryption (Using Customer-Provided Encryption Keys</a>. </p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-customer-key-MD5"
- },
- "Expression":{
- "shape":"Expression",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-customer-key-MD5"
+ },
+ "Expression":{
+ "shape":"Expression",
"documentation":"<p>The expression that is used to query the object.</p>"
- },
- "ExpressionType":{
- "shape":"ExpressionType",
+ },
+ "ExpressionType":{
+ "shape":"ExpressionType",
"documentation":"<p>The type of the provided expression (for example, SQL).</p>"
- },
- "RequestProgress":{
- "shape":"RequestProgress",
+ },
+ "RequestProgress":{
+ "shape":"RequestProgress",
"documentation":"<p>Specifies if periodic request progress information should be enabled.</p>"
- },
- "InputSerialization":{
- "shape":"InputSerialization",
+ },
+ "InputSerialization":{
+ "shape":"InputSerialization",
"documentation":"<p>Describes the format of the data in the object that is being queried.</p>"
- },
- "OutputSerialization":{
- "shape":"OutputSerialization",
+ },
+ "OutputSerialization":{
+ "shape":"OutputSerialization",
"documentation":"<p>Describes the format of the data that you want Amazon S3 to return in response.</p>"
},
"ScanRange":{
@@ -8973,279 +8973,279 @@
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- },
+ }
+ },
"documentation":"<p>Request to filter the contents of an Amazon S3 object based on a simple Structured Query Language (SQL) statement. In the request, along with the SQL expression, you must specify a data serialization format (JSON or CSV) of the object. Amazon S3 uses this to parse object data into records. It returns only records that match the specified SQL expression. You must also specify the data serialization format for the response. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectSELECTContent.html\">S3Select API Documentation</a>.</p>"
- },
- "SelectParameters":{
- "type":"structure",
- "required":[
- "InputSerialization",
- "ExpressionType",
- "Expression",
- "OutputSerialization"
- ],
- "members":{
- "InputSerialization":{
- "shape":"InputSerialization",
+ },
+ "SelectParameters":{
+ "type":"structure",
+ "required":[
+ "InputSerialization",
+ "ExpressionType",
+ "Expression",
+ "OutputSerialization"
+ ],
+ "members":{
+ "InputSerialization":{
+ "shape":"InputSerialization",
"documentation":"<p>Describes the serialization format of the object.</p>"
- },
- "ExpressionType":{
- "shape":"ExpressionType",
+ },
+ "ExpressionType":{
+ "shape":"ExpressionType",
"documentation":"<p>The type of the provided expression (for example, SQL).</p>"
- },
- "Expression":{
- "shape":"Expression",
+ },
+ "Expression":{
+ "shape":"Expression",
"documentation":"<p>The expression that is used to query the object.</p>"
- },
- "OutputSerialization":{
- "shape":"OutputSerialization",
+ },
+ "OutputSerialization":{
+ "shape":"OutputSerialization",
"documentation":"<p>Describes how the results of the Select job are serialized.</p>"
- }
- },
+ }
+ },
"documentation":"<p>Describes the parameters for Select job types.</p>"
- },
- "ServerSideEncryption":{
- "type":"string",
- "enum":[
- "AES256",
- "aws:kms"
- ]
- },
- "ServerSideEncryptionByDefault":{
- "type":"structure",
- "required":["SSEAlgorithm"],
- "members":{
- "SSEAlgorithm":{
- "shape":"ServerSideEncryption",
+ },
+ "ServerSideEncryption":{
+ "type":"string",
+ "enum":[
+ "AES256",
+ "aws:kms"
+ ]
+ },
+ "ServerSideEncryptionByDefault":{
+ "type":"structure",
+ "required":["SSEAlgorithm"],
+ "members":{
+ "SSEAlgorithm":{
+ "shape":"ServerSideEncryption",
"documentation":"<p>Server-side encryption algorithm to use for the default encryption.</p>"
- },
- "KMSMasterKeyID":{
- "shape":"SSEKMSKeyId",
+ },
+ "KMSMasterKeyID":{
+ "shape":"SSEKMSKeyId",
"documentation":"<p>AWS Key Management Service (KMS) customer AWS KMS key ID to use for the default encryption. This parameter is allowed if and only if <code>SSEAlgorithm</code> is set to <code>aws:kms</code>.</p> <p>You can specify the key ID or the Amazon Resource Name (ARN) of the KMS key. However, if you are using encryption with cross-account operations, you must use a fully qualified KMS key ARN. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/bucket-encryption.html#bucket-encryption-update-bucket-policy\">Using encryption for cross-account operations</a>. </p> <p> <b>For example:</b> </p> <ul> <li> <p>Key ID: <code>1234abcd-12ab-34cd-56ef-1234567890ab</code> </p> </li> <li> <p>Key ARN: <code>arn:aws:kms:us-east-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab</code> </p> </li> </ul> <important> <p>Amazon S3 only supports symmetric KMS keys and not asymmetric KMS keys. For more information, see <a href=\"https://docs.aws.amazon.com/kms/latest/developerguide/symmetric-asymmetric.html\">Using symmetric and asymmetric keys</a> in the <i>AWS Key Management Service Developer Guide</i>.</p> </important>"
- }
- },
+ }
+ },
"documentation":"<p>Describes the default server-side encryption to apply to new objects in the bucket. If a PUT Object request doesn't specify any server-side encryption, this default encryption will be applied. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketPUTencryption.html\">PUT Bucket encryption</a> in the <i>Amazon S3 API Reference</i>.</p>"
- },
- "ServerSideEncryptionConfiguration":{
- "type":"structure",
- "required":["Rules"],
- "members":{
- "Rules":{
- "shape":"ServerSideEncryptionRules",
+ },
+ "ServerSideEncryptionConfiguration":{
+ "type":"structure",
+ "required":["Rules"],
+ "members":{
+ "Rules":{
+ "shape":"ServerSideEncryptionRules",
"documentation":"<p>Container for information about a particular server-side encryption configuration rule.</p>",
- "locationName":"Rule"
- }
- },
+ "locationName":"Rule"
+ }
+ },
"documentation":"<p>Specifies the default server-side-encryption configuration.</p>"
- },
- "ServerSideEncryptionRule":{
- "type":"structure",
- "members":{
- "ApplyServerSideEncryptionByDefault":{
- "shape":"ServerSideEncryptionByDefault",
+ },
+ "ServerSideEncryptionRule":{
+ "type":"structure",
+ "members":{
+ "ApplyServerSideEncryptionByDefault":{
+ "shape":"ServerSideEncryptionByDefault",
"documentation":"<p>Specifies the default server-side encryption to apply to new objects in the bucket. If a PUT Object request doesn't specify any server-side encryption, this default encryption will be applied.</p>"
},
"BucketKeyEnabled":{
"shape":"BucketKeyEnabled",
"documentation":"<p>Specifies whether Amazon S3 should use an S3 Bucket Key with server-side encryption using KMS (SSE-KMS) for new objects in the bucket. Existing objects are not affected. Setting the <code>BucketKeyEnabled</code> element to <code>true</code> causes Amazon S3 to use an S3 Bucket Key. By default, S3 Bucket Key is not enabled.</p> <p>For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/bucket-key.html\">Amazon S3 Bucket Keys</a> in the <i>Amazon S3 User Guide</i>.</p>"
- }
- },
+ }
+ },
"documentation":"<p>Specifies the default server-side encryption configuration.</p>"
- },
- "ServerSideEncryptionRules":{
- "type":"list",
- "member":{"shape":"ServerSideEncryptionRule"},
- "flattened":true
- },
+ },
+ "ServerSideEncryptionRules":{
+ "type":"list",
+ "member":{"shape":"ServerSideEncryptionRule"},
+ "flattened":true
+ },
"Setting":{"type":"boolean"},
- "Size":{"type":"integer"},
- "SourceSelectionCriteria":{
- "type":"structure",
- "members":{
- "SseKmsEncryptedObjects":{
- "shape":"SseKmsEncryptedObjects",
+ "Size":{"type":"integer"},
+ "SourceSelectionCriteria":{
+ "type":"structure",
+ "members":{
+ "SseKmsEncryptedObjects":{
+ "shape":"SseKmsEncryptedObjects",
"documentation":"<p> A container for filter information for the selection of Amazon S3 objects encrypted with AWS KMS. If you include <code>SourceSelectionCriteria</code> in the replication configuration, this element is required. </p>"
},
"ReplicaModifications":{
"shape":"ReplicaModifications",
"documentation":"<p>A filter that you can specify for selections for modifications on replicas. Amazon S3 doesn't replicate replica modifications by default. In the latest version of replication configuration (when <code>Filter</code> is specified), you can specify this element and set the status to <code>Enabled</code> to replicate modifications on replicas. </p> <note> <p> If you don't specify the <code>Filter</code> element, Amazon S3 assumes that the replication configuration is the earlier version, V1. In the earlier version, this element is not allowed</p> </note>"
- }
- },
+ }
+ },
"documentation":"<p>A container that describes additional filters for identifying the source objects that you want to replicate. You can choose to enable or disable the replication of these objects. Currently, Amazon S3 supports only the filter that you can specify for objects created with server-side encryption using a customer master key (CMK) stored in AWS Key Management Service (SSE-KMS).</p>"
- },
- "SseKmsEncryptedObjects":{
- "type":"structure",
- "required":["Status"],
- "members":{
- "Status":{
- "shape":"SseKmsEncryptedObjectsStatus",
+ },
+ "SseKmsEncryptedObjects":{
+ "type":"structure",
+ "required":["Status"],
+ "members":{
+ "Status":{
+ "shape":"SseKmsEncryptedObjectsStatus",
"documentation":"<p>Specifies whether Amazon S3 replicates objects created with server-side encryption using an AWS KMS key stored in AWS Key Management Service.</p>"
- }
- },
+ }
+ },
"documentation":"<p>A container for filter information for the selection of S3 objects encrypted with AWS KMS.</p>"
- },
- "SseKmsEncryptedObjectsStatus":{
- "type":"string",
- "enum":[
- "Enabled",
- "Disabled"
- ]
- },
+ },
+ "SseKmsEncryptedObjectsStatus":{
+ "type":"string",
+ "enum":[
+ "Enabled",
+ "Disabled"
+ ]
+ },
"Start":{"type":"long"},
- "StartAfter":{"type":"string"},
- "Stats":{
- "type":"structure",
- "members":{
- "BytesScanned":{
- "shape":"BytesScanned",
+ "StartAfter":{"type":"string"},
+ "Stats":{
+ "type":"structure",
+ "members":{
+ "BytesScanned":{
+ "shape":"BytesScanned",
"documentation":"<p>The total number of object bytes scanned.</p>"
- },
- "BytesProcessed":{
- "shape":"BytesProcessed",
+ },
+ "BytesProcessed":{
+ "shape":"BytesProcessed",
"documentation":"<p>The total number of uncompressed object bytes processed.</p>"
- },
- "BytesReturned":{
- "shape":"BytesReturned",
+ },
+ "BytesReturned":{
+ "shape":"BytesReturned",
"documentation":"<p>The total number of bytes of records payload data returned.</p>"
- }
+ }
},
"documentation":"<p>Container for the stats details.</p>"
- },
- "StatsEvent":{
- "type":"structure",
- "members":{
- "Details":{
- "shape":"Stats",
+ },
+ "StatsEvent":{
+ "type":"structure",
+ "members":{
+ "Details":{
+ "shape":"Stats",
"documentation":"<p>The Stats event details.</p>",
- "eventpayload":true
- }
- },
+ "eventpayload":true
+ }
+ },
"documentation":"<p>Container for the Stats Event.</p>",
- "event":true
- },
- "StorageClass":{
- "type":"string",
- "enum":[
- "STANDARD",
- "REDUCED_REDUNDANCY",
- "STANDARD_IA",
+ "event":true
+ },
+ "StorageClass":{
+ "type":"string",
+ "enum":[
+ "STANDARD",
+ "REDUCED_REDUNDANCY",
+ "STANDARD_IA",
"ONEZONE_IA",
"INTELLIGENT_TIERING",
"GLACIER",
"DEEP_ARCHIVE",
"OUTPOSTS"
- ]
- },
- "StorageClassAnalysis":{
- "type":"structure",
- "members":{
- "DataExport":{
- "shape":"StorageClassAnalysisDataExport",
+ ]
+ },
+ "StorageClassAnalysis":{
+ "type":"structure",
+ "members":{
+ "DataExport":{
+ "shape":"StorageClassAnalysisDataExport",
"documentation":"<p>Specifies how data related to the storage class analysis for an Amazon S3 bucket should be exported.</p>"
- }
+ }
},
"documentation":"<p>Specifies data related to access patterns to be collected and made available to analyze the tradeoffs between different storage classes for an Amazon S3 bucket.</p>"
- },
- "StorageClassAnalysisDataExport":{
- "type":"structure",
- "required":[
- "OutputSchemaVersion",
- "Destination"
- ],
- "members":{
- "OutputSchemaVersion":{
- "shape":"StorageClassAnalysisSchemaVersion",
+ },
+ "StorageClassAnalysisDataExport":{
+ "type":"structure",
+ "required":[
+ "OutputSchemaVersion",
+ "Destination"
+ ],
+ "members":{
+ "OutputSchemaVersion":{
+ "shape":"StorageClassAnalysisSchemaVersion",
"documentation":"<p>The version of the output schema to use when exporting data. Must be <code>V_1</code>.</p>"
- },
- "Destination":{
- "shape":"AnalyticsExportDestination",
+ },
+ "Destination":{
+ "shape":"AnalyticsExportDestination",
"documentation":"<p>The place to store the data for an analysis.</p>"
- }
+ }
},
"documentation":"<p>Container for data related to the storage class analysis for an Amazon S3 bucket for export.</p>"
- },
- "StorageClassAnalysisSchemaVersion":{
- "type":"string",
- "enum":["V_1"]
- },
- "Suffix":{"type":"string"},
- "Tag":{
- "type":"structure",
- "required":[
- "Key",
- "Value"
- ],
- "members":{
- "Key":{
- "shape":"ObjectKey",
+ },
+ "StorageClassAnalysisSchemaVersion":{
+ "type":"string",
+ "enum":["V_1"]
+ },
+ "Suffix":{"type":"string"},
+ "Tag":{
+ "type":"structure",
+ "required":[
+ "Key",
+ "Value"
+ ],
+ "members":{
+ "Key":{
+ "shape":"ObjectKey",
"documentation":"<p>Name of the object key.</p>"
- },
- "Value":{
- "shape":"Value",
+ },
+ "Value":{
+ "shape":"Value",
"documentation":"<p>Value of the tag.</p>"
- }
+ }
},
"documentation":"<p>A container of a key value name pair.</p>"
- },
- "TagCount":{"type":"integer"},
- "TagSet":{
- "type":"list",
- "member":{
- "shape":"Tag",
- "locationName":"Tag"
- }
- },
- "Tagging":{
- "type":"structure",
- "required":["TagSet"],
- "members":{
+ },
+ "TagCount":{"type":"integer"},
+ "TagSet":{
+ "type":"list",
+ "member":{
+ "shape":"Tag",
+ "locationName":"Tag"
+ }
+ },
+ "Tagging":{
+ "type":"structure",
+ "required":["TagSet"],
+ "members":{
"TagSet":{
"shape":"TagSet",
"documentation":"<p>A collection for a set of tags</p>"
}
},
"documentation":"<p>Container for <code>TagSet</code> elements.</p>"
- },
- "TaggingDirective":{
- "type":"string",
- "enum":[
- "COPY",
- "REPLACE"
- ]
- },
- "TaggingHeader":{"type":"string"},
- "TargetBucket":{"type":"string"},
- "TargetGrant":{
- "type":"structure",
- "members":{
+ },
+ "TaggingDirective":{
+ "type":"string",
+ "enum":[
+ "COPY",
+ "REPLACE"
+ ]
+ },
+ "TaggingHeader":{"type":"string"},
+ "TargetBucket":{"type":"string"},
+ "TargetGrant":{
+ "type":"structure",
+ "members":{
"Grantee":{
"shape":"Grantee",
"documentation":"<p>Container for the person being granted permissions.</p>"
},
- "Permission":{
- "shape":"BucketLogsPermission",
+ "Permission":{
+ "shape":"BucketLogsPermission",
"documentation":"<p>Logging permissions assigned to the grantee for the bucket.</p>"
- }
+ }
},
"documentation":"<p>Container for granting information.</p>"
- },
- "TargetGrants":{
- "type":"list",
- "member":{
- "shape":"TargetGrant",
- "locationName":"Grant"
- }
- },
- "TargetPrefix":{"type":"string"},
- "Tier":{
- "type":"string",
- "enum":[
- "Standard",
- "Bulk",
- "Expedited"
- ]
- },
+ },
+ "TargetGrants":{
+ "type":"list",
+ "member":{
+ "shape":"TargetGrant",
+ "locationName":"Grant"
+ }
+ },
+ "TargetPrefix":{"type":"string"},
+ "Tier":{
+ "type":"string",
+ "enum":[
+ "Standard",
+ "Bulk",
+ "Expedited"
+ ]
+ },
"Tiering":{
"type":"structure",
"required":[
@@ -9269,260 +9269,260 @@
"member":{"shape":"Tiering"},
"flattened":true
},
- "Token":{"type":"string"},
- "TopicArn":{"type":"string"},
- "TopicConfiguration":{
- "type":"structure",
- "required":[
- "TopicArn",
- "Events"
- ],
- "members":{
- "Id":{"shape":"NotificationId"},
- "TopicArn":{
- "shape":"TopicArn",
+ "Token":{"type":"string"},
+ "TopicArn":{"type":"string"},
+ "TopicConfiguration":{
+ "type":"structure",
+ "required":[
+ "TopicArn",
+ "Events"
+ ],
+ "members":{
+ "Id":{"shape":"NotificationId"},
+ "TopicArn":{
+ "shape":"TopicArn",
"documentation":"<p>The Amazon Resource Name (ARN) of the Amazon SNS topic to which Amazon S3 publishes a message when it detects events of the specified type.</p>",
- "locationName":"Topic"
- },
- "Events":{
- "shape":"EventList",
+ "locationName":"Topic"
+ },
+ "Events":{
+ "shape":"EventList",
"documentation":"<p>The Amazon S3 bucket event about which to send notifications. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/NotificationHowTo.html\">Supported Event Types</a> in the <i>Amazon S3 User Guide</i>.</p>",
- "locationName":"Event"
- },
+ "locationName":"Event"
+ },
"Filter":{"shape":"NotificationConfigurationFilter"}
- },
+ },
"documentation":"<p>A container for specifying the configuration for publication of messages to an Amazon Simple Notification Service (Amazon SNS) topic when Amazon S3 detects specified events.</p>"
- },
- "TopicConfigurationDeprecated":{
- "type":"structure",
- "members":{
- "Id":{"shape":"NotificationId"},
- "Events":{
- "shape":"EventList",
+ },
+ "TopicConfigurationDeprecated":{
+ "type":"structure",
+ "members":{
+ "Id":{"shape":"NotificationId"},
+ "Events":{
+ "shape":"EventList",
"documentation":"<p>A collection of events related to objects</p>",
- "locationName":"Event"
- },
- "Event":{
- "shape":"Event",
+ "locationName":"Event"
+ },
+ "Event":{
+ "shape":"Event",
"documentation":"<p>Bucket event for which to send notifications.</p>",
- "deprecated":true
- },
- "Topic":{
- "shape":"TopicArn",
+ "deprecated":true
+ },
+ "Topic":{
+ "shape":"TopicArn",
"documentation":"<p>Amazon SNS topic to which Amazon S3 will publish a message to report the specified events for the bucket.</p>"
- }
+ }
},
"documentation":"<p>A container for specifying the configuration for publication of messages to an Amazon Simple Notification Service (Amazon SNS) topic when Amazon S3 detects specified events. This data type is deprecated. Use <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/API_TopicConfiguration.html\">TopicConfiguration</a> instead.</p>"
- },
- "TopicConfigurationList":{
- "type":"list",
- "member":{"shape":"TopicConfiguration"},
- "flattened":true
- },
- "Transition":{
- "type":"structure",
- "members":{
- "Date":{
- "shape":"Date",
+ },
+ "TopicConfigurationList":{
+ "type":"list",
+ "member":{"shape":"TopicConfiguration"},
+ "flattened":true
+ },
+ "Transition":{
+ "type":"structure",
+ "members":{
+ "Date":{
+ "shape":"Date",
"documentation":"<p>Indicates when objects are transitioned to the specified storage class. The date value must be in ISO 8601 format. The time is always midnight UTC.</p>"
- },
- "Days":{
- "shape":"Days",
+ },
+ "Days":{
+ "shape":"Days",
"documentation":"<p>Indicates the number of days after creation when objects are transitioned to the specified storage class. The value must be a positive integer.</p>"
- },
- "StorageClass":{
- "shape":"TransitionStorageClass",
+ },
+ "StorageClass":{
+ "shape":"TransitionStorageClass",
"documentation":"<p>The storage class to which you want the object to transition.</p>"
- }
+ }
},
"documentation":"<p>Specifies when an object transitions to a specified storage class. For more information about Amazon S3 lifecycle configuration rules, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/dev/lifecycle-transition-general-considerations.html\">Transitioning Objects Using Amazon S3 Lifecycle</a> in the <i>Amazon S3 User Guide</i>.</p>"
- },
- "TransitionList":{
- "type":"list",
- "member":{"shape":"Transition"},
- "flattened":true
- },
- "TransitionStorageClass":{
- "type":"string",
- "enum":[
- "GLACIER",
- "STANDARD_IA",
+ },
+ "TransitionList":{
+ "type":"list",
+ "member":{"shape":"Transition"},
+ "flattened":true
+ },
+ "TransitionStorageClass":{
+ "type":"string",
+ "enum":[
+ "GLACIER",
+ "STANDARD_IA",
"ONEZONE_IA",
"INTELLIGENT_TIERING",
"DEEP_ARCHIVE"
- ]
- },
- "Type":{
- "type":"string",
- "enum":[
- "CanonicalUser",
- "AmazonCustomerByEmail",
- "Group"
- ]
- },
- "URI":{"type":"string"},
- "UploadIdMarker":{"type":"string"},
- "UploadPartCopyOutput":{
- "type":"structure",
- "members":{
- "CopySourceVersionId":{
- "shape":"CopySourceVersionId",
+ ]
+ },
+ "Type":{
+ "type":"string",
+ "enum":[
+ "CanonicalUser",
+ "AmazonCustomerByEmail",
+ "Group"
+ ]
+ },
+ "URI":{"type":"string"},
+ "UploadIdMarker":{"type":"string"},
+ "UploadPartCopyOutput":{
+ "type":"structure",
+ "members":{
+ "CopySourceVersionId":{
+ "shape":"CopySourceVersionId",
"documentation":"<p>The version of the source object that was copied, if you have enabled versioning on the source bucket.</p>",
- "location":"header",
- "locationName":"x-amz-copy-source-version-id"
- },
+ "location":"header",
+ "locationName":"x-amz-copy-source-version-id"
+ },
"CopyPartResult":{
"shape":"CopyPartResult",
"documentation":"<p>Container for all response elements.</p>"
},
- "ServerSideEncryption":{
- "shape":"ServerSideEncryption",
+ "ServerSideEncryption":{
+ "shape":"ServerSideEncryption",
"documentation":"<p>The server-side encryption algorithm used when storing this object in Amazon S3 (for example, AES256, aws:kms).</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption"
- },
- "SSECustomerAlgorithm":{
- "shape":"SSECustomerAlgorithm",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption"
+ },
+ "SSECustomerAlgorithm":{
+ "shape":"SSECustomerAlgorithm",
"documentation":"<p>If server-side encryption with a customer-provided encryption key was requested, the response will include this header confirming the encryption algorithm used.</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-customer-algorithm"
- },
- "SSECustomerKeyMD5":{
- "shape":"SSECustomerKeyMD5",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-customer-algorithm"
+ },
+ "SSECustomerKeyMD5":{
+ "shape":"SSECustomerKeyMD5",
"documentation":"<p>If server-side encryption with a customer-provided encryption key was requested, the response will include this header to provide round-trip message integrity verification of the customer-provided encryption key.</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-customer-key-MD5"
- },
- "SSEKMSKeyId":{
- "shape":"SSEKMSKeyId",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-customer-key-MD5"
+ },
+ "SSEKMSKeyId":{
+ "shape":"SSEKMSKeyId",
"documentation":"<p>If present, specifies the ID of the AWS Key Management Service (AWS KMS) symmetric customer managed customer master key (CMK) that was used for the object.</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-aws-kms-key-id"
- },
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-aws-kms-key-id"
+ },
"BucketKeyEnabled":{
"shape":"BucketKeyEnabled",
"documentation":"<p>Indicates whether the multipart upload uses an S3 Bucket Key for server-side encryption with AWS KMS (SSE-KMS).</p>",
"location":"header",
"locationName":"x-amz-server-side-encryption-bucket-key-enabled"
},
- "RequestCharged":{
- "shape":"RequestCharged",
- "location":"header",
- "locationName":"x-amz-request-charged"
- }
- },
- "payload":"CopyPartResult"
- },
- "UploadPartCopyRequest":{
- "type":"structure",
- "required":[
- "Bucket",
- "CopySource",
- "Key",
- "PartNumber",
- "UploadId"
- ],
- "members":{
- "Bucket":{
- "shape":"BucketName",
+ "RequestCharged":{
+ "shape":"RequestCharged",
+ "location":"header",
+ "locationName":"x-amz-request-charged"
+ }
+ },
+ "payload":"CopyPartResult"
+ },
+ "UploadPartCopyRequest":{
+ "type":"structure",
+ "required":[
+ "Bucket",
+ "CopySource",
+ "Key",
+ "PartNumber",
+ "UploadId"
+ ],
+ "members":{
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The bucket name.</p> <p>When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.s3-accesspoint.<i>Region</i>.amazonaws.com. When using this action with an access point through the AWS SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\">Using access points</a> in the <i>Amazon S3 User Guide</i>.</p> <p>When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.<i>outpostID</i>.s3-outposts.<i>Region</i>.amazonaws.com. When using this action using S3 on Outposts through the AWS SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html\">Using S3 on Outposts</a> in the <i>Amazon S3 User Guide</i>.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "CopySource":{
- "shape":"CopySource",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "CopySource":{
+ "shape":"CopySource",
"documentation":"<p>Specifies the source object for the copy operation. You specify the value in one of two formats, depending on whether you want to access the source object through an <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-points.html\">access point</a>:</p> <ul> <li> <p>For objects not accessed through an access point, specify the name of the source bucket and key of the source object, separated by a slash (/). For example, to copy the object <code>reports/january.pdf</code> from the bucket <code>awsexamplebucket</code>, use <code>awsexamplebucket/reports/january.pdf</code>. The value must be URL encoded.</p> </li> <li> <p>For objects accessed through access points, specify the Amazon Resource Name (ARN) of the object as accessed through the access point, in the format <code>arn:aws:s3:&lt;Region&gt;:&lt;account-id&gt;:accesspoint/&lt;access-point-name&gt;/object/&lt;key&gt;</code>. For example, to copy the object <code>reports/january.pdf</code> through access point <code>my-access-point</code> owned by account <code>123456789012</code> in Region <code>us-west-2</code>, use the URL encoding of <code>arn:aws:s3:us-west-2:123456789012:accesspoint/my-access-point/object/reports/january.pdf</code>. The value must be URL encoded.</p> <note> <p>Amazon S3 supports copy operations using access points only when the source and destination buckets are in the same AWS Region.</p> </note> <p>Alternatively, for objects accessed through Amazon S3 on Outposts, specify the ARN of the object as accessed in the format <code>arn:aws:s3-outposts:&lt;Region&gt;:&lt;account-id&gt;:outpost/&lt;outpost-id&gt;/object/&lt;key&gt;</code>. For example, to copy the object <code>reports/january.pdf</code> through outpost <code>my-outpost</code> owned by account <code>123456789012</code> in Region <code>us-west-2</code>, use the URL encoding of <code>arn:aws:s3-outposts:us-west-2:123456789012:outpost/my-outpost/object/reports/january.pdf</code>. The value must be URL encoded. </p> </li> </ul> <p>To copy a specific version of an object, append <code>?versionId=&lt;version-id&gt;</code> to the value (for example, <code>awsexamplebucket/reports/january.pdf?versionId=QUpfdndhfd8438MNFDN93jdnJFkdmqnh893</code>). If you don't specify a version ID, Amazon S3 copies the latest version of the source object.</p>",
- "location":"header",
- "locationName":"x-amz-copy-source"
- },
- "CopySourceIfMatch":{
- "shape":"CopySourceIfMatch",
+ "location":"header",
+ "locationName":"x-amz-copy-source"
+ },
+ "CopySourceIfMatch":{
+ "shape":"CopySourceIfMatch",
"documentation":"<p>Copies the object if its entity tag (ETag) matches the specified tag.</p>",
- "location":"header",
- "locationName":"x-amz-copy-source-if-match"
- },
- "CopySourceIfModifiedSince":{
- "shape":"CopySourceIfModifiedSince",
+ "location":"header",
+ "locationName":"x-amz-copy-source-if-match"
+ },
+ "CopySourceIfModifiedSince":{
+ "shape":"CopySourceIfModifiedSince",
"documentation":"<p>Copies the object if it has been modified since the specified time.</p>",
- "location":"header",
- "locationName":"x-amz-copy-source-if-modified-since"
- },
- "CopySourceIfNoneMatch":{
- "shape":"CopySourceIfNoneMatch",
+ "location":"header",
+ "locationName":"x-amz-copy-source-if-modified-since"
+ },
+ "CopySourceIfNoneMatch":{
+ "shape":"CopySourceIfNoneMatch",
"documentation":"<p>Copies the object if its entity tag (ETag) is different than the specified ETag.</p>",
- "location":"header",
- "locationName":"x-amz-copy-source-if-none-match"
- },
- "CopySourceIfUnmodifiedSince":{
- "shape":"CopySourceIfUnmodifiedSince",
+ "location":"header",
+ "locationName":"x-amz-copy-source-if-none-match"
+ },
+ "CopySourceIfUnmodifiedSince":{
+ "shape":"CopySourceIfUnmodifiedSince",
"documentation":"<p>Copies the object if it hasn't been modified since the specified time.</p>",
- "location":"header",
- "locationName":"x-amz-copy-source-if-unmodified-since"
- },
- "CopySourceRange":{
- "shape":"CopySourceRange",
+ "location":"header",
+ "locationName":"x-amz-copy-source-if-unmodified-since"
+ },
+ "CopySourceRange":{
+ "shape":"CopySourceRange",
"documentation":"<p>The range of bytes to copy from the source object. The range value must use the form bytes=first-last, where the first and last are the zero-based byte offsets to copy. For example, bytes=0-9 indicates that you want to copy the first 10 bytes of the source. You can copy a range only if the source object is greater than 5 MB.</p>",
- "location":"header",
- "locationName":"x-amz-copy-source-range"
- },
- "Key":{
- "shape":"ObjectKey",
+ "location":"header",
+ "locationName":"x-amz-copy-source-range"
+ },
+ "Key":{
+ "shape":"ObjectKey",
"documentation":"<p>Object key for which the multipart upload was initiated.</p>",
- "location":"uri",
- "locationName":"Key"
- },
- "PartNumber":{
- "shape":"PartNumber",
+ "location":"uri",
+ "locationName":"Key"
+ },
+ "PartNumber":{
+ "shape":"PartNumber",
"documentation":"<p>Part number of part being copied. This is a positive integer between 1 and 10,000.</p>",
- "location":"querystring",
- "locationName":"partNumber"
- },
- "UploadId":{
- "shape":"MultipartUploadId",
+ "location":"querystring",
+ "locationName":"partNumber"
+ },
+ "UploadId":{
+ "shape":"MultipartUploadId",
"documentation":"<p>Upload ID identifying the multipart upload whose part is being copied.</p>",
- "location":"querystring",
- "locationName":"uploadId"
- },
- "SSECustomerAlgorithm":{
- "shape":"SSECustomerAlgorithm",
+ "location":"querystring",
+ "locationName":"uploadId"
+ },
+ "SSECustomerAlgorithm":{
+ "shape":"SSECustomerAlgorithm",
"documentation":"<p>Specifies the algorithm to use to when encrypting the object (for example, AES256).</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-customer-algorithm"
- },
- "SSECustomerKey":{
- "shape":"SSECustomerKey",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-customer-algorithm"
+ },
+ "SSECustomerKey":{
+ "shape":"SSECustomerKey",
"documentation":"<p>Specifies the customer-provided encryption key for Amazon S3 to use in encrypting data. This value is used to store the object and then it is discarded; Amazon S3 does not store the encryption key. The key must be appropriate for use with the algorithm specified in the <code>x-amz-server-side-encryption-customer-algorithm</code> header. This must be the same encryption key specified in the initiate multipart upload request.</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-customer-key"
- },
- "SSECustomerKeyMD5":{
- "shape":"SSECustomerKeyMD5",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-customer-key"
+ },
+ "SSECustomerKeyMD5":{
+ "shape":"SSECustomerKeyMD5",
"documentation":"<p>Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. Amazon S3 uses this header for a message integrity check to ensure that the encryption key was transmitted without error.</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-customer-key-MD5"
- },
- "CopySourceSSECustomerAlgorithm":{
- "shape":"CopySourceSSECustomerAlgorithm",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-customer-key-MD5"
+ },
+ "CopySourceSSECustomerAlgorithm":{
+ "shape":"CopySourceSSECustomerAlgorithm",
"documentation":"<p>Specifies the algorithm to use when decrypting the source object (for example, AES256).</p>",
- "location":"header",
- "locationName":"x-amz-copy-source-server-side-encryption-customer-algorithm"
- },
- "CopySourceSSECustomerKey":{
- "shape":"CopySourceSSECustomerKey",
+ "location":"header",
+ "locationName":"x-amz-copy-source-server-side-encryption-customer-algorithm"
+ },
+ "CopySourceSSECustomerKey":{
+ "shape":"CopySourceSSECustomerKey",
"documentation":"<p>Specifies the customer-provided encryption key for Amazon S3 to use to decrypt the source object. The encryption key provided in this header must be one that was used when the source object was created.</p>",
- "location":"header",
- "locationName":"x-amz-copy-source-server-side-encryption-customer-key"
- },
- "CopySourceSSECustomerKeyMD5":{
- "shape":"CopySourceSSECustomerKeyMD5",
+ "location":"header",
+ "locationName":"x-amz-copy-source-server-side-encryption-customer-key"
+ },
+ "CopySourceSSECustomerKeyMD5":{
+ "shape":"CopySourceSSECustomerKeyMD5",
"documentation":"<p>Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. Amazon S3 uses this header for a message integrity check to ensure that the encryption key was transmitted without error.</p>",
- "location":"header",
- "locationName":"x-amz-copy-source-server-side-encryption-customer-key-MD5"
- },
- "RequestPayer":{
- "shape":"RequestPayer",
- "location":"header",
- "locationName":"x-amz-request-payer"
+ "location":"header",
+ "locationName":"x-amz-copy-source-server-side-encryption-customer-key-MD5"
+ },
+ "RequestPayer":{
+ "shape":"RequestPayer",
+ "location":"header",
+ "locationName":"x-amz-request-payer"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
@@ -9535,164 +9535,164 @@
"documentation":"<p>The account ID of the expected source bucket owner. If the source bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-source-expected-bucket-owner"
- }
- }
- },
- "UploadPartOutput":{
- "type":"structure",
- "members":{
- "ServerSideEncryption":{
- "shape":"ServerSideEncryption",
+ }
+ }
+ },
+ "UploadPartOutput":{
+ "type":"structure",
+ "members":{
+ "ServerSideEncryption":{
+ "shape":"ServerSideEncryption",
"documentation":"<p>The server-side encryption algorithm used when storing this object in Amazon S3 (for example, AES256, aws:kms).</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption"
- },
- "ETag":{
- "shape":"ETag",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption"
+ },
+ "ETag":{
+ "shape":"ETag",
"documentation":"<p>Entity tag for the uploaded object.</p>",
- "location":"header",
- "locationName":"ETag"
- },
- "SSECustomerAlgorithm":{
- "shape":"SSECustomerAlgorithm",
+ "location":"header",
+ "locationName":"ETag"
+ },
+ "SSECustomerAlgorithm":{
+ "shape":"SSECustomerAlgorithm",
"documentation":"<p>If server-side encryption with a customer-provided encryption key was requested, the response will include this header confirming the encryption algorithm used.</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-customer-algorithm"
- },
- "SSECustomerKeyMD5":{
- "shape":"SSECustomerKeyMD5",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-customer-algorithm"
+ },
+ "SSECustomerKeyMD5":{
+ "shape":"SSECustomerKeyMD5",
"documentation":"<p>If server-side encryption with a customer-provided encryption key was requested, the response will include this header to provide round-trip message integrity verification of the customer-provided encryption key.</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-customer-key-MD5"
- },
- "SSEKMSKeyId":{
- "shape":"SSEKMSKeyId",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-customer-key-MD5"
+ },
+ "SSEKMSKeyId":{
+ "shape":"SSEKMSKeyId",
"documentation":"<p>If present, specifies the ID of the AWS Key Management Service (AWS KMS) symmetric customer managed customer master key (CMK) was used for the object.</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-aws-kms-key-id"
- },
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-aws-kms-key-id"
+ },
"BucketKeyEnabled":{
"shape":"BucketKeyEnabled",
"documentation":"<p>Indicates whether the multipart upload uses an S3 Bucket Key for server-side encryption with AWS KMS (SSE-KMS).</p>",
"location":"header",
"locationName":"x-amz-server-side-encryption-bucket-key-enabled"
},
- "RequestCharged":{
- "shape":"RequestCharged",
- "location":"header",
- "locationName":"x-amz-request-charged"
- }
- }
- },
- "UploadPartRequest":{
- "type":"structure",
- "required":[
- "Bucket",
- "Key",
- "PartNumber",
- "UploadId"
- ],
- "members":{
- "Body":{
- "shape":"Body",
+ "RequestCharged":{
+ "shape":"RequestCharged",
+ "location":"header",
+ "locationName":"x-amz-request-charged"
+ }
+ }
+ },
+ "UploadPartRequest":{
+ "type":"structure",
+ "required":[
+ "Bucket",
+ "Key",
+ "PartNumber",
+ "UploadId"
+ ],
+ "members":{
+ "Body":{
+ "shape":"Body",
"documentation":"<p>Object data.</p>",
- "streaming":true
- },
- "Bucket":{
- "shape":"BucketName",
+ "streaming":true
+ },
+ "Bucket":{
+ "shape":"BucketName",
"documentation":"<p>The name of the bucket to which the multipart upload was initiated.</p> <p>When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.s3-accesspoint.<i>Region</i>.amazonaws.com. When using this action with an access point through the AWS SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-access-points.html\">Using access points</a> in the <i>Amazon S3 User Guide</i>.</p> <p>When using this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form <i>AccessPointName</i>-<i>AccountId</i>.<i>outpostID</i>.s3-outposts.<i>Region</i>.amazonaws.com. When using this action using S3 on Outposts through the AWS SDKs, you provide the Outposts bucket ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/S3onOutposts.html\">Using S3 on Outposts</a> in the <i>Amazon S3 User Guide</i>.</p>",
- "location":"uri",
- "locationName":"Bucket"
- },
- "ContentLength":{
- "shape":"ContentLength",
+ "location":"uri",
+ "locationName":"Bucket"
+ },
+ "ContentLength":{
+ "shape":"ContentLength",
"documentation":"<p>Size of the body in bytes. This parameter is useful when the size of the body cannot be determined automatically.</p>",
- "location":"header",
- "locationName":"Content-Length"
- },
- "ContentMD5":{
- "shape":"ContentMD5",
+ "location":"header",
+ "locationName":"Content-Length"
+ },
+ "ContentMD5":{
+ "shape":"ContentMD5",
"documentation":"<p>The base64-encoded 128-bit MD5 digest of the part data. This parameter is auto-populated when using the command from the CLI. This parameter is required if object lock parameters are specified.</p>",
- "location":"header",
- "locationName":"Content-MD5"
- },
- "Key":{
- "shape":"ObjectKey",
+ "location":"header",
+ "locationName":"Content-MD5"
+ },
+ "Key":{
+ "shape":"ObjectKey",
"documentation":"<p>Object key for which the multipart upload was initiated.</p>",
- "location":"uri",
- "locationName":"Key"
- },
- "PartNumber":{
- "shape":"PartNumber",
+ "location":"uri",
+ "locationName":"Key"
+ },
+ "PartNumber":{
+ "shape":"PartNumber",
"documentation":"<p>Part number of part being uploaded. This is a positive integer between 1 and 10,000.</p>",
- "location":"querystring",
- "locationName":"partNumber"
- },
- "UploadId":{
- "shape":"MultipartUploadId",
+ "location":"querystring",
+ "locationName":"partNumber"
+ },
+ "UploadId":{
+ "shape":"MultipartUploadId",
"documentation":"<p>Upload ID identifying the multipart upload whose part is being uploaded.</p>",
- "location":"querystring",
- "locationName":"uploadId"
- },
- "SSECustomerAlgorithm":{
- "shape":"SSECustomerAlgorithm",
+ "location":"querystring",
+ "locationName":"uploadId"
+ },
+ "SSECustomerAlgorithm":{
+ "shape":"SSECustomerAlgorithm",
"documentation":"<p>Specifies the algorithm to use to when encrypting the object (for example, AES256).</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-customer-algorithm"
- },
- "SSECustomerKey":{
- "shape":"SSECustomerKey",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-customer-algorithm"
+ },
+ "SSECustomerKey":{
+ "shape":"SSECustomerKey",
"documentation":"<p>Specifies the customer-provided encryption key for Amazon S3 to use in encrypting data. This value is used to store the object and then it is discarded; Amazon S3 does not store the encryption key. The key must be appropriate for use with the algorithm specified in the <code>x-amz-server-side-encryption-customer-algorithm header</code>. This must be the same encryption key specified in the initiate multipart upload request.</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-customer-key"
- },
- "SSECustomerKeyMD5":{
- "shape":"SSECustomerKeyMD5",
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-customer-key"
+ },
+ "SSECustomerKeyMD5":{
+ "shape":"SSECustomerKeyMD5",
"documentation":"<p>Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. Amazon S3 uses this header for a message integrity check to ensure that the encryption key was transmitted without error.</p>",
- "location":"header",
- "locationName":"x-amz-server-side-encryption-customer-key-MD5"
- },
- "RequestPayer":{
- "shape":"RequestPayer",
- "location":"header",
- "locationName":"x-amz-request-payer"
+ "location":"header",
+ "locationName":"x-amz-server-side-encryption-customer-key-MD5"
+ },
+ "RequestPayer":{
+ "shape":"RequestPayer",
+ "location":"header",
+ "locationName":"x-amz-request-payer"
},
"ExpectedBucketOwner":{
"shape":"AccountId",
"documentation":"<p>The account ID of the expected bucket owner. If the bucket is owned by a different account, the request will fail with an HTTP <code>403 (Access Denied)</code> error.</p>",
"location":"header",
"locationName":"x-amz-expected-bucket-owner"
- }
- },
- "payload":"Body"
- },
- "UserMetadata":{
- "type":"list",
- "member":{
- "shape":"MetadataEntry",
- "locationName":"MetadataEntry"
- }
- },
- "Value":{"type":"string"},
- "VersionIdMarker":{"type":"string"},
- "VersioningConfiguration":{
- "type":"structure",
- "members":{
- "MFADelete":{
- "shape":"MFADelete",
+ }
+ },
+ "payload":"Body"
+ },
+ "UserMetadata":{
+ "type":"list",
+ "member":{
+ "shape":"MetadataEntry",
+ "locationName":"MetadataEntry"
+ }
+ },
+ "Value":{"type":"string"},
+ "VersionIdMarker":{"type":"string"},
+ "VersioningConfiguration":{
+ "type":"structure",
+ "members":{
+ "MFADelete":{
+ "shape":"MFADelete",
"documentation":"<p>Specifies whether MFA delete is enabled in the bucket versioning configuration. This element is only returned if the bucket has been configured with MFA delete. If the bucket has never been so configured, this element is not returned.</p>",
- "locationName":"MfaDelete"
- },
- "Status":{
- "shape":"BucketVersioningStatus",
+ "locationName":"MfaDelete"
+ },
+ "Status":{
+ "shape":"BucketVersioningStatus",
"documentation":"<p>The versioning state of the bucket.</p>"
- }
+ }
},
"documentation":"<p>Describes the versioning state of an Amazon S3 bucket. For more information, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketPUTVersioningStatus.html\">PUT Bucket versioning</a> in the <i>Amazon S3 API Reference</i>.</p>"
- },
- "WebsiteConfiguration":{
- "type":"structure",
- "members":{
+ },
+ "WebsiteConfiguration":{
+ "type":"structure",
+ "members":{
"ErrorDocument":{
"shape":"ErrorDocument",
"documentation":"<p>The name of the error document for the website.</p>"
@@ -9711,7 +9711,7 @@
}
},
"documentation":"<p>Specifies website configuration parameters for an Amazon S3 bucket.</p>"
- },
+ },
"WebsiteRedirectLocation":{"type":"string"},
"WriteGetObjectResponseRequest":{
"type":"structure",
@@ -9941,4 +9941,4 @@
"Years":{"type":"integer"}
},
"documentation":"<p/>"
-}
+}
diff --git a/contrib/python/botocore/botocore/data/s3/2006-03-01/waiters-2.json b/contrib/python/botocore/botocore/data/s3/2006-03-01/waiters-2.json
index b508a8f5b0..ce75576155 100644
--- a/contrib/python/botocore/botocore/data/s3/2006-03-01/waiters-2.json
+++ b/contrib/python/botocore/botocore/data/s3/2006-03-01/waiters-2.json
@@ -1,73 +1,73 @@
-{
- "version": 2,
- "waiters": {
- "BucketExists": {
- "delay": 5,
- "operation": "HeadBucket",
- "maxAttempts": 20,
- "acceptors": [
- {
- "expected": 200,
- "matcher": "status",
- "state": "success"
- },
- {
- "expected": 301,
- "matcher": "status",
- "state": "success"
- },
- {
- "expected": 403,
- "matcher": "status",
- "state": "success"
- },
- {
- "expected": 404,
- "matcher": "status",
- "state": "retry"
- }
- ]
- },
- "BucketNotExists": {
- "delay": 5,
- "operation": "HeadBucket",
- "maxAttempts": 20,
- "acceptors": [
- {
- "expected": 404,
- "matcher": "status",
- "state": "success"
- }
- ]
- },
- "ObjectExists": {
- "delay": 5,
- "operation": "HeadObject",
- "maxAttempts": 20,
- "acceptors": [
- {
- "expected": 200,
- "matcher": "status",
- "state": "success"
- },
- {
- "expected": 404,
- "matcher": "status",
- "state": "retry"
- }
- ]
- },
- "ObjectNotExists": {
- "delay": 5,
- "operation": "HeadObject",
- "maxAttempts": 20,
- "acceptors": [
- {
- "expected": 404,
- "matcher": "status",
- "state": "success"
- }
- ]
- }
- }
-}
+{
+ "version": 2,
+ "waiters": {
+ "BucketExists": {
+ "delay": 5,
+ "operation": "HeadBucket",
+ "maxAttempts": 20,
+ "acceptors": [
+ {
+ "expected": 200,
+ "matcher": "status",
+ "state": "success"
+ },
+ {
+ "expected": 301,
+ "matcher": "status",
+ "state": "success"
+ },
+ {
+ "expected": 403,
+ "matcher": "status",
+ "state": "success"
+ },
+ {
+ "expected": 404,
+ "matcher": "status",
+ "state": "retry"
+ }
+ ]
+ },
+ "BucketNotExists": {
+ "delay": 5,
+ "operation": "HeadBucket",
+ "maxAttempts": 20,
+ "acceptors": [
+ {
+ "expected": 404,
+ "matcher": "status",
+ "state": "success"
+ }
+ ]
+ },
+ "ObjectExists": {
+ "delay": 5,
+ "operation": "HeadObject",
+ "maxAttempts": 20,
+ "acceptors": [
+ {
+ "expected": 200,
+ "matcher": "status",
+ "state": "success"
+ },
+ {
+ "expected": 404,
+ "matcher": "status",
+ "state": "retry"
+ }
+ ]
+ },
+ "ObjectNotExists": {
+ "delay": 5,
+ "operation": "HeadObject",
+ "maxAttempts": 20,
+ "acceptors": [
+ {
+ "expected": 404,
+ "matcher": "status",
+ "state": "success"
+ }
+ ]
+ }
+ }
+}
diff --git a/contrib/python/botocore/tests/SQS-119.py b/contrib/python/botocore/tests/SQS-119.py
index 8856654233..aeb9b2c992 100644
--- a/contrib/python/botocore/tests/SQS-119.py
+++ b/contrib/python/botocore/tests/SQS-119.py
@@ -8,8 +8,8 @@ class TestSqs119(unittest.TestCase):
boto3.client('sqs', region_name='yandex')
except:
raise AssertionError('builtin AWS data is insufficient for SQS')
-
- try:
- boto3.client('s3', region_name='yandex')
- except:
- raise AssertionError('builtin AWS data is insufficient for S3')
+
+ try:
+ boto3.client('s3', region_name='yandex')
+ except:
+ raise AssertionError('builtin AWS data is insufficient for S3')
diff --git a/contrib/python/ya.make b/contrib/python/ya.make
index d01ced9f3a..c1c70fca44 100644
--- a/contrib/python/ya.make
+++ b/contrib/python/ya.make
@@ -823,7 +823,7 @@ RECURSE(
PyHamcrest
pyjavaproperties
PyJWT
- pykdtree
+ pykdtree
pyketama
pylev
pylint
@@ -847,7 +847,7 @@ RECURSE(
pyproj
pyre2
pyrepl
- pyresample
+ pyresample
pyrsistent
pysctp
pysendfile
@@ -886,7 +886,7 @@ RECURSE(
pytest-twisted
pytest-vcr
pytest-xdist
- pytest-xprocess
+ pytest-xprocess
python-crfsuite
python-crontab
python-daemon
diff --git a/library/cpp/timezone_conversion/civil.cpp b/library/cpp/timezone_conversion/civil.cpp
index 5986318b9a..eb62e405f8 100644
--- a/library/cpp/timezone_conversion/civil.cpp
+++ b/library/cpp/timezone_conversion/civil.cpp
@@ -76,10 +76,10 @@ namespace NDatetime {
return result;
}
- TTimeZone GetFixedTimeZone(const long offset) {
- return cctz::fixed_time_zone(std::chrono::seconds(offset));
- }
-
+ TTimeZone GetFixedTimeZone(const long offset) {
+ return cctz::fixed_time_zone(std::chrono::seconds(offset));
+ }
+
TCivilSecond Convert(const TInstant& absTime, const TTimeZone& tz) {
return cctz::convert(TSystemClock::from_time_t(absTime.TimeT()), tz);
}
diff --git a/library/cpp/timezone_conversion/civil.h b/library/cpp/timezone_conversion/civil.h
index 0e95b807ed..9e809ad6a3 100644
--- a/library/cpp/timezone_conversion/civil.h
+++ b/library/cpp/timezone_conversion/civil.h
@@ -100,13 +100,13 @@ namespace NDatetime {
*/
TTimeZone GetTimeZone(TStringBuf name);
- /**
- * Returns a time zone that is a fixed offset (seconds east) from UTC.
- * Note: If the absolute value of the offset is greater than 24 hours
- * you'll get UTC (i.e., zero offset) instead.
- */
- TTimeZone GetFixedTimeZone(const long offset);
-
+ /**
+ * Returns a time zone that is a fixed offset (seconds east) from UTC.
+ * Note: If the absolute value of the offset is greater than 24 hours
+ * you'll get UTC (i.e., zero offset) instead.
+ */
+ TTimeZone GetFixedTimeZone(const long offset);
+
/** Convert civil time from one timezone to another
* @param[in] src is source time with 'from' timezone
* @param[in] from is a initial timezone