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