##// END OF EJS Templates
ipy_profile_sh now has "depth" in the monkeypatch lambda for var_expand
vivainio -
Show More
@@ -1,182 +1,183 b''
1 1 """Shell mode for IPython.
2 2
3 3 Start ipython in shell mode by invoking "ipython -p sh"
4 4
5 5 (the old version, "ipython -p pysh" still works but this is the more "modern"
6 6 shell mode and is recommended for users who don't care about pysh-mode
7 7 compatibility)
8 8 """
9 9
10 10 from IPython import ipapi
11 11 import os,textwrap
12 12
13 13 # The import below effectively obsoletes your old-style ipythonrc[.ini],
14 14 # so consider yourself warned!
15 15
16 16 import ipy_defaults
17 17
18 18 def main():
19 19 ip = ipapi.get()
20 20 o = ip.options
21 21 # autocall to "full" mode (smart mode is default, I like full mode)
22 22
23 23 o.autocall = 2
24 24
25 25 # Jason Orendorff's path class is handy to have in user namespace
26 26 # if you are doing shell-like stuff
27 27 try:
28 28 ip.ex("from path import path" )
29 29 except ImportError:
30 30 pass
31 31
32 32 ip.ex('import os')
33 33 ip.ex("def up(): os.chdir('..')")
34 34
35 35 # Get pysh-like prompt for all profiles.
36 36
37 37 o.prompt_in1= '\C_LightBlue[\C_LightCyan\Y1\C_LightBlue]\C_Green|\#> '
38 38 o.prompt_in2= '\C_Green|\C_LightGreen\D\C_Green> '
39 39 o.prompt_out= '<\#> '
40 40
41 41 from IPython import Release
42 42
43 43 import sys
44 44 # I like my banner minimal.
45 45 o.banner = "Py %s IPy %s\n" % (sys.version.split('\n')[0],Release.version)
46 46
47 47 # make 'd' an alias for ls -F
48 48
49 49 ip.magic('alias d ls -F --color=auto')
50 50
51 51 # Make available all system commands through "rehashing" immediately.
52 52 # You can comment these lines out to speed up startup on very slow
53 53 # machines, and to conserve a bit of memory. Note that pysh profile does this
54 54 # automatically
55 55 ip.IP.default_option('cd','-q')
56 56
57 57
58 58 o.prompts_pad_left="1"
59 59 # Remove all blank lines in between prompts, like a normal shell.
60 60 o.separate_in="0"
61 61 o.separate_out="0"
62 62 o.separate_out2="0"
63 63
64 64 # now alias all syscommands
65 65
66 66 db = ip.db
67 67
68 68 syscmds = db.get("syscmdlist",[] )
69 69 if not syscmds:
70 70 print textwrap.dedent("""
71 71 System command list not initialized, probably the first run...
72 72 running %rehashx to refresh the command list. Run %rehashx
73 73 again to refresh command list (after installing new software etc.)
74 74 """)
75 75 ip.magic('rehashx')
76 76 syscmds = db.get("syscmdlist")
77 77 for cmd in syscmds:
78 78 #print "al",cmd
79 79 noext, ext = os.path.splitext(cmd)
80 80 ip.IP.alias_table[noext] = (0,cmd)
81 81 extend_shell_behavior(ip)
82 82
83 83 def extend_shell_behavior(ip):
84 84
85 85 # Instead of making signature a global variable tie it to IPSHELL.
86 86 # In future if it is required to distinguish between different
87 87 # shells we can assign a signature per shell basis
88 88 ip.IP.__sig__ = 0xa005
89 89 # mark the IPSHELL with this signature
90 90 ip.IP.user_ns['__builtins__'].__dict__['__sig__'] = ip.IP.__sig__
91 91
92 92 from IPython.Itpl import ItplNS
93 93 from IPython.genutils import shell
94 94 # utility to expand user variables via Itpl
95 ip.IP.var_expand = lambda cmd, lvars=None: \
95 # xxx do something sensible with depth?
96 ip.IP.var_expand = lambda cmd, lvars=None, depth=2: \
96 97 str(ItplNS(cmd.replace('#','\#'), ip.IP.user_ns, get_locals()))
97 98
98 99 def get_locals():
99 100 """ Substituting a variable through Itpl deep inside the IPSHELL stack
100 101 requires the knowledge of all the variables in scope upto the last
101 102 IPSHELL frame. This routine simply merges all the local variables
102 103 on the IPSHELL stack without worrying about their scope rules
103 104 """
104 105 import sys
105 106 # note lambda expression constitues a function call
106 107 # hence fno should be incremented by one
107 108 getsig = lambda fno: sys._getframe(fno+1).f_globals \
108 109 ['__builtins__'].__dict__['__sig__']
109 110 getlvars = lambda fno: sys._getframe(fno+1).f_locals
110 111 # trackback until we enter the IPSHELL
111 112 frame_no = 1
112 113 sig = ip.IP.__sig__
113 114 fsig = ~sig
114 115 while fsig != sig :
115 116 try:
116 117 fsig = getsig(frame_no)
117 118 except (AttributeError, KeyError):
118 119 frame_no += 1
119 120 except ValueError:
120 121 # stack is depleted
121 122 # call did not originate from IPSHELL
122 123 return {}
123 124 first_frame = frame_no
124 125 # walk further back until we exit from IPSHELL or deplete stack
125 126 try:
126 127 while(sig == getsig(frame_no+1)):
127 128 frame_no += 1
128 129 except (AttributeError, KeyError, ValueError):
129 130 pass
130 131 # merge the locals from top down hence overriding
131 132 # any re-definitions of variables, functions etc.
132 133 lvars = {}
133 134 for fno in range(frame_no, first_frame-1, -1):
134 135 lvars.update(getlvars(fno))
135 136 #print '\n'*5, first_frame, frame_no, '\n', lvars, '\n'*5 #dbg
136 137 return lvars
137 138
138 139 def _runlines(lines):
139 140 """Run a string of one or more lines of source.
140 141
141 142 This method is capable of running a string containing multiple source
142 143 lines, as if they had been entered at the IPython prompt. Since it
143 144 exposes IPython's processing machinery, the given strings can contain
144 145 magic calls (%magic), special shell access (!cmd), etc."""
145 146
146 147 # We must start with a clean buffer, in case this is run from an
147 148 # interactive IPython session (via a magic, for example).
148 149 ip.IP.resetbuffer()
149 150 lines = lines.split('\n')
150 151 more = 0
151 152 command = ''
152 153 for line in lines:
153 154 # skip blank lines so we don't mess up the prompt counter, but do
154 155 # NOT skip even a blank line if we are in a code block (more is
155 156 # true)
156 157 # if command is not empty trim the line
157 158 if command != '' :
158 159 line = line.strip()
159 160 # add the broken line to the command
160 161 if line and line[-1] == '\\' :
161 162 command += line[0:-1] + ' '
162 163 more = True
163 164 continue
164 165 else :
165 166 # add the last (current) line to the command
166 167 command += line
167 168 if command or more:
168 169 more = ip.IP.push(ip.IP.prefilter(command,more))
169 170 command = ''
170 171 # IPython's runsource returns None if there was an error
171 172 # compiling the code. This allows us to stop processing right
172 173 # away, so the user gets the error message at the right place.
173 174 if more is None:
174 175 break
175 176 # final newline in case the input didn't have it, so that the code
176 177 # actually does get executed
177 178 if more:
178 179 ip.IP.push('\n')
179 180
180 181 ip.IP.runlines = _runlines
181 182
182 183 main()
General Comments 0
You need to be logged in to leave comments. Login now