diff --git a/gallery_dl/formatter.py b/gallery_dl/formatter.py index 27d5e40e..d1b3a8a7 100644 --- a/gallery_dl/formatter.py +++ b/gallery_dl/formatter.py @@ -20,6 +20,7 @@ _CACHE = {} _CONVERSIONS = None _GLOBALS = { "_env": lambda: os.environ, + "_lit": lambda: _literal, "_now": datetime.datetime.now, } @@ -219,6 +220,10 @@ def parse_field_name(field_name): first, rest = _string.formatter_field_name_split(field_name) funcs = [] + if first[0] == "'": + funcs.append(operator.itemgetter(first[1:-1])) + first = "_lit" + for is_attr, key in rest: if is_attr: func = operator.attrgetter @@ -344,3 +349,15 @@ def _default_format(format_spec): def wrap(obj): return format(obj, format_spec) return wrap + + +class Literal(): + # __getattr__, __getattribute__, and __class_getitem__ + # are all slower than regular __getitem__ + + @staticmethod + def __getitem__(key): + return key + + +_literal = Literal() diff --git a/test/test_formatter.py b/test/test_formatter.py index 4cce8a38..efb69636 100644 --- a/test/test_formatter.py +++ b/test/test_formatter.py @@ -208,6 +208,22 @@ class TestFormatter(unittest.TestCase): self.assertRegex(out1, r"^\d{4}-\d\d-\d\d \d\d:\d\d:\d\d(\.\d+)?$") self.assertNotEqual(out1, out2) + def test_literals(self): + value = "foo" + + self._run_test("{'foo'}" , value) + self._run_test("{'foo'!u}" , value.upper()) + self._run_test("{'f00':R0/o/}" , value) + self._run_test("{'foobar'[:3]}", value) + self._run_test("{z|'foo'}" , value) + self._run_test("{z|''|'foo'}" , value) + + self._run_test("{_lit[foo]}" , value) + self._run_test("{_lit[foo]!u}" , value.upper()) + self._run_test("{_lit[f00]:R0/o/}" , value) + self._run_test("{_lit[foobar][:3]}", value) + self._run_test("{z|_lit[foo]}" , value) + def test_template(self): with tempfile.TemporaryDirectory() as tmpdirname: path1 = os.path.join(tmpdirname, "tpl1")