wrap filters/conditionals in a try-except block

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)
pull/5870/head
Mike Fährmann 2 months ago
parent c83c812a1e
commit f7383a56f8
No known key found for this signature in database
GPG Key ID: 5680CA389D365A88

@ -6085,6 +6085,18 @@ Description
this cache. 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 format-separator
---------------- ----------------
Type Type

@ -105,6 +105,11 @@ def main():
output.ANSI = True output.ANSI = True
# filter environment
filterenv = config.get((), "filters-environment", True)
if not filterenv:
util.compile_expression = util.compile_expression_raw
# format string separator # format string separator
separator = config.get((), "format-separator") separator = config.get((), "format-separator")
if separator: if separator:

@ -616,11 +616,28 @@ else:
Popen = subprocess.Popen Popen = subprocess.Popen
def compile_expression(expr, name="<expr>", globals=None): def compile_expression_raw(expr, name="<expr>", globals=None):
code_object = compile(expr, name, "eval") code_object = compile(expr, name, "eval")
return functools.partial(eval, code_object, globals or GLOBALS) return functools.partial(eval, code_object, globals or GLOBALS)
def compile_expression_tryexcept(expr, name="<expr>", 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): def import_file(path):
"""Import a Python module from a filesystem path""" """Import a Python module from a filesystem path"""
path, name = os.path.split(path) path, name = os.path.split(path)

@ -134,19 +134,18 @@ class TestPredicate(unittest.TestCase):
with self.assertRaises(SyntaxError): with self.assertRaises(SyntaxError):
util.FilterPredicate("(") util.FilterPredicate("(")
with self.assertRaises(exception.FilterError): self.assertFalse(
util.FilterPredicate("a > 1")(url, {"a": None}) util.FilterPredicate("a > 1")(url, {"a": None}))
self.assertFalse(
with self.assertRaises(exception.FilterError): util.FilterPredicate("b > 1")(url, {"a": 2}))
util.FilterPredicate("b > 1")(url, {"a": 2})
pred = util.FilterPredicate(["a < 3", "b < 4", "c < 5"]) pred = util.FilterPredicate(["a < 3", "b < 4", "c < 5"])
self.assertTrue(pred(url, {"a": 2, "b": 3, "c": 4})) 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": 3, "b": 3, "c": 4}))
self.assertFalse(pred(url, {"a": 2, "b": 4, "c": 4})) self.assertFalse(pred(url, {"a": 2, "b": 4, "c": 4}))
self.assertFalse(pred(url, {"a": 2, "b": 3, "c": 5})) 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): def test_build_predicate(self):
pred = util.build_predicate([]) 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": 1, "b": 2, "c": 3}), 7)
self.assertEqual(expr({"a": 9, "b": 9, "c": 9}), 90) self.assertEqual(expr({"a": 9, "b": 9, "c": 9}), 90)
expr = util.compile_expression_raw("a + b * c")
with self.assertRaises(NameError): with self.assertRaises(NameError):
expr() expr()
with self.assertRaises(NameError): with self.assertRaises(NameError):

Loading…
Cancel
Save