From f7383a56f887694bbf6942733116bee7d88afe85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20F=C3=A4hrmann?= Date: Thu, 11 Jul 2024 01:16:06 +0200 Subject: [PATCH] wrap filters/conditionals in a try-except block MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit allows accessing undefined fields without exception or locals().get(…) but hides mistakes/typos/etc by evaluating to False without feedback performance loss compared to the previous version without try-except is negligible (~20ns for me) --- docs/configuration.rst | 12 ++++++++++++ gallery_dl/__init__.py | 5 +++++ gallery_dl/util.py | 19 ++++++++++++++++++- test/test_util.py | 14 +++++++------- 4 files changed, 42 insertions(+), 8 deletions(-) diff --git a/docs/configuration.rst b/docs/configuration.rst index b62ad33f..055e4e29 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -6085,6 +6085,18 @@ Description this cache. +filters-environment +------------------- +Type + ``bool`` +Default + ``true`` +Description + Evaluate filter expressions raising an exception as ``false`` + instead of aborting the current extractor run + by wrapping them in a `try`/`except` block. + + format-separator ---------------- Type diff --git a/gallery_dl/__init__.py b/gallery_dl/__init__.py index b4db17d6..8a23127f 100644 --- a/gallery_dl/__init__.py +++ b/gallery_dl/__init__.py @@ -105,6 +105,11 @@ def main(): output.ANSI = True + # filter environment + filterenv = config.get((), "filters-environment", True) + if not filterenv: + util.compile_expression = util.compile_expression_raw + # format string separator separator = config.get((), "format-separator") if separator: diff --git a/gallery_dl/util.py b/gallery_dl/util.py index e76ddf36..2f17dc21 100644 --- a/gallery_dl/util.py +++ b/gallery_dl/util.py @@ -616,11 +616,28 @@ else: Popen = subprocess.Popen -def compile_expression(expr, name="", globals=None): +def compile_expression_raw(expr, name="", globals=None): code_object = compile(expr, name, "eval") return functools.partial(eval, code_object, globals or GLOBALS) +def compile_expression_tryexcept(expr, name="", globals=None): + code_object = compile(expr, name, "eval") + + def _eval(locals=None, globals=(globals or GLOBALS), co=code_object): + try: + return eval(co, globals, locals) + except exception.GalleryDLException: + raise + except Exception: + return False + + return _eval + + +compile_expression = compile_expression_tryexcept + + def import_file(path): """Import a Python module from a filesystem path""" path, name = os.path.split(path) diff --git a/test/test_util.py b/test/test_util.py index 35e72473..dba54bba 100644 --- a/test/test_util.py +++ b/test/test_util.py @@ -134,19 +134,18 @@ class TestPredicate(unittest.TestCase): with self.assertRaises(SyntaxError): util.FilterPredicate("(") - with self.assertRaises(exception.FilterError): - util.FilterPredicate("a > 1")(url, {"a": None}) - - with self.assertRaises(exception.FilterError): - util.FilterPredicate("b > 1")(url, {"a": 2}) + self.assertFalse( + util.FilterPredicate("a > 1")(url, {"a": None})) + self.assertFalse( + util.FilterPredicate("b > 1")(url, {"a": 2})) pred = util.FilterPredicate(["a < 3", "b < 4", "c < 5"]) self.assertTrue(pred(url, {"a": 2, "b": 3, "c": 4})) self.assertFalse(pred(url, {"a": 3, "b": 3, "c": 4})) self.assertFalse(pred(url, {"a": 2, "b": 4, "c": 4})) self.assertFalse(pred(url, {"a": 2, "b": 3, "c": 5})) - with self.assertRaises(exception.FilterError): - pred(url, {"a": 2}) + + self.assertFalse(pred(url, {"a": 2})) def test_build_predicate(self): pred = util.build_predicate([]) @@ -445,6 +444,7 @@ class TestOther(unittest.TestCase): self.assertEqual(expr({"a": 1, "b": 2, "c": 3}), 7) self.assertEqual(expr({"a": 9, "b": 9, "c": 9}), 90) + expr = util.compile_expression_raw("a + b * c") with self.assertRaises(NameError): expr() with self.assertRaises(NameError):