comparison genshi/template/tests/eval.py @ 917:bcaa91c42b97 experimental-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 Sun, 24 Oct 2010 22:39:08 +0000
parents 85e4678337cf
children
comparison
equal deleted inserted replaced
916:872726bac135 917:bcaa91c42b97
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
Copyright (C) 2012-2017 Edgewall Software