# HG changeset patch # User mgood # Date 1156459327 0 # Node ID d7c0a7d65783bbba72bf82063e727cf863e6a5b7 # Parent a593d57f478f42eeeb67deba2d366f4ed0417c12 Implemented support for generator expressions (fixes #16) diff --git a/markup/eval.py b/markup/eval.py --- a/markup/eval.py +++ b/markup/eval.py @@ -331,6 +331,26 @@ node.test = self.visit(node.test, *args, **kwargs) return node + def visitGenExpr(self, node, *args, **kwargs): + node.code = self.visit(node.code, *args, **kwargs) + node.filename = '' # workaround for bug in pycodegen + return node + + def visitGenExprFor(self, node, *args, **kwargs): + node.assign = self.visit(node.assign, *args, **kwargs) + node.iter = self.visit(node.iter, *args, **kwargs) + node.ifs = map(lambda x: self.visit(x, *args, **kwargs), node.ifs) + return node + + def visitGenExprIf(self, node, *args, **kwargs): + node.test = self.visit(node.test, locals_=True, *args, **kwargs) + return node + + def visitGenExprInner(self, node, *args, **kwargs): + node.expr = self.visit(node.expr, locals_=True, *args, **kwargs) + node.quals = map(lambda x: self.visit(x, *args, **kwargs), node.quals) + return node + class ExpressionASTTransformer(ASTTransformer): """Concrete AST transformer that implements the AST transformations needed diff --git a/markup/tests/eval.py b/markup/tests/eval.py --- a/markup/tests/eval.py +++ b/markup/tests/eval.py @@ -240,6 +240,30 @@ expr = Expression("[i['name'] for i in items if i['value'] > 1]") self.assertEqual(['b'], expr.evaluate({'items': items})) + # generator expressions only supported in Python 2.4 and up + if sys.version_info >= (2, 4): + def test_generator_expression(self): + expr = Expression("list(n for n in numbers if n < 2)") + self.assertEqual([0, 1], expr.evaluate({'numbers': range(5)})) + + expr = Expression("list((i, n + 1) for i, n in enumerate(numbers))") + self.assertEqual([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)], + expr.evaluate({'numbers': range(5)})) + + expr = Expression("list(offset + n for n in numbers)") + self.assertEqual([2, 3, 4, 5, 6], + expr.evaluate({'numbers': range(5), 'offset': 2})) + + def test_generator_expression_with_getattr(self): + items = [{'name': 'a', 'value': 1}, {'name': 'b', 'value': 2}] + expr = Expression("list(i.name for i in items if i.value > 1)") + self.assertEqual(['b'], expr.evaluate({'items': items})) + + def test_generator_expression_with_getitem(self): + items = [{'name': 'a', 'value': 1}, {'name': 'b', 'value': 2}] + expr = Expression("list(i['name'] for i in items if i['value'] > 1)") + self.assertEqual(['b'], expr.evaluate({'items': items})) + def test_error_access_undefined(self): expr = Expression("nothing", filename='index.html', lineno=50) self.assertEqual(Undefined, type(expr.evaluate({})))