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