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)
This commit is contained in:
@@ -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):
|
||||||
|
|||||||
Reference in New Issue
Block a user