diff --git a/gallery_dl/formatter.py b/gallery_dl/formatter.py index 34ede812..7a49049b 100644 --- a/gallery_dl/formatter.py +++ b/gallery_dl/formatter.py @@ -211,14 +211,38 @@ class FStringFormatter(): self.format_map = util.compile_expression(f'f"""{fstring}"""') +def _init_jinja(): + import jinja2 + from . import config + + if opts := config.get((), "jinja"): + JinjaFormatter.env = env = jinja2.Environment( + **opts.get("environment") or {}) + else: + JinjaFormatter.env = jinja2.Environment() + return + + if policies := opts.get("policies"): + env.policies.update(policies) + + if path := opts.get("filters"): + module = util.import_file(path).__dict__ + env.filters.update( + module["__filters__"] if "__filters__" in module else module) + + if path := opts.get("tests"): + module = util.import_file(path).__dict__ + env.tests.update( + module["__tests__"] if "__tests__" in module else module) + + class JinjaFormatter(): """Generate text by evaluating a Jinja template string""" env = None def __init__(self, source, default=NONE, fmt=None): if self.env is None: - import jinja2 - JinjaFormatter.env = jinja2.Environment() + _init_jinja() self.format_map = self.env.from_string(source).render diff --git a/test/test_formatter.py b/test/test_formatter.py index 4a5a7abb..3305983b 100644 --- a/test/test_formatter.py +++ b/test/test_formatter.py @@ -15,7 +15,7 @@ import datetime import tempfile sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) -from gallery_dl import formatter, text, util # noqa E402 +from gallery_dl import formatter, text, util, config # noqa E402 try: import jinja2 @@ -25,6 +25,9 @@ except ImportError: class TestFormatter(unittest.TestCase): + def tearDown(self): + config.clear() + kwdict = { "a": "hElLo wOrLd", "b": "äöü", @@ -487,6 +490,8 @@ class TestFormatter(unittest.TestCase): @unittest.skipIf(jinja2 is None, "no jinja2") def test_jinja(self): + formatter.JinjaFormatter.env = None + self._run_test("\fJ {{a}}", self.kwdict["a"]) self._run_test("\fJ {{name}}{{name}} {{a}}", "{}{} {}".format( self.kwdict["name"], self.kwdict["name"], self.kwdict["a"])) @@ -495,6 +500,8 @@ class TestFormatter(unittest.TestCase): @unittest.skipIf(jinja2 is None, "no jinja2") def test_template_jinja(self): + formatter.JinjaFormatter.env = None + with tempfile.TemporaryDirectory() as tmpdirname: path1 = os.path.join(tmpdirname, "tpl1") path2 = os.path.join(tmpdirname, "tpl2") @@ -514,6 +521,57 @@ class TestFormatter(unittest.TestCase): with self.assertRaises(OSError): formatter.parse("\fTJ /") + @unittest.skipIf(jinja2 is None, "no jinja2") + def test_template_jinja_opts(self): + formatter.JinjaFormatter.env = None + + with tempfile.TemporaryDirectory() as tmpdirname: + path_filters = os.path.join(tmpdirname, "jinja_filters.py") + path_template = os.path.join(tmpdirname, "jinja_template.txt") + + config.set((), "jinja", { + "environment": { + "variable_start_string": "(((", + "variable_end_string" : ")))", + "keep_trailing_newline": True, + }, + "filters": path_filters, + }) + + with open(path_filters, "w") as fp: + fp.write(r""" +import re + +def datetime_format(value, format="%H:%M %d-%m-%y"): + return value.strftime(format) + +def sanitize(value): + return re.sub(r"\s+", " ", value.strip()) + +__filters__ = { + "dt_fmt": datetime_format, + "sanitize_whitespace": sanitize, +} +""") + + with open(path_template, "w") as fp: + fp.write("""\ +Present Day is ((( dt | dt_fmt("%B %d, %Y") ))) +Present Time is ((( dt | dt_fmt("%H:%M:%S") ))) + +Hello ((( s | sanitize_whitespace ))). +I hope there is enough "(((S|sanitize_whitespace)))" for you. +""") + fmt = formatter.parse("\fTJ " + path_template) + + self.assertEqual(fmt.format_map(self.kwdict), """\ +Present Day is January 01, 2010 +Present Time is 00:00:00 + +Hello SPACE. +I hope there is enough "S P A C E" for you. +""") + def test_module(self): with tempfile.TemporaryDirectory() as tmpdirname: path = os.path.join(tmpdirname, "testmod.py")