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