From fa1212f2dee216bd02b321e3747c22fc854b31a5 Mon Sep 17 00:00:00 2001 From: moson Date: Mon, 10 Jul 2023 18:02:20 +0200 Subject: [PATCH] fix: translations not containing string formatting In some translations we might be missing replacement placeholders (%). This turns out to be problematic when calling the format function. Wrap the jinja2 format function and just return the string unformatted when % is missing. Fixes: #341 Signed-off-by: moson --- aurweb/filters.py | 15 +++++++++++++++ test/test_filters.py | 17 +++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/aurweb/filters.py b/aurweb/filters.py index 893f21af..38322cdf 100644 --- a/aurweb/filters.py +++ b/aurweb/filters.py @@ -8,6 +8,7 @@ from zoneinfo import ZoneInfo import fastapi import paginate from jinja2 import pass_context +from jinja2.filters import do_format import aurweb.models from aurweb import config, l10n @@ -164,3 +165,17 @@ def date_display(context: dict[str, Any], dt: Union[int, datetime]) -> str: @pass_context def datetime_display(context: dict[str, Any], dt: Union[int, datetime]) -> str: return date_strftime(context, dt, "%Y-%m-%d %H:%M (%Z)") + + +@register_filter("format") +def safe_format(value: str, *args: Any, **kwargs: Any) -> str: + """Wrapper for jinja2 format function to perform additional checks.""" + + # If we don't have anything to be formatted, just return the value. + # We have some translations that do not contain placeholders for replacement. + # In these cases the jinja2 function is throwing an error: + # "TypeError: not all arguments converted during string formatting" + if "%" not in value: + return value + + return do_format(value, *args, **kwargs) diff --git a/test/test_filters.py b/test/test_filters.py index e74ddb87..b56b80ab 100644 --- a/test/test_filters.py +++ b/test/test_filters.py @@ -1,6 +1,8 @@ from datetime import datetime from zoneinfo import ZoneInfo +import pytest + from aurweb import filters, time @@ -34,3 +36,18 @@ def test_to_qs(): query = {"a": "b", "c": [1, 2, 3]} qs = filters.to_qs(query) assert qs == "a=b&c=1&c=2&c=3" + + +@pytest.mark.parametrize( + "value, args, expected", + [ + ("", (), ""), + ("a", (), "a"), + ("a", (1,), "a"), + ("%s", ("a",), "a"), + ("%s", ("ab",), "ab"), + ("%s%d", ("a", 1), "a1"), + ], +) +def test_safe_format(value: str, args: tuple, expected: str): + assert filters.safe_format(value, *args) == expected