From 5bc3657c593f9c29ab734e707870975b0ed86edf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20F=C3=A4hrmann?= Date: Thu, 14 Nov 2024 21:59:32 +0100 Subject: [PATCH] [util] implement 'compile_filter()' (#5262) https://github.com/mikf/gallery-dl/issues/5262#issuecomment-2477029728 allow (theoretically*) all filter expression statements to be a list of individual filters (*) except for 'filename' and 'directory' conditionals, as dict keys cannot be lists --- gallery_dl/job.py | 4 ++-- gallery_dl/path.py | 4 ++-- gallery_dl/util.py | 10 +++++++--- test/test_util.py | 9 +++++++++ 4 files changed, 20 insertions(+), 7 deletions(-) diff --git a/gallery_dl/job.py b/gallery_dl/job.py index 30801eec..f58cc05d 100644 --- a/gallery_dl/job.py +++ b/gallery_dl/job.py @@ -598,7 +598,7 @@ class DownloadJob(Job): skip_filter = cfg("skip-filter") if skip_filter: - self._skipftr = util.compile_expression(skip_filter) + self._skipftr = util.compile_filter(skip_filter) else: self._skipftr = None else: @@ -660,7 +660,7 @@ class DownloadJob(Job): expr = options.get("filter") if options else None if expr: - condition = util.compile_expression(expr) + condition = util.compile_filter(expr) for hook, callback in hooks.items(): self.hooks[hook].append(functools.partial( self._call_hook, callback, condition)) diff --git a/gallery_dl/path.py b/gallery_dl/path.py index d408a41a..f57b02e1 100644 --- a/gallery_dl/path.py +++ b/gallery_dl/path.py @@ -38,7 +38,7 @@ class PathFormat(): filename_fmt = extractor.filename_fmt elif isinstance(filename_fmt, dict): self.filename_conditions = [ - (util.compile_expression(expr), + (util.compile_filter(expr), formatter.parse(fmt, kwdefault).format_map) for expr, fmt in filename_fmt.items() if expr ] @@ -57,7 +57,7 @@ class PathFormat(): directory_fmt = extractor.directory_fmt elif isinstance(directory_fmt, dict): self.directory_conditions = [ - (util.compile_expression(expr), [ + (util.compile_filter(expr), [ formatter.parse(fmt, kwdefault).format_map for fmt in fmts ]) diff --git a/gallery_dl/util.py b/gallery_dl/util.py index 7c27c738..44ac22e2 100644 --- a/gallery_dl/util.py +++ b/gallery_dl/util.py @@ -734,6 +734,12 @@ def compile_expression_tryexcept(expr, name="", globals=None): compile_expression = compile_expression_tryexcept +def compile_filter(expr, name="", globals=None): + if not isinstance(expr, str): + expr = "(" + ") and (".join(expr) + ")" + return compile_expression(expr, name, globals) + + def import_file(path): """Import a Python module from a filesystem path""" path, name = os.path.split(path) @@ -964,10 +970,8 @@ class FilterPredicate(): """Predicate; True if evaluating the given expression returns True""" def __init__(self, expr, target="image"): - if not isinstance(expr, str): - expr = "(" + ") and (".join(expr) + ")" name = "<{} filter>".format(target) - self.expr = compile_expression(expr, name) + self.expr = compile_filter(expr, name) def __call__(self, _, kwdict): try: diff --git a/test/test_util.py b/test/test_util.py index e179f30b..0a9ff423 100644 --- a/test/test_util.py +++ b/test/test_util.py @@ -349,6 +349,15 @@ class TestCompileExpression(unittest.TestCase): with self.assertRaises(AttributeError): expr({"a": 2}) + def test_compile_filter(self): + expr = util.compile_filter("a + b * c") + self.assertEqual(expr({"a": 1, "b": 2, "c": 3}), 7) + self.assertEqual(expr({"a": 9, "b": 9, "c": 9}), 90) + + expr = util.compile_filter(["a % 2 == 0", "b % 3 == 0", "c % 5 == 0"]) + self.assertTrue(expr({"a": 4, "b": 6, "c": 10})) + self.assertFalse(expr({"a": 1, "b": 2, "c": 3})) + def test_custom_globals(self): value = {"v": "foobar"} result = "8843d7f92416211de9ebb963ff4ce28125932878"