##// END OF EJS Templates
update EvalFormatter to allow arbitrary expressions...
MinRK -
Show More
@@ -13,6 +13,7 b''
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 import os
15 import os
16 import math
16
17
17 import nose.tools as nt
18 import nose.tools as nt
18
19
@@ -42,3 +43,45 b' def test_columnize_long():'
42 items = [l*size for l in 'abc']
43 items = [l*size for l in 'abc']
43 out = text.columnize(items, displaywidth=size-1)
44 out = text.columnize(items, displaywidth=size-1)
44 nt.assert_equals(out, '\n'.join(items+['']))
45 nt.assert_equals(out, '\n'.join(items+['']))
46
47 def test_eval_formatter():
48 f = text.EvalFormatter()
49 ns = dict(n=12, pi=math.pi, stuff='hello there', os=os)
50 s = f.format("{n} {n/4} {stuff.split()[0]}", **ns)
51 nt.assert_equals(s, "12 3 hello")
52 s = f.format(' '.join(['{n//%i}'%i for i in range(1,8)]), **ns)
53 nt.assert_equals(s, "12 6 4 3 2 2 1")
54 s = f.format('{[n//i for i in range(1,8)]}', **ns)
55 nt.assert_equals(s, "[12, 6, 4, 3, 2, 2, 1]")
56 s = f.format("{stuff!s}", **ns)
57 nt.assert_equals(s, ns['stuff'])
58 s = f.format("{stuff!r}", **ns)
59 nt.assert_equals(s, repr(ns['stuff']))
60
61 nt.assert_raises(NameError, f.format, '{dne}', **ns)
62
63
64 def test_eval_formatter_slicing():
65 f = text.EvalFormatter()
66 f.allow_slicing = True
67 ns = dict(n=12, pi=math.pi, stuff='hello there', os=os)
68 s = f.format(" {stuff.split()[:]} ", **ns)
69 nt.assert_equals(s, " ['hello', 'there'] ")
70 s = f.format(" {stuff.split()[::-1]} ", **ns)
71 nt.assert_equals(s, " ['there', 'hello'] ")
72 s = f.format("{stuff[::2]}", **ns)
73 nt.assert_equals(s, ns['stuff'][::2])
74
75 nt.assert_raises(SyntaxError, f.format, "{n:x}", **ns)
76
77
78 def test_eval_formatter_no_slicing():
79 f = text.EvalFormatter()
80 f.allow_slicing = False
81 ns = dict(n=12, pi=math.pi, stuff='hello there', os=os)
82
83 s = f.format('{n:x} {pi**2:+f}', **ns)
84 nt.assert_equals(s, "c +9.869604")
85
86 nt.assert_raises(SyntaxError, f.format, "{a[:]}")
87
@@ -597,18 +597,47 b' class EvalFormatter(Formatter):'
597 Out[4]: '6'
597 Out[4]: '6'
598 """
598 """
599
599
600 def get_value(self, key, args, kwargs):
600 # should we allow slicing by disabling the format_spec feature?
601 if isinstance(key, (int, long)):
601 allow_slicing = True
602 return args[key]
602
603 elif key in kwargs:
603 # copied from Formatter._vformat with minor changes to allow eval
604 return kwargs[key]
604 # and replace the format_spec code with slicing
605 else:
605 def _vformat(self, format_string, args, kwargs, used_args, recursion_depth):
606 # evaluate the expression using kwargs as namespace
606 if recursion_depth < 0:
607 try:
607 raise ValueError('Max string recursion exceeded')
608 return eval(key, kwargs)
608 result = []
609 except Exception:
609 for literal_text, field_name, format_spec, conversion in \
610 # classify all bad expressions as key errors
610 self.parse(format_string):
611 raise KeyError(key)
611
612 # output the literal text
613 if literal_text:
614 result.append(literal_text)
615
616 # if there's a field, output it
617 if field_name is not None:
618 # this is some markup, find the object and do
619 # the formatting
620
621 if self.allow_slicing and format_spec:
622 # override format spec, to allow slicing:
623 field_name = ':'.join([field_name, format_spec])
624 format_spec = ''
625
626 # eval the contents of the field for the object
627 # to be formatted
628 obj = eval(field_name, kwargs)
629
630 # do any conversion on the resulting object
631 obj = self.convert_field(obj, conversion)
632
633 # expand the format spec, if needed
634 format_spec = self._vformat(format_spec, args, kwargs,
635 used_args, recursion_depth-1)
636
637 # format the object and append to the result
638 result.append(self.format_field(obj, format_spec))
639
640 return ''.join(result)
612
641
613
642
614 def columnize(items, separator=' ', displaywidth=80):
643 def columnize(items, separator=' ', displaywidth=80):
General Comments 0
You need to be logged in to leave comments. Login now