##// END OF EJS Templates
prefilter: magics on multiline structuress now work again
vivainio -
Show More
@@ -1,313 +1,316 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 Classes and functions for prefiltering (transforming) a line of user input.
4 4 This module is responsible, primarily, for breaking the line up into useful
5 5 pieces and triggering the appropriate handlers in iplib to do the actual
6 6 transforming work.
7 7 """
8 8 __docformat__ = "restructuredtext en"
9 9
10 10 import re
11 11 import IPython.ipapi
12 12
13 13 class LineInfo(object):
14 14 """A single line of input and associated info.
15 15
16 16 Includes the following as properties:
17 17
18 18 line
19 19 The original, raw line
20 20
21 21 continue_prompt
22 22 Is this line a continuation in a sequence of multiline input?
23 23
24 24 pre
25 25 The initial esc character or whitespace.
26 26
27 27 preChar
28 28 The escape character(s) in pre or the empty string if there isn't one.
29 29 Note that '!!' is a possible value for preChar. Otherwise it will
30 30 always be a single character.
31 31
32 32 preWhitespace
33 33 The leading whitespace from pre if it exists. If there is a preChar,
34 34 this is just ''.
35 35
36 36 iFun
37 37 The 'function part', which is basically the maximal initial sequence
38 38 of valid python identifiers and the '.' character. This is what is
39 39 checked for alias and magic transformations, used for auto-calling,
40 40 etc.
41 41
42 42 theRest
43 43 Everything else on the line.
44 44 """
45 45 def __init__(self, line, continue_prompt):
46 46 self.line = line
47 47 self.continue_prompt = continue_prompt
48 48 self.pre, self.iFun, self.theRest = splitUserInput(line)
49 49
50 50 self.preChar = self.pre.strip()
51 51 if self.preChar:
52 52 self.preWhitespace = '' # No whitespace allowd before esc chars
53 53 else:
54 54 self.preWhitespace = self.pre
55 55
56 56 self._oinfo = None
57 57
58 58 def ofind(self, ip):
59 59 """Do a full, attribute-walking lookup of the iFun in the various
60 60 namespaces for the given IPython InteractiveShell instance.
61 61
62 62 Return a dict with keys: found,obj,ospace,ismagic
63 63
64 64 Note: can cause state changes because of calling getattr, but should
65 65 only be run if autocall is on and if the line hasn't matched any
66 66 other, less dangerous handlers.
67 67
68 68 Does cache the results of the call, so can be called multiple times
69 69 without worrying about *further* damaging state.
70 70 """
71 71 if not self._oinfo:
72 72 self._oinfo = ip._ofind(self.iFun)
73 73 return self._oinfo
74
74 def __str__(self):
75 return "Lineinfo [%s|%s|%s]" %(self.pre,self.iFun,self.theRest)
75 76
76 77 def splitUserInput(line, pattern=None):
77 78 """Split user input into pre-char/whitespace, function part and rest.
78 79
79 80 Mostly internal to this module, but also used by iplib.expand_aliases,
80 81 which passes in a shell pattern.
81 82 """
82 83 # It seems to me that the shell splitting should be a separate method.
83 84
84 85 if not pattern:
85 86 pattern = line_split
86 87 match = pattern.match(line)
87 88 if not match:
88 89 #print "match failed for line '%s'" % line
89 90 try:
90 91 iFun,theRest = line.split(None,1)
91 92 except ValueError:
92 93 #print "split failed for line '%s'" % line
93 94 iFun,theRest = line,''
94 95 pre = re.match('^(\s*)(.*)',line).groups()[0]
95 96 else:
96 97 pre,iFun,theRest = match.groups()
97 98
98 99 # iFun has to be a valid python identifier, so it better be only pure
99 100 # ascii, no unicode:
100 101 try:
101 102 iFun = iFun.encode('ascii')
102 103 except UnicodeEncodeError:
103 104 theRest = iFun + u' ' + theRest
104 105 iFun = u''
105 106
106 107 #print 'line:<%s>' % line # dbg
107 108 #print 'pre <%s> iFun <%s> rest <%s>' % (pre,iFun.strip(),theRest) # dbg
108 109 return pre,iFun.strip(),theRest.lstrip()
109 110
110 111
111 112 # RegExp for splitting line contents into pre-char//first word-method//rest.
112 113 # For clarity, each group in on one line.
113 114
114 115 # WARNING: update the regexp if the escapes in iplib are changed, as they
115 116 # are hardwired in.
116 117
117 118 # Although it's not solely driven by the regex, note that:
118 119 # ,;/% only trigger if they are the first character on the line
119 120 # ! and !! trigger if they are first char(s) *or* follow an indent
120 121 # ? triggers as first or last char.
121 122
122 123 # The three parts of the regex are:
123 124 # 1) pre: pre_char *or* initial whitespace
124 125 # 2) iFun: first word/method (mix of \w and '.')
125 126 # 3) theRest: rest of line (separated from iFun by space if non-empty)
126 127 line_split = re.compile(r'^([,;/%?]|!!?|\s*)'
127 128 r'\s*([\w\.]+)'
128 129 r'(\s+.*$|$)')
129 130
130 131 shell_line_split = re.compile(r'^(\s*)(\S*\s*)(.*$)')
131 132
132 133 def prefilter(line_info, ip):
133 134 """Call one of the passed-in InteractiveShell's handler preprocessors,
134 135 depending on the form of the line. Return the results, which must be a
135 136 value, even if it's a blank ('')."""
136 137 # Note: the order of these checks does matter.
137 138 for check in [ checkEmacs,
138 139 checkIPyAutocall,
139 140 checkMultiLineShell,
140 141 checkEscChars,
141 142 checkAssignment,
142 143 checkAutomagic,
143 144 checkAlias,
144 145 checkPythonOps,
145 146 checkAutocall,
146 147 ]:
147 148 handler = check(line_info, ip)
148 149 if handler:
149 150 return handler(line_info)
150 151
151 152 return ip.handle_normal(line_info)
152 153
153 154 # Handler checks
154 155 #
155 156 # All have the same interface: they take a LineInfo object and a ref to the
156 157 # iplib.InteractiveShell object. They check the line to see if a particular
157 158 # handler should be called, and return either a handler or None. The
158 159 # handlers which they return are *bound* methods of the InteractiveShell
159 160 # object.
160 161 #
161 162 # In general, these checks should only take responsibility for their 'own'
162 163 # handler. If it doesn't get triggered, they should just return None and
163 164 # let the rest of the check sequence run.
164 165 def checkEmacs(l_info,ip):
165 166 "Emacs ipython-mode tags certain input lines."
166 167 if l_info.line.endswith('# PYTHON-MODE'):
167 168 return ip.handle_emacs
168 169 else:
169 170 return None
170 171
171 172 def checkIPyAutocall(l_info,ip):
172 173 "Instances of IPyAutocall in user_ns get autocalled immediately"
173 174 obj = ip.user_ns.get(l_info.iFun, None)
174 175 if isinstance(obj, IPython.ipapi.IPyAutocall):
175 176 obj.set_ip(ip.api)
176 177 return ip.handle_auto
177 178 else:
178 179 return None
179 180
180 181
181 182 def checkMultiLineShell(l_info,ip):
182 183 "Allow ! and !! in multi-line statements if multi_line_specials is on"
183 184 # Note that this one of the only places we check the first character of
184 185 # iFun and *not* the preChar. Also note that the below test matches
185 # both ! and !!.
186 # both ! and !!.
186 187 if l_info.continue_prompt \
187 and ip.rc.multi_line_specials \
188 and l_info.iFun.startswith(ip.ESC_SHELL):
189 return ip.handle_shell_escape
188 and ip.rc.multi_line_specials:
189 if l_info.iFun.startswith(ip.ESC_SHELL):
190 return ip.handle_shell_escape
191 if l_info.iFun.startswith(ip.ESC_MAGIC):
192 return ip.handle_magic
190 193 else:
191 194 return None
192 195
193 196 def checkEscChars(l_info,ip):
194 197 """Check for escape character and return either a handler to handle it,
195 198 or None if there is no escape char."""
196 199 if l_info.line[-1] == ip.ESC_HELP \
197 200 and l_info.preChar != ip.ESC_SHELL \
198 201 and l_info.preChar != ip.ESC_SH_CAP:
199 202 # the ? can be at the end, but *not* for either kind of shell escape,
200 203 # because a ? can be a vaild final char in a shell cmd
201 204 return ip.handle_help
202 205 elif l_info.preChar in ip.esc_handlers:
203 206 return ip.esc_handlers[l_info.preChar]
204 207 else:
205 208 return None
206 209
207 210
208 211 def checkAssignment(l_info,ip):
209 212 """Check to see if user is assigning to a var for the first time, in
210 213 which case we want to avoid any sort of automagic / autocall games.
211 214
212 215 This allows users to assign to either alias or magic names true python
213 216 variables (the magic/alias systems always take second seat to true
214 217 python code). E.g. ls='hi', or ls,that=1,2"""
215 218 if l_info.theRest and l_info.theRest[0] in '=,':
216 219 return ip.handle_normal
217 220 else:
218 221 return None
219 222
220 223
221 224 def checkAutomagic(l_info,ip):
222 225 """If the iFun is magic, and automagic is on, run it. Note: normal,
223 226 non-auto magic would already have been triggered via '%' in
224 227 check_esc_chars. This just checks for automagic. Also, before
225 228 triggering the magic handler, make sure that there is nothing in the
226 229 user namespace which could shadow it."""
227 230 if not ip.rc.automagic or not hasattr(ip,'magic_'+l_info.iFun):
228 231 return None
229 232
230 233 # We have a likely magic method. Make sure we should actually call it.
231 234 if l_info.continue_prompt and not ip.rc.multi_line_specials:
232 235 return None
233 236
234 237 head = l_info.iFun.split('.',1)[0]
235 238 if isShadowed(head,ip):
236 239 return None
237 240
238 241 return ip.handle_magic
239 242
240 243
241 244 def checkAlias(l_info,ip):
242 245 "Check if the initital identifier on the line is an alias."
243 246 # Note: aliases can not contain '.'
244 247 head = l_info.iFun.split('.',1)[0]
245 248
246 249 if l_info.iFun not in ip.alias_table \
247 250 or head not in ip.alias_table \
248 251 or isShadowed(head,ip):
249 252 return None
250 253
251 254 return ip.handle_alias
252 255
253 256
254 257 def checkPythonOps(l_info,ip):
255 258 """If the 'rest' of the line begins with a function call or pretty much
256 259 any python operator, we should simply execute the line (regardless of
257 260 whether or not there's a possible autocall expansion). This avoids
258 261 spurious (and very confusing) geattr() accesses."""
259 262 if l_info.theRest and l_info.theRest[0] in '!=()<>,+*/%^&|':
260 263 return ip.handle_normal
261 264 else:
262 265 return None
263 266
264 267
265 268 def checkAutocall(l_info,ip):
266 269 "Check if the initial word/function is callable and autocall is on."
267 270 if not ip.rc.autocall:
268 271 return None
269 272
270 273 oinfo = l_info.ofind(ip) # This can mutate state via getattr
271 274 if not oinfo['found']:
272 275 return None
273 276
274 277 if callable(oinfo['obj']) \
275 278 and (not re_exclude_auto.match(l_info.theRest)) \
276 279 and re_fun_name.match(l_info.iFun):
277 280 #print 'going auto' # dbg
278 281 return ip.handle_auto
279 282 else:
280 283 #print 'was callable?', callable(l_info.oinfo['obj']) # dbg
281 284 return None
282 285
283 286 # RegExp to identify potential function names
284 287 re_fun_name = re.compile(r'[a-zA-Z_]([a-zA-Z0-9_.]*) *$')
285 288
286 289 # RegExp to exclude strings with this start from autocalling. In
287 290 # particular, all binary operators should be excluded, so that if foo is
288 291 # callable, foo OP bar doesn't become foo(OP bar), which is invalid. The
289 292 # characters '!=()' don't need to be checked for, as the checkPythonChars
290 293 # routine explicitely does so, to catch direct calls and rebindings of
291 294 # existing names.
292 295
293 296 # Warning: the '-' HAS TO BE AT THE END of the first group, otherwise
294 297 # it affects the rest of the group in square brackets.
295 298 re_exclude_auto = re.compile(r'^[,&^\|\*/\+-]'
296 299 r'|^is |^not |^in |^and |^or ')
297 300
298 301 # try to catch also methods for stuff in lists/tuples/dicts: off
299 302 # (experimental). For this to work, the line_split regexp would need
300 303 # to be modified so it wouldn't break things at '['. That line is
301 304 # nasty enough that I shouldn't change it until I can test it _well_.
302 305 #self.re_fun_name = re.compile (r'[a-zA-Z_]([a-zA-Z0-9_.\[\]]*) ?$')
303 306
304 307 # Handler Check Utilities
305 308 def isShadowed(identifier,ip):
306 309 """Is the given identifier defined in one of the namespaces which shadow
307 310 the alias and magic namespaces? Note that an identifier is different
308 311 than iFun, because it can not contain a '.' character."""
309 312 # This is much safer than calling ofind, which can change state
310 313 return (identifier in ip.user_ns \
311 314 or identifier in ip.internal_ns \
312 315 or identifier in ip.ns_table['builtin'])
313 316
General Comments 0
You need to be logged in to leave comments. Login now