diff --git a/qutebrowser/config/configdata.py b/qutebrowser/config/configdata.py index 46cdb91eb..0210f9c65 100644 --- a/qutebrowser/config/configdata.py +++ b/qutebrowser/config/configdata.py @@ -381,7 +381,7 @@ def data(readonly=False): "What to display in the download filename input."), ('timestamp-format', - SettingValue(typ.String(none_ok=True), '%Y-%m-%d'), + SettingValue(typ.TimestampTemplate(none_ok=True), '%Y-%m-%d'), "How to format timestamps (e.g. for history)"), ('show', diff --git a/qutebrowser/config/configtypes.py b/qutebrowser/config/configtypes.py index 86e500f1e..594510da9 100644 --- a/qutebrowser/config/configtypes.py +++ b/qutebrowser/config/configtypes.py @@ -27,6 +27,7 @@ import os.path import itertools import collections import warnings +import datetime from PyQt5.QtCore import QUrl from PyQt5.QtGui import QColor, QFont @@ -1630,3 +1631,25 @@ class URLSegmentList(FlagList): """A list of URL segments.""" valid_values = ValidValues('host', 'path', 'query', 'anchor') + + +class TimestampTemplate(BaseType): + + """A strftime-like template for timestamps. + + See + https://docs.python.org/3/library/datetime.html#strftime-strptime-behavior + for reference. + """ + + def validate(self, value): + self._basic_validation(value) + if not value: + return + try: + # Dummy check to see if the template is valid + datetime.datetime.now().strftime(value) + except ValueError as error: + # thrown on invalid template string + raise configexc.ValidationError( + value, "Invalid format string: {}".format(error)) diff --git a/tests/unit/config/test_configtypes.py b/tests/unit/config/test_configtypes.py index 8a2150be4..3fd9d8138 100644 --- a/tests/unit/config/test_configtypes.py +++ b/tests/unit/config/test_configtypes.py @@ -2042,6 +2042,24 @@ class TestUserAgent: klass().complete() +class TestTimestampTemplate: + + """Test TimestampTemplate.""" + + @pytest.fixture + def klass(self): + return configtypes.TimestampTemplate + + @pytest.mark.parametrize('val', ['', 'foobar', '%H:%M', 'foo %H bar %M']) + def test_validate_valid(self, klass, val): + klass(none_ok=True).validate(val) + + @pytest.mark.parametrize('val', ['', '%']) + def test_validate_invalid(self, klass, val): + with pytest.raises(configexc.ValidationError): + klass().validate(val) + + @pytest.mark.parametrize('first, second, equal', [ (re.compile('foo'), RegexEq('foo'), True), (RegexEq('bar'), re.compile('bar'), True),