Skip to content

Commit

Permalink
Merge branch '3.1.x'
Browse files Browse the repository at this point in the history
  • Loading branch information
davidism committed Jan 10, 2024
2 parents 7f8fb54 + 36f9885 commit 3fd91e4
Show file tree
Hide file tree
Showing 9 changed files with 69 additions and 26 deletions.
11 changes: 4 additions & 7 deletions .github/workflows/publish.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,10 @@ jobs:
# files in the draft release.
environment: 'publish'
runs-on: ubuntu-latest
permissions:
id-token: write
steps:
- uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a
# Try uploading to Test PyPI first, in case something fails.
- uses: pypa/gh-action-pypi-publish@b7f401de30cb6434a1e19f805ff006643653240e
with:
repository_url: https://test.pypi.org/legacy/
packages_dir: artifact/
- uses: pypa/gh-action-pypi-publish@b7f401de30cb6434a1e19f805ff006643653240e
- uses: pypa/gh-action-pypi-publish@2f6f737ca5f74c637829c0f5c3acd0e29ea5e8bf
with:
packages_dir: artifact/
packages-dir: artifact/
10 changes: 5 additions & 5 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,21 @@ ci:
autoupdate_schedule: monthly
repos:
- repo: https://github.com/asottile/pyupgrade
rev: v3.7.0
rev: v3.15.0
hooks:
- id: pyupgrade
args: ["--py37-plus"]
- repo: https://github.com/asottile/reorder-python-imports
rev: v3.10.0
rev: v3.12.0
hooks:
- id: reorder-python-imports
args: ["--application-directories", "src"]
- repo: https://github.com/psf/black
rev: 23.3.0
rev: 23.12.1
hooks:
- id: black
- repo: https://github.com/PyCQA/flake8
rev: 6.0.0
rev: 7.0.0
hooks:
- id: flake8
additional_dependencies: [flake8-bugbear]
Expand All @@ -26,7 +26,7 @@ repos:
hooks:
- id: pip-compile-multi-verify
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
rev: v4.5.0
hooks:
- id: fix-byte-order-marker
- id: trailing-whitespace
Expand Down
5 changes: 4 additions & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@ Unreleased
Version 3.1.3
-------------

Unreleased
Released 2024-01-10

- Fix compiler error when checking if required blocks in parent templates are
empty. :pr:`1858`
- ``xmlattr`` filter does not allow keys with spaces. GHSA-h5c8-rqwp-cp95
- Make error messages stemming from invalid nesting of ``{% trans %}`` blocks
more helpful. :pr:`1918`


Version 3.1.2
Expand Down
4 changes: 2 additions & 2 deletions src/jinja2/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -1406,15 +1406,15 @@ def _make_finalize(self) -> _FinalizeInfo:

if pass_arg is None:

def finalize(value: t.Any) -> t.Any:
def finalize(value: t.Any) -> t.Any: # noqa: F811
return default(env_finalize(value))

else:
src = f"{src}{pass_arg}, "

if pass_arg == "environment":

def finalize(value: t.Any) -> t.Any:
def finalize(value: t.Any) -> t.Any: # noqa: F811
return default(env_finalize(self.environment, value))

self._finalize = self._FinalizeInfo(finalize, src)
Expand Down
16 changes: 13 additions & 3 deletions src/jinja2/ext.py
Original file line number Diff line number Diff line change
Expand Up @@ -495,16 +495,26 @@ def _parse_block(
parser.stream.expect("variable_end")
elif parser.stream.current.type == "block_begin":
next(parser.stream)
if parser.stream.current.test("name:endtrans"):
block_name = (
parser.stream.current.value
if parser.stream.current.type == "name"
else None
)
if block_name == "endtrans":
break
elif parser.stream.current.test("name:pluralize"):
elif block_name == "pluralize":
if allow_pluralize:
break
parser.fail(
"a translatable section can have only one pluralize section"
)
elif block_name == "trans":
parser.fail(
"trans blocks can't be nested; did you mean `endtrans`?"
)
parser.fail(
"control structures in translatable sections are not allowed"
f"control structures in translatable sections are not allowed; "
f"saw `{block_name}`"
)
elif parser.stream.eos:
parser.fail("unclosed translation block")
Expand Down
28 changes: 21 additions & 7 deletions src/jinja2/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,13 +248,17 @@ def do_items(value: t.Union[t.Mapping[K, V], Undefined]) -> t.Iterator[t.Tuple[K
yield from value.items()


_space_re = re.compile(r"\s", flags=re.ASCII)


@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:
If any key contains a space, this fails with a ``ValueError``. Values that
are neither ``none`` nor ``undefined`` are automatically escaped.
.. sourcecode:: html+jinja
Expand All @@ -273,12 +277,22 @@ def do_xmlattr(
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.
.. versionchanged:: 3.1.3
Keys with spaces are not allowed.
"""
rv = " ".join(
f'{escape(key)}="{escape(value)}"'
for key, value in d.items()
if value is not None and not isinstance(value, Undefined)
)
items = []

for key, value in d.items():
if value is None or isinstance(value, Undefined):
continue

if _space_re.search(key) is not None:
raise ValueError(f"Spaces are not allowed in attributes: '{key}'")

items.append(f'{escape(key)}="{escape(value)}"')

rv = " ".join(items)

if autospace and rv:
rv = " " + rv
Expand Down
2 changes: 1 addition & 1 deletion src/jinja2/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -859,7 +859,7 @@ def parse_subscribed(self) -> nodes.Expr:
else:
args.append(None)

return nodes.Slice(lineno=lineno, *args)
return nodes.Slice(lineno=lineno, *args) # noqa: B026

def parse_call_args(
self,
Expand Down
13 changes: 13 additions & 0 deletions tests/test_ext.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from jinja2 import Environment
from jinja2 import nodes
from jinja2 import pass_context
from jinja2 import TemplateSyntaxError
from jinja2.exceptions import TemplateAssertionError
from jinja2.ext import Extension
from jinja2.lexer import count_newlines
Expand Down Expand Up @@ -468,6 +469,18 @@ def test_extract_context(self):
(3, "npgettext", ("babel", "%(users)s user", "%(users)s users", None), []),
]

def test_nested_trans_error(self):
s = "{% trans %}foo{% trans %}{% endtrans %}"
with pytest.raises(TemplateSyntaxError) as excinfo:
i18n_env.from_string(s)
assert "trans blocks can't be nested" in str(excinfo.value)

def test_trans_block_error(self):
s = "{% trans %}foo{% wibble bar %}{% endwibble %}{% endtrans %}"
with pytest.raises(TemplateSyntaxError) as excinfo:
i18n_env.from_string(s)
assert "saw `wibble`" in str(excinfo.value)


class TestScope:
def test_basic_scope_behavior(self):
Expand Down
6 changes: 6 additions & 0 deletions tests/test_filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,12 @@ def test_xmlattr(self, env):
assert 'bar="23"' in out
assert 'blub:blub="<?>"' in out

def test_xmlattr_key_with_spaces(self, env):
with pytest.raises(ValueError, match="Spaces are not allowed"):
env.from_string(
"{{ {'src=1 onerror=alert(1)': 'my_class'}|xmlattr }}"
).render()

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]"
Expand Down

0 comments on commit 3fd91e4

Please sign in to comment.