From c990bcfbc302ad6b13dfe4bd30c6a2a8394186a8 Mon Sep 17 00:00:00 2001 From: dieter Date: Sun, 5 Jul 2020 15:26:38 +0200 Subject: [PATCH 1/3] Improve `PathExpr` reusability; allow customizable use of builtins in path expressions --- CHANGES.rst | 3 ++- src/zope/tales/expressions.py | 13 +++++++++++-- src/zope/tales/tests/test_expressions.py | 22 ++++++++++++++++++++++ 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 64a7d92..308dc28 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,7 +5,8 @@ 5.0.3 (unreleased) ================== -- Nothing changed yet. +- Improve `PathExpr` reusability + Provide customizable support for the use of builtins in path expressions 5.0.2 (2020-03-27) diff --git a/src/zope/tales/expressions.py b/src/zope/tales/expressions.py index 10584b9..dd8980c 100644 --- a/src/zope/tales/expressions.py +++ b/src/zope/tales/expressions.py @@ -60,6 +60,8 @@ class SubPathExpr(object): Implementation of a single path expression. """ + ALLOWED_BUILTINS = {} + def __init__(self, path, traverser, engine): self._traverser = traverser self._engine = engine @@ -137,7 +139,12 @@ def _eval(self, econtext, if base == 'CONTEXTS' or not base: # Special base name ob = econtext.contexts else: - ob = vars[base] + try: + ob = vars[base] + except KeyError: + ob = self.ALLOWED_BUILTINS.get(base, _marker) + if ob is _marker: + raise if isinstance(ob, DeferWrapper): ob = ob() @@ -177,6 +184,8 @@ class PathExpr(object): 'nocall', ) + SUBEXPR_FACTORY = SubPathExpr + def __init__(self, name, expr, engine, traverser=simpleTraverse): self._s = expr self._name = name @@ -192,7 +201,7 @@ def __init__(self, name, expr, engine, traverser=simpleTraverse): add(engine.compile('|'.join(paths[i:]).lstrip())) self._hybrid = True break - add(SubPathExpr(path, traverser, engine)._eval) + add(self.SUBEXPR_FACTORY(path, traverser, engine)._eval) def _exists(self, econtext): for expr in self._subexprs: diff --git a/src/zope/tales/tests/test_expressions.py b/src/zope/tales/tests/test_expressions.py index 9158d7b..2369468 100644 --- a/src/zope/tales/tests/test_expressions.py +++ b/src/zope/tales/tests/test_expressions.py @@ -387,6 +387,28 @@ def test_bad_initial_name_subexpr(self): "Invalid variable name" ) + def test_builtins_in_path(self): + from ..tales import ExpressionEngine + from ..expressions import PathExpr, SubPathExpr + + class MySubPathExpr(SubPathExpr): + ALLOWED_BUILTINS = dict(True=True, False=False) + + class MyPathExpr(PathExpr): + SUBEXPR_FACTORY = MySubPathExpr + + engine = ExpressionEngine() + for pt in MyPathExpr._default_type_names: + engine.registerType(pt, MyPathExpr) + + def eval(expr): + return engine.compile(expr)(self.context) + + self.assertTrue(eval("True")) + self.assertFalse(eval("False")) + with self.assertRaises(KeyError): + eval("None") + class FunctionTests(ExpressionTestBase): From a09ffdbd2bbfb59a1c2d737c43aba2427f367d16 Mon Sep 17 00:00:00 2001 From: dieter Date: Sun, 5 Jul 2020 15:53:09 +0200 Subject: [PATCH 2/3] Python 3 compatibility; test improvement --- src/zope/tales/tests/test_expressions.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/zope/tales/tests/test_expressions.py b/src/zope/tales/tests/test_expressions.py index 2369468..6ff8f52 100644 --- a/src/zope/tales/tests/test_expressions.py +++ b/src/zope/tales/tests/test_expressions.py @@ -392,7 +392,7 @@ def test_builtins_in_path(self): from ..expressions import PathExpr, SubPathExpr class MySubPathExpr(SubPathExpr): - ALLOWED_BUILTINS = dict(True=True, False=False) + ALLOWED_BUILTINS = {'True':True, 'False':False, 'x':None} class MyPathExpr(PathExpr): SUBEXPR_FACTORY = MySubPathExpr @@ -408,6 +408,7 @@ def eval(expr): self.assertFalse(eval("False")) with self.assertRaises(KeyError): eval("None") + self.assertIsNotNone(eval("x")) # variable before builtin class FunctionTests(ExpressionTestBase): From 85e911aaa1991a06d6807f8f352d4a3a24090338 Mon Sep 17 00:00:00 2001 From: dieter Date: Sun, 5 Jul 2020 15:56:26 +0200 Subject: [PATCH 3/3] make flake8 happy --- src/zope/tales/tests/test_expressions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zope/tales/tests/test_expressions.py b/src/zope/tales/tests/test_expressions.py index 6ff8f52..1653c29 100644 --- a/src/zope/tales/tests/test_expressions.py +++ b/src/zope/tales/tests/test_expressions.py @@ -392,7 +392,7 @@ def test_builtins_in_path(self): from ..expressions import PathExpr, SubPathExpr class MySubPathExpr(SubPathExpr): - ALLOWED_BUILTINS = {'True':True, 'False':False, 'x':None} + ALLOWED_BUILTINS = {'True': True, 'False': False, 'x': None} class MyPathExpr(PathExpr): SUBEXPR_FACTORY = MySubPathExpr