##// END OF EJS Templates
Use DollarFormatter to fill in names in ! shell calls....
Thomas Kluyver -
Show More
@@ -73,7 +73,8 b' from IPython.utils.pickleshare import PickleShareDB'
73 73 from IPython.utils.process import system, getoutput
74 74 from IPython.utils.strdispatch import StrDispatch
75 75 from IPython.utils.syspathcontext import prepended_to_syspath
76 from IPython.utils.text import num_ini_spaces, format_screen, LSString, SList
76 from IPython.utils.text import (num_ini_spaces, format_screen, LSString, SList,
77 DollarFormatter)
77 78 from IPython.utils.traitlets import (Integer, CBool, CaselessStrEnum, Enum,
78 79 List, Unicode, Instance, Type)
79 80 from IPython.utils.warn import warn, error, fatal
@@ -2571,7 +2572,7 b' class InteractiveShell(SingletonConfigurable, Magic):'
2571 2572 # Utilities
2572 2573 #-------------------------------------------------------------------------
2573 2574
2574 def var_expand(self,cmd,depth=0):
2575 def var_expand(self, cmd, depth=0, formatter=DollarFormatter()):
2575 2576 """Expand python variables in a string.
2576 2577
2577 2578 The depth argument indicates how many frames above the caller should
@@ -2580,11 +2581,10 b' class InteractiveShell(SingletonConfigurable, Magic):'
2580 2581 The global namespace for expansion is always the user's interactive
2581 2582 namespace.
2582 2583 """
2583 res = ItplNS(cmd, self.user_ns, # globals
2584 # Skip our own frame in searching for locals:
2585 sys._getframe(depth+1).f_locals # locals
2586 )
2587 return py3compat.str_to_unicode(str(res), res.codec)
2584 ns = self.user_ns.copy()
2585 ns.update(sys._getframe(depth+1).f_locals)
2586 ns.pop('self', None)
2587 return formatter.format(cmd, **ns)
2588 2588
2589 2589 def mktempfile(self, data=None, prefix='ipython_edit_'):
2590 2590 """Make a new tempfile and return its filename.
@@ -45,7 +45,7 b' def test_columnize_long():'
45 45 nt.assert_equals(out, '\n'.join(items+['']))
46 46
47 47 def eval_formatter_check(f):
48 ns = dict(n=12, pi=math.pi, stuff='hello there', os=os)
48 ns = dict(n=12, pi=math.pi, stuff='hello there', os=os, u=u"cafΓ©", b="cafΓ©")
49 49 s = f.format("{n} {n//4} {stuff.split()[0]}", **ns)
50 50 nt.assert_equals(s, "12 3 hello")
51 51 s = f.format(' '.join(['{n//%i}'%i for i in range(1,8)]), **ns)
@@ -57,6 +57,12 b' def eval_formatter_check(f):'
57 57 s = f.format("{stuff!r}", **ns)
58 58 nt.assert_equals(s, repr(ns['stuff']))
59 59
60 # Check with unicode:
61 s = f.format("{u}", **ns)
62 nt.assert_equals(s, ns['u'])
63 # This decodes in a platform dependent manner, but it shouldn't error out
64 s = f.format("{b}", **ns)
65
60 66 nt.assert_raises(NameError, f.format, '{dne}', **ns)
61 67
62 68 def eval_formatter_slicing_check(f):
@@ -25,6 +25,7 b' import textwrap'
25 25 from string import Formatter
26 26
27 27 from IPython.external.path import path
28 from IPython.testing.skipdoctest import skip_doctest_py3
28 29 from IPython.utils import py3compat
29 30 from IPython.utils.io import nlprint
30 31 from IPython.utils.data import flatten
@@ -621,6 +622,7 b' class EvalFormatter(Formatter):'
621 622 v = eval(name, kwargs)
622 623 return v, name
623 624
625 @skip_doctest_py3
624 626 class FullEvalFormatter(Formatter):
625 627 """A String Formatter that allows evaluation of simple expressions.
626 628
@@ -635,13 +637,13 b' class FullEvalFormatter(Formatter):'
635 637
636 638 In [1]: f = FullEvalFormatter()
637 639 In [2]: f.format('{n//4}', n=8)
638 Out[2]: '2'
640 Out[2]: u'2'
639 641
640 642 In [3]: f.format('{list(range(5))[2:4]}')
641 Out[3]: '[2, 3]'
643 Out[3]: u'[2, 3]'
642 644
643 645 In [4]: f.format('{3*2}')
644 Out[4]: '6'
646 Out[4]: u'6'
645 647 """
646 648 # copied from Formatter._vformat with minor changes to allow eval
647 649 # and replace the format_spec code with slicing
@@ -675,8 +677,9 b' class FullEvalFormatter(Formatter):'
675 677 # format the object and append to the result
676 678 result.append(self.format_field(obj, ''))
677 679
678 return ''.join(result)
680 return u''.join(py3compat.cast_unicode(s) for s in result)
679 681
682 @skip_doctest_py3
680 683 class DollarFormatter(FullEvalFormatter):
681 684 """Formatter allowing Itpl style $foo replacement, for names and attribute
682 685 access only. Standard {foo} replacement also works, and allows full
@@ -686,13 +689,13 b' class DollarFormatter(FullEvalFormatter):'
686 689 --------
687 690 In [1]: f = DollarFormatter()
688 691 In [2]: f.format('{n//4}', n=8)
689 Out[2]: '2'
692 Out[2]: u'2'
690 693
691 694 In [3]: f.format('23 * 76 is $result', result=23*76)
692 Out[3]: '23 * 76 is 1748'
695 Out[3]: u'23 * 76 is 1748'
693 696
694 697 In [4]: f.format('$a or {b}', a=1, b=2)
695 Out[4]: '1 or 2'
698 Out[4]: u'1 or 2'
696 699 """
697 700 _dollar_pattern = re.compile("(.*)\$([\w\.]+)")
698 701 def parse(self, fmt_string):
@@ -703,7 +706,7 b' class DollarFormatter(FullEvalFormatter):'
703 706 continue_from = 0
704 707 for m in self._dollar_pattern.finditer(literal_txt):
705 708 new_txt, new_field = m.group(1,2)
706 yield (new_txt, new_field, "", "s")
709 yield (new_txt, new_field, "", None)
707 710 continue_from = m.end()
708 711
709 712 # Re-yield the {foo} style pattern
General Comments 0
You need to be logged in to leave comments. Login now