From 46fdf46f21051454779b6455ac2703dbb313cb28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20F=C3=A4hrmann?= Date: Mon, 20 Mar 2023 22:05:33 +0100 Subject: [PATCH] [formatter] support loading an f-string from a template file "\fTF ~/path/to/file.txt" --- docs/formatting.md | 15 ++++++++++----- gallery_dl/formatter.py | 29 ++++++++++++++++++++--------- test/test_formatter.py | 21 +++++++++++++++++++++ 3 files changed, 51 insertions(+), 14 deletions(-) diff --git a/docs/formatting.md b/docs/formatting.md index 7ebff499..cc2703d2 100644 --- a/docs/formatting.md +++ b/docs/formatting.md @@ -255,11 +255,6 @@ Starting a format string with '\f ' allows to set a different format strin - - T - A template file containing the actual format string - \fT ~/.templates/booru.txt - F An f-string literal @@ -270,6 +265,16 @@ Starting a format string with '\f ' allows to set a different format strin An arbitrary Python expression \fE title.upper().replace(' ', '-') + + T + Path to a template file containing a regular format string + \fT ~/.templates/booru.txt + + + TF + Path to a template file containing an f-string literal + \fTF ~/.templates/fstr.txt + M Path or name of a Python module diff --git a/gallery_dl/formatter.py b/gallery_dl/formatter.py index 95085c79..858e89ef 100644 --- a/gallery_dl/formatter.py +++ b/gallery_dl/formatter.py @@ -34,6 +34,8 @@ def parse(format_string, default=NONE, fmt=format): if kind == "T": cls = TemplateFormatter + elif kind == "TF": + cls = TemplateFStringFormatter elif kind == "E": cls = ExpressionFormatter elif kind == "M": @@ -197,15 +199,6 @@ class StringFormatter(): return lambda obj: fmt(conversion(obj)) -class TemplateFormatter(StringFormatter): - """Read format_string from file""" - - def __init__(self, path, default=NONE, fmt=format): - with open(util.expand_path(path)) as fp: - format_string = fp.read() - StringFormatter.__init__(self, format_string, default, fmt) - - class ExpressionFormatter(): """Generate text by evaluating a Python expression""" @@ -229,6 +222,24 @@ class FStringFormatter(): self.format_map = util.compile_expression('f"""' + fstring + '"""') +class TemplateFormatter(StringFormatter): + """Read format_string from file""" + + def __init__(self, path, default=NONE, fmt=format): + with open(util.expand_path(path)) as fp: + format_string = fp.read() + StringFormatter.__init__(self, format_string, default, fmt) + + +class TemplateFStringFormatter(FStringFormatter): + """Read f-string from file""" + + def __init__(self, path, default=NONE, fmt=format): + with open(util.expand_path(path)) as fp: + format_string = fp.read() + FStringFormatter.__init__(self, format_string, default, fmt) + + def parse_field_name(field_name): first, rest = _string.formatter_field_name_split(field_name) funcs = [] diff --git a/test/test_formatter.py b/test/test_formatter.py index ee9b2491..c6e21a60 100644 --- a/test/test_formatter.py +++ b/test/test_formatter.py @@ -348,6 +348,27 @@ class TestFormatter(unittest.TestCase): self._run_test("\fF foo-'\"{a.upper()}\"'-bar", """foo-'"{}"'-bar""".format(self.kwdict["a"].upper())) + @unittest.skipIf(sys.hexversion < 0x3060000, "no fstring support") + def test_template_fstring(self): + with tempfile.TemporaryDirectory() as tmpdirname: + path1 = os.path.join(tmpdirname, "tpl1") + path2 = os.path.join(tmpdirname, "tpl2") + + with open(path1, "w") as fp: + fp.write("{a}") + fmt1 = formatter.parse("\fTF " + path1) + + with open(path2, "w") as fp: + fp.write("foo-'\"{a.upper()}\"'-bar") + fmt2 = formatter.parse("\fTF " + path2) + + self.assertEqual(fmt1.format_map(self.kwdict), self.kwdict["a"]) + self.assertEqual(fmt2.format_map(self.kwdict), + """foo-'"{}"'-bar""".format(self.kwdict["a"].upper())) + + with self.assertRaises(OSError): + formatter.parse("\fTF /") + def test_module(self): with tempfile.TemporaryDirectory() as tmpdirname: path = os.path.join(tmpdirname, "testmod.py")