# HG changeset patch # User cmlenz # Date 1154471679 0 # Node ID 226613431921df9fe30972609dcc72fd0e013d66 # Parent e51b81f1b5d5c1363974957e7a5c9514e1aa26a5 Add basic support for using `lambda`s in expressions. Closes #21. (Not sure about default arguments, need a test case). diff --git a/markup/eval.py b/markup/eval.py --- 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 = '' # 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 = '' # 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 diff --git a/markup/tests/eval.py b/markup/tests/eval.py --- 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)}))