Mercurial > genshi > mirror
comparison genshi/template/tests/eval.py @ 934:31bbb6f9e87b trunk
Merge r1142 from py3k:
add support for python 3 to genshi.template expression evaluator:
* add support for python 3 AST:
* AST for raise has changed in Python 3.
* Python 3 adds AST nodes for individual arguments and Bytes.
* use genshi.compat functions for dealing with code objects.
* do not coerce byte strings to unicode in Python 3 ASTTransformer.
* replace doctests that reply on exception names with uglier but more compatible try:.. except:.. doctest
* handle filename preferences of Python 2 and 3 (2 prefers bytes, 3 prefers unicode).
* ifilter is gone from itertools in Python 3 so use repeat for tests instead.
author | hodgestar |
---|---|
date | Fri, 18 Mar 2011 09:15:29 +0000 |
parents | 64f04a2c5e66 |
children | 19ac5d8fd96c |
comparison
equal
deleted
inserted
replaced
933:1e8c33345e52 | 934:31bbb6f9e87b |
---|---|
12 # history and logs, available at http://genshi.edgewall.org/log/. | 12 # history and logs, available at http://genshi.edgewall.org/log/. |
13 | 13 |
14 import doctest | 14 import doctest |
15 import os | 15 import os |
16 import pickle | 16 import pickle |
17 from StringIO import StringIO | |
18 import sys | 17 import sys |
19 from tempfile import mkstemp | 18 from tempfile import mkstemp |
20 import unittest | 19 import unittest |
21 | 20 |
22 from genshi.core import Markup | 21 from genshi.core import Markup |
23 from genshi.template.base import Context | 22 from genshi.template.base import Context |
24 from genshi.template.eval import Expression, Suite, Undefined, UndefinedError, \ | 23 from genshi.template.eval import Expression, Suite, Undefined, UndefinedError, \ |
25 UNDEFINED | 24 UNDEFINED |
25 from genshi.compat import BytesIO, IS_PYTHON2, wrapped_bytes | |
26 | 26 |
27 | 27 |
28 class ExpressionTestCase(unittest.TestCase): | 28 class ExpressionTestCase(unittest.TestCase): |
29 | 29 |
30 def test_eq(self): | 30 def test_eq(self): |
37 self.assertEqual(hash(expr), hash(Expression('x,y'))) | 37 self.assertEqual(hash(expr), hash(Expression('x,y'))) |
38 self.assertNotEqual(hash(expr), hash(Expression('y, x'))) | 38 self.assertNotEqual(hash(expr), hash(Expression('y, x'))) |
39 | 39 |
40 def test_pickle(self): | 40 def test_pickle(self): |
41 expr = Expression('1 < 2') | 41 expr = Expression('1 < 2') |
42 buf = StringIO() | 42 buf = BytesIO() |
43 pickle.dump(expr, buf, 2) | 43 pickle.dump(expr, buf, 2) |
44 buf.seek(0) | 44 buf.seek(0) |
45 unpickled = pickle.load(buf) | 45 unpickled = pickle.load(buf) |
46 assert unpickled.evaluate({}) is True | 46 assert unpickled.evaluate({}) is True |
47 | 47 |
56 self.assertEqual(expr.evaluate({}), Markup) | 56 self.assertEqual(expr.evaluate({}), Markup) |
57 | 57 |
58 def test_str_literal(self): | 58 def test_str_literal(self): |
59 self.assertEqual('foo', Expression('"foo"').evaluate({})) | 59 self.assertEqual('foo', Expression('"foo"').evaluate({})) |
60 self.assertEqual('foo', Expression('"""foo"""').evaluate({})) | 60 self.assertEqual('foo', Expression('"""foo"""').evaluate({})) |
61 self.assertEqual('foo', Expression("'foo'").evaluate({})) | 61 self.assertEqual(u'foo'.encode('utf-8'), |
62 Expression(wrapped_bytes("b'foo'")).evaluate({})) | |
62 self.assertEqual('foo', Expression("'''foo'''").evaluate({})) | 63 self.assertEqual('foo', Expression("'''foo'''").evaluate({})) |
63 self.assertEqual('foo', Expression("u'foo'").evaluate({})) | 64 self.assertEqual('foo', Expression("u'foo'").evaluate({})) |
64 self.assertEqual('foo', Expression("r'foo'").evaluate({})) | 65 self.assertEqual('foo', Expression("r'foo'").evaluate({})) |
65 | 66 |
66 def test_str_literal_non_ascii(self): | 67 def test_str_literal_non_ascii(self): |
67 expr = Expression(u"u'\xfe'") | 68 expr = Expression(u"u'\xfe'") |
68 self.assertEqual(u'þ', expr.evaluate({})) | 69 self.assertEqual(u'þ', expr.evaluate({})) |
69 expr = Expression("u'\xfe'") | 70 expr = Expression("u'\xfe'") |
70 self.assertEqual(u'þ', expr.evaluate({})) | 71 self.assertEqual(u'þ', expr.evaluate({})) |
71 expr = Expression("'\xc3\xbe'") | 72 # On Python2 strings are converted to unicode if they contained |
72 self.assertEqual(u'þ', expr.evaluate({})) | 73 # non-ASCII characters. |
74 # On Py3k, we have no need to do this as non-prefixed strings aren't | |
75 # raw. | |
76 expr = Expression(wrapped_bytes(r"b'\xc3\xbe'")) | |
77 if IS_PYTHON2: | |
78 self.assertEqual(u'þ', expr.evaluate({})) | |
79 else: | |
80 self.assertEqual(u'þ'.encode('utf-8'), expr.evaluate({})) | |
73 | 81 |
74 def test_num_literal(self): | 82 def test_num_literal(self): |
75 self.assertEqual(42, Expression("42").evaluate({})) | 83 self.assertEqual(42, Expression("42").evaluate({})) |
76 self.assertEqual(42L, Expression("42L").evaluate({})) | 84 if IS_PYTHON2: |
85 self.assertEqual(42L, Expression("42L").evaluate({})) | |
77 self.assertEqual(.42, Expression(".42").evaluate({})) | 86 self.assertEqual(.42, Expression(".42").evaluate({})) |
78 self.assertEqual(07, Expression("07").evaluate({})) | 87 if IS_PYTHON2: |
88 self.assertEqual(07, Expression("07").evaluate({})) | |
79 self.assertEqual(0xF2, Expression("0xF2").evaluate({})) | 89 self.assertEqual(0xF2, Expression("0xF2").evaluate({})) |
80 self.assertEqual(0XF2, Expression("0XF2").evaluate({})) | 90 self.assertEqual(0XF2, Expression("0XF2").evaluate({})) |
81 | 91 |
82 def test_dict_literal(self): | 92 def test_dict_literal(self): |
83 self.assertEqual({}, Expression("{}").evaluate({})) | 93 self.assertEqual({}, Expression("{}").evaluate({})) |
244 self.assertEqual(42, expr.evaluate({'foo': foo, 'bar': {"x": 42}})) | 254 self.assertEqual(42, expr.evaluate({'foo': foo, 'bar': {"x": 42}})) |
245 | 255 |
246 def test_lambda(self): | 256 def test_lambda(self): |
247 data = {'items': range(5)} | 257 data = {'items': range(5)} |
248 expr = Expression("filter(lambda x: x > 2, items)") | 258 expr = Expression("filter(lambda x: x > 2, items)") |
249 self.assertEqual([3, 4], expr.evaluate(data)) | 259 self.assertEqual([3, 4], list(expr.evaluate(data))) |
250 | 260 |
251 def test_lambda_tuple_arg(self): | 261 def test_lambda_tuple_arg(self): |
262 # This syntax goes away in Python 3 | |
263 if not IS_PYTHON2: | |
264 return | |
252 data = {'items': [(1, 2), (2, 1)]} | 265 data = {'items': [(1, 2), (2, 1)]} |
253 expr = Expression("filter(lambda (x, y): x > y, items)") | 266 expr = Expression("filter(lambda (x, y): x > y, items)") |
254 self.assertEqual([(2, 1)], expr.evaluate(data)) | 267 self.assertEqual([(2, 1)], list(expr.evaluate(data))) |
255 | 268 |
256 def test_list_comprehension(self): | 269 def test_list_comprehension(self): |
257 expr = Expression("[n for n in numbers if n < 2]") | 270 expr = Expression("[n for n in numbers if n < 2]") |
258 self.assertEqual([0, 1], expr.evaluate({'numbers': range(5)})) | 271 self.assertEqual([0, 1], expr.evaluate({'numbers': range(5)})) |
259 | 272 |
468 | 481 |
469 class SuiteTestCase(unittest.TestCase): | 482 class SuiteTestCase(unittest.TestCase): |
470 | 483 |
471 def test_pickle(self): | 484 def test_pickle(self): |
472 suite = Suite('foo = 42') | 485 suite = Suite('foo = 42') |
473 buf = StringIO() | 486 buf = BytesIO() |
474 pickle.dump(suite, buf, 2) | 487 pickle.dump(suite, buf, 2) |
475 buf.seek(0) | 488 buf.seek(0) |
476 unpickled = pickle.load(buf) | 489 unpickled = pickle.load(buf) |
477 data = {} | 490 data = {} |
478 unpickled.execute(data) | 491 unpickled.execute(data) |
643 data = {} | 656 data = {} |
644 suite.execute(data) | 657 suite.execute(data) |
645 assert 'plain' in data | 658 assert 'plain' in data |
646 | 659 |
647 def test_import(self): | 660 def test_import(self): |
648 suite = Suite("from itertools import ifilter") | 661 suite = Suite("from itertools import repeat") |
649 data = {} | 662 data = {} |
650 suite.execute(data) | 663 suite.execute(data) |
651 assert 'ifilter' in data | 664 assert 'repeat' in data |
652 | 665 |
653 def test_import_star(self): | 666 def test_import_star(self): |
654 suite = Suite("from itertools import *") | 667 suite = Suite("from itertools import *") |
655 data = Context() | 668 data = Context() |
656 suite.execute(data) | 669 suite.execute(data) |
657 assert 'ifilter' in data | 670 assert 'repeat' in data |
658 | 671 |
659 def test_import_in_def(self): | 672 def test_import_in_def(self): |
660 suite = Suite("""def fun(): | 673 suite = Suite("""def fun(): |
661 from itertools import ifilter | 674 from itertools import repeat |
662 return ifilter(None, range(3)) | 675 return repeat(1, 3) |
663 """) | 676 """) |
664 data = Context() | 677 data = Context() |
665 suite.execute(data) | 678 suite.execute(data) |
666 assert 'ifilter' not in data | 679 assert 'repeat' not in data |
667 self.assertEqual([1, 2], list(data['fun']())) | 680 self.assertEqual([1, 1, 1], list(data['fun']())) |
668 | 681 |
669 def test_for(self): | 682 def test_for(self): |
670 suite = Suite("""x = [] | 683 suite = Suite("""x = [] |
671 for i in range(3): | 684 for i in range(3): |
672 x.append(i**2) | 685 x.append(i**2) |
764 d = {"k": "bar"} | 777 d = {"k": "bar"} |
765 suite.execute({"d": d}) | 778 suite.execute({"d": d}) |
766 self.assertEqual("foo", d["k"]) | 779 self.assertEqual("foo", d["k"]) |
767 | 780 |
768 def test_exec(self): | 781 def test_exec(self): |
769 suite = Suite("x = 1; exec d['k']; assert x == 42, x") | 782 suite = Suite("x = 1; exec(d['k']); assert x == 42, x") |
770 suite.execute({"d": {"k": "x = 42"}}) | 783 suite.execute({"d": {"k": "x = 42"}}) |
771 | 784 |
772 def test_return(self): | 785 def test_return(self): |
773 suite = Suite(""" | 786 suite = Suite(""" |
774 def f(): | 787 def f(): |
826 finally: | 839 finally: |
827 os.remove(path) | 840 os.remove(path) |
828 | 841 |
829 def test_yield_expression(self): | 842 def test_yield_expression(self): |
830 d = {} | 843 d = {} |
831 suite = Suite("""results = [] | 844 suite = Suite("""from genshi.compat import next |
845 results = [] | |
832 def counter(maximum): | 846 def counter(maximum): |
833 i = 0 | 847 i = 0 |
834 while i < maximum: | 848 while i < maximum: |
835 val = (yield i) | 849 val = (yield i) |
836 if val is not None: | 850 if val is not None: |
837 i = val | 851 i = val |
838 else: | 852 else: |
839 i += 1 | 853 i += 1 |
840 it = counter(5) | 854 it = counter(5) |
841 results.append(it.next()) | 855 results.append(next(it)) |
842 results.append(it.send(3)) | 856 results.append(it.send(3)) |
843 results.append(it.next()) | 857 results.append(next(it)) |
844 """) | 858 """) |
845 suite.execute(d) | 859 suite.execute(d) |
846 self.assertEqual([0, 3, 4], d['results']) | 860 self.assertEqual([0, 3, 4], d['results']) |
847 | 861 |
848 | 862 |