changeset 118:c392d38694d9 trunk

Add basic support for using `lambda`s in expressions. Closes #21. (Not sure about default arguments, need a test case).
author cmlenz
date Tue, 01 Aug 2006 22:34:39 +0000
parents f96b04b0db96
children cc2aee07f53b
files markup/eval.py markup/tests/eval.py
diffstat 2 files changed, 31 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/markup/eval.py
+++ b/markup/eval.py
@@ -82,7 +82,10 @@
         @param data: a mapping containing the data to evaluate against
         @return: the result of the evaluation
         """
-        retval = eval(self.code)
+        retval = eval(self.code, {'data': data,
+                                  '_lookup_name': _lookup_name,
+                                  '_lookup_attr': _lookup_attr,
+                                  '_lookup_item': _lookup_item})
         if callable(retval):
             retval = retval()
         return retval
@@ -112,7 +115,7 @@
         val = getattr(__builtin__, name, None)
     return val
 
-def _lookup_attribute(data, obj, key):
+def _lookup_attr(data, obj, key):
     if hasattr(obj, key):
         return getattr(obj, key)
     try:
@@ -165,6 +168,11 @@
                                    node.dstar_args)
         return node
 
+    def visitLambda(self, node, *args, **kwargs):
+        node.code = self.visit(node.code, *args, **kwargs)
+        node.filename = '<string>' # workaround for bug in pycodegen
+        return node
+
     def visitGetattr(self, node, *args, **kwargs):
         node.expr = self.visit(node.expr, *args, **kwargs)
         return node
@@ -248,11 +256,19 @@
     """
 
     def visitGetattr(self, node, *args, **kwargs):
-        return ast.CallFunc(ast.Name('_lookup_attribute'),
+        return ast.CallFunc(ast.Name('_lookup_attr'),
             [ast.Name('data'), self.visit(node.expr, *args, **kwargs),
              ast.Const(node.attrname)]
         )
 
+    def visitLambda(self, node, *args, **kwargs):
+        old_lookup_locals = kwargs.get('lookup_locals', False)
+        kwargs['lookup_locals'] = True
+        node.code = self.visit(node.code, *args, **kwargs)
+        node.filename = '<string>' # workaround for bug in pycodegen
+        kwargs['lookup_locals'] = old_lookup_locals
+        return node
+
     def visitListComp(self, node, *args, **kwargs):
         old_lookup_locals = kwargs.get('lookup_locals', False)
         kwargs['lookup_locals'] = True
--- a/markup/tests/eval.py
+++ b/markup/tests/eval.py
@@ -190,6 +190,18 @@
         self.assertEqual('BAR', Expression("foo.upper").evaluate(data))
         data = {'foo': {'bar': range(42)}}
 
+    def test_lambda(self):
+        # Define a custom `sorted` function cause the builtin isn't available
+        # on Python 2.3
+        def sorted(items, compfunc):
+            items.sort(compfunc)
+            return items
+        data = {'items': [{'name': 'b', 'value': 0}, {'name': 'a', 'value': 1}],
+                'sorted': sorted}
+        expr = Expression("sorted(items, lambda a, b: cmp(a.name, b.name))")
+        self.assertEqual([{'name': 'a', 'value': 1}, {'name': 'b', 'value': 0}],
+                         expr.evaluate(data))
+
     def test_list_comprehension(self):
         expr = Expression("[n for n in numbers if n < 2]")
         self.assertEqual([0, 1], expr.evaluate({'numbers': range(5)}))
Copyright (C) 2012-2017 Edgewall Software