##// END OF EJS Templates
handle ! as priority
vivainio -
Show More
@@ -1,316 +1,320 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 if self.preChar:
51 if self.preChar:
52 self.preWhitespace = '' # No whitespace allowd before esc chars
52 self.preWhitespace = '' # No whitespace allowd before esc chars
53 else:
53 else:
54 self.preWhitespace = self.pre
54 self.preWhitespace = self.pre
55
55
56 self._oinfo = None
56 self._oinfo = None
57
57
58 def ofind(self, ip):
58 def ofind(self, ip):
59 """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
60 namespaces for the given IPython InteractiveShell instance.
60 namespaces for the given IPython InteractiveShell instance.
61
61
62 Return a dict with keys: found,obj,ospace,ismagic
62 Return a dict with keys: found,obj,ospace,ismagic
63
63
64 Note: can cause state changes because of calling getattr, but should
64 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
65 only be run if autocall is on and if the line hasn't matched any
66 other, less dangerous handlers.
66 other, less dangerous handlers.
67
67
68 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
69 without worrying about *further* damaging state.
69 without worrying about *further* damaging state.
70 """
70 """
71 if not self._oinfo:
71 if not self._oinfo:
72 self._oinfo = ip._ofind(self.iFun)
72 self._oinfo = ip._ofind(self.iFun)
73 return self._oinfo
73 return self._oinfo
74 def __str__(self):
74 def __str__(self):
75 return "Lineinfo [%s|%s|%s]" %(self.pre,self.iFun,self.theRest)
75 return "Lineinfo [%s|%s|%s]" %(self.pre,self.iFun,self.theRest)
76
76
77 def splitUserInput(line, pattern=None):
77 def splitUserInput(line, pattern=None):
78 """Split user input into pre-char/whitespace, function part and rest.
78 """Split user input into pre-char/whitespace, function part and rest.
79
79
80 Mostly internal to this module, but also used by iplib.expand_aliases,
80 Mostly internal to this module, but also used by iplib.expand_aliases,
81 which passes in a shell pattern.
81 which passes in a shell pattern.
82 """
82 """
83 # It seems to me that the shell splitting should be a separate method.
83 # It seems to me that the shell splitting should be a separate method.
84
84
85 if not pattern:
85 if not pattern:
86 pattern = line_split
86 pattern = line_split
87 match = pattern.match(line)
87 match = pattern.match(line)
88 if not match:
88 if not match:
89 #print "match failed for line '%s'" % line
89 #print "match failed for line '%s'" % line
90 try:
90 try:
91 iFun,theRest = line.split(None,1)
91 iFun,theRest = line.split(None,1)
92 except ValueError:
92 except ValueError:
93 #print "split failed for line '%s'" % line
93 #print "split failed for line '%s'" % line
94 iFun,theRest = line,''
94 iFun,theRest = line,''
95 pre = re.match('^(\s*)(.*)',line).groups()[0]
95 pre = re.match('^(\s*)(.*)',line).groups()[0]
96 else:
96 else:
97 pre,iFun,theRest = match.groups()
97 pre,iFun,theRest = match.groups()
98
98
99 # iFun has to be a valid python identifier, so it better be only pure
99 # iFun has to be a valid python identifier, so it better be only pure
100 # ascii, no unicode:
100 # ascii, no unicode:
101 try:
101 try:
102 iFun = iFun.encode('ascii')
102 iFun = iFun.encode('ascii')
103 except UnicodeEncodeError:
103 except UnicodeEncodeError:
104 theRest = iFun + u' ' + theRest
104 theRest = iFun + u' ' + theRest
105 iFun = u''
105 iFun = u''
106
106
107 #print 'line:<%s>' % line # dbg
107 #print 'line:<%s>' % line # dbg
108 #print 'pre <%s> iFun <%s> rest <%s>' % (pre,iFun.strip(),theRest) # dbg
108 #print 'pre <%s> iFun <%s> rest <%s>' % (pre,iFun.strip(),theRest) # dbg
109 return pre,iFun.strip(),theRest.lstrip()
109 return pre,iFun.strip(),theRest.lstrip()
110
110
111
111
112 # RegExp for splitting line contents into pre-char//first word-method//rest.
112 # RegExp for splitting line contents into pre-char//first word-method//rest.
113 # For clarity, each group in on one line.
113 # For clarity, each group in on one line.
114
114
115 # WARNING: update the regexp if the escapes in iplib are changed, as they
115 # WARNING: update the regexp if the escapes in iplib are changed, as they
116 # are hardwired in.
116 # are hardwired in.
117
117
118 # Although it's not solely driven by the regex, note that:
118 # Although it's not solely driven by the regex, note that:
119 # ,;/% only trigger if they are the first character on the line
119 # ,;/% only trigger if they are the first character on the line
120 # ! and !! trigger if they are first char(s) *or* follow an indent
120 # ! and !! trigger if they are first char(s) *or* follow an indent
121 # ? triggers as first or last char.
121 # ? triggers as first or last char.
122
122
123 # The three parts of the regex are:
123 # The three parts of the regex are:
124 # 1) pre: pre_char *or* initial whitespace
124 # 1) pre: pre_char *or* initial whitespace
125 # 2) iFun: first word/method (mix of \w and '.')
125 # 2) iFun: first word/method (mix of \w and '.')
126 # 3) theRest: rest of line (separated from iFun by space if non-empty)
126 # 3) theRest: rest of line (separated from iFun by space if non-empty)
127 line_split = re.compile(r'^([,;/%?]|!!?|\s*)'
127 line_split = re.compile(r'^([,;/%?]|!!?|\s*)'
128 r'\s*([\w\.]+)'
128 r'\s*([\w\.]+)'
129 r'(\s+.*$|$)')
129 r'(\s+.*$|$)')
130
130
131 shell_line_split = re.compile(r'^(\s*)(\S*\s*)(.*$)')
131 shell_line_split = re.compile(r'^(\s*)(\S*\s*)(.*$)')
132
132
133 def prefilter(line_info, ip):
133 def prefilter(line_info, ip):
134 """Call one of the passed-in InteractiveShell's handler preprocessors,
134 """Call one of the passed-in InteractiveShell's handler preprocessors,
135 depending on the form of the line. Return the results, which must be a
135 depending on the form of the line. Return the results, which must be a
136 value, even if it's a blank ('')."""
136 value, even if it's a blank ('')."""
137 # Note: the order of these checks does matter.
137 # Note: the order of these checks does matter.
138 for check in [ checkEmacs,
138 for check in [ checkEmacs,
139 checkShellEscape,
139 checkIPyAutocall,
140 checkIPyAutocall,
140 checkMultiLineShell,
141 checkMultiLineMagic,
141 checkEscChars,
142 checkEscChars,
142 checkAssignment,
143 checkAssignment,
143 checkAutomagic,
144 checkAutomagic,
144 checkAlias,
145 checkAlias,
145 checkPythonOps,
146 checkPythonOps,
146 checkAutocall,
147 checkAutocall,
147 ]:
148 ]:
148 handler = check(line_info, ip)
149 handler = check(line_info, ip)
149 if handler:
150 if handler:
150 return handler(line_info)
151 return handler(line_info)
151
152
152 return ip.handle_normal(line_info)
153 return ip.handle_normal(line_info)
153
154
154 # Handler checks
155 # Handler checks
155 #
156 #
156 # All have the same interface: they take a LineInfo object and a ref to the
157 # All have the same interface: they take a LineInfo object and a ref to the
157 # iplib.InteractiveShell object. They check the line to see if a particular
158 # iplib.InteractiveShell object. They check the line to see if a particular
158 # handler should be called, and return either a handler or None. The
159 # handler should be called, and return either a handler or None. The
159 # handlers which they return are *bound* methods of the InteractiveShell
160 # handlers which they return are *bound* methods of the InteractiveShell
160 # object.
161 # object.
161 #
162 #
162 # In general, these checks should only take responsibility for their 'own'
163 # In general, these checks should only take responsibility for their 'own'
163 # handler. If it doesn't get triggered, they should just return None and
164 # handler. If it doesn't get triggered, they should just return None and
164 # let the rest of the check sequence run.
165 # let the rest of the check sequence run.
166
167 def checkShellEscape(l_info,ip):
168 if l_info.line.lstrip().startswith(ip.ESC_SHELL):
169 return ip.handle_shell_escape
170
165 def checkEmacs(l_info,ip):
171 def checkEmacs(l_info,ip):
166 "Emacs ipython-mode tags certain input lines."
172 "Emacs ipython-mode tags certain input lines."
167 if l_info.line.endswith('# PYTHON-MODE'):
173 if l_info.line.endswith('# PYTHON-MODE'):
168 return ip.handle_emacs
174 return ip.handle_emacs
169 else:
175 else:
170 return None
176 return None
171
177
172 def checkIPyAutocall(l_info,ip):
178 def checkIPyAutocall(l_info,ip):
173 "Instances of IPyAutocall in user_ns get autocalled immediately"
179 "Instances of IPyAutocall in user_ns get autocalled immediately"
174 obj = ip.user_ns.get(l_info.iFun, None)
180 obj = ip.user_ns.get(l_info.iFun, None)
175 if isinstance(obj, IPython.ipapi.IPyAutocall):
181 if isinstance(obj, IPython.ipapi.IPyAutocall):
176 obj.set_ip(ip.api)
182 obj.set_ip(ip.api)
177 return ip.handle_auto
183 return ip.handle_auto
178 else:
184 else:
179 return None
185 return None
180
186
181
187
182 def checkMultiLineShell(l_info,ip):
188 def checkMultiLineMagic(l_info,ip):
183 "Allow ! and !! in multi-line statements if multi_line_specials is on"
189 "Allow ! and !! in multi-line statements if multi_line_specials is on"
184 # Note that this one of the only places we check the first character of
190 # Note that this one of the only places we check the first character of
185 # iFun and *not* the preChar. Also note that the below test matches
191 # iFun and *not* the preChar. Also note that the below test matches
186 # both ! and !!.
192 # both ! and !!.
187 if l_info.continue_prompt \
193 if l_info.continue_prompt \
188 and ip.rc.multi_line_specials:
194 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):
195 if l_info.iFun.startswith(ip.ESC_MAGIC):
192 return ip.handle_magic
196 return ip.handle_magic
193 else:
197 else:
194 return None
198 return None
195
199
196 def checkEscChars(l_info,ip):
200 def checkEscChars(l_info,ip):
197 """Check for escape character and return either a handler to handle it,
201 """Check for escape character and return either a handler to handle it,
198 or None if there is no escape char."""
202 or None if there is no escape char."""
199 if l_info.line[-1] == ip.ESC_HELP \
203 if l_info.line[-1] == ip.ESC_HELP \
200 and l_info.preChar != ip.ESC_SHELL \
204 and l_info.preChar != ip.ESC_SHELL \
201 and l_info.preChar != ip.ESC_SH_CAP:
205 and l_info.preChar != ip.ESC_SH_CAP:
202 # the ? can be at the end, but *not* for either kind of shell escape,
206 # the ? can be at the end, but *not* for either kind of shell escape,
203 # because a ? can be a vaild final char in a shell cmd
207 # because a ? can be a vaild final char in a shell cmd
204 return ip.handle_help
208 return ip.handle_help
205 elif l_info.preChar in ip.esc_handlers:
209 elif l_info.preChar in ip.esc_handlers:
206 return ip.esc_handlers[l_info.preChar]
210 return ip.esc_handlers[l_info.preChar]
207 else:
211 else:
208 return None
212 return None
209
213
210
214
211 def checkAssignment(l_info,ip):
215 def checkAssignment(l_info,ip):
212 """Check to see if user is assigning to a var for the first time, in
216 """Check to see if user is assigning to a var for the first time, in
213 which case we want to avoid any sort of automagic / autocall games.
217 which case we want to avoid any sort of automagic / autocall games.
214
218
215 This allows users to assign to either alias or magic names true python
219 This allows users to assign to either alias or magic names true python
216 variables (the magic/alias systems always take second seat to true
220 variables (the magic/alias systems always take second seat to true
217 python code). E.g. ls='hi', or ls,that=1,2"""
221 python code). E.g. ls='hi', or ls,that=1,2"""
218 if l_info.theRest and l_info.theRest[0] in '=,':
222 if l_info.theRest and l_info.theRest[0] in '=,':
219 return ip.handle_normal
223 return ip.handle_normal
220 else:
224 else:
221 return None
225 return None
222
226
223
227
224 def checkAutomagic(l_info,ip):
228 def checkAutomagic(l_info,ip):
225 """If the iFun is magic, and automagic is on, run it. Note: normal,
229 """If the iFun is magic, and automagic is on, run it. Note: normal,
226 non-auto magic would already have been triggered via '%' in
230 non-auto magic would already have been triggered via '%' in
227 check_esc_chars. This just checks for automagic. Also, before
231 check_esc_chars. This just checks for automagic. Also, before
228 triggering the magic handler, make sure that there is nothing in the
232 triggering the magic handler, make sure that there is nothing in the
229 user namespace which could shadow it."""
233 user namespace which could shadow it."""
230 if not ip.rc.automagic or not hasattr(ip,'magic_'+l_info.iFun):
234 if not ip.rc.automagic or not hasattr(ip,'magic_'+l_info.iFun):
231 return None
235 return None
232
236
233 # We have a likely magic method. Make sure we should actually call it.
237 # We have a likely magic method. Make sure we should actually call it.
234 if l_info.continue_prompt and not ip.rc.multi_line_specials:
238 if l_info.continue_prompt and not ip.rc.multi_line_specials:
235 return None
239 return None
236
240
237 head = l_info.iFun.split('.',1)[0]
241 head = l_info.iFun.split('.',1)[0]
238 if isShadowed(head,ip):
242 if isShadowed(head,ip):
239 return None
243 return None
240
244
241 return ip.handle_magic
245 return ip.handle_magic
242
246
243
247
244 def checkAlias(l_info,ip):
248 def checkAlias(l_info,ip):
245 "Check if the initital identifier on the line is an alias."
249 "Check if the initital identifier on the line is an alias."
246 # Note: aliases can not contain '.'
250 # Note: aliases can not contain '.'
247 head = l_info.iFun.split('.',1)[0]
251 head = l_info.iFun.split('.',1)[0]
248
252
249 if l_info.iFun not in ip.alias_table \
253 if l_info.iFun not in ip.alias_table \
250 or head not in ip.alias_table \
254 or head not in ip.alias_table \
251 or isShadowed(head,ip):
255 or isShadowed(head,ip):
252 return None
256 return None
253
257
254 return ip.handle_alias
258 return ip.handle_alias
255
259
256
260
257 def checkPythonOps(l_info,ip):
261 def checkPythonOps(l_info,ip):
258 """If the 'rest' of the line begins with a function call or pretty much
262 """If the 'rest' of the line begins with a function call or pretty much
259 any python operator, we should simply execute the line (regardless of
263 any python operator, we should simply execute the line (regardless of
260 whether or not there's a possible autocall expansion). This avoids
264 whether or not there's a possible autocall expansion). This avoids
261 spurious (and very confusing) geattr() accesses."""
265 spurious (and very confusing) geattr() accesses."""
262 if l_info.theRest and l_info.theRest[0] in '!=()<>,+*/%^&|':
266 if l_info.theRest and l_info.theRest[0] in '!=()<>,+*/%^&|':
263 return ip.handle_normal
267 return ip.handle_normal
264 else:
268 else:
265 return None
269 return None
266
270
267
271
268 def checkAutocall(l_info,ip):
272 def checkAutocall(l_info,ip):
269 "Check if the initial word/function is callable and autocall is on."
273 "Check if the initial word/function is callable and autocall is on."
270 if not ip.rc.autocall:
274 if not ip.rc.autocall:
271 return None
275 return None
272
276
273 oinfo = l_info.ofind(ip) # This can mutate state via getattr
277 oinfo = l_info.ofind(ip) # This can mutate state via getattr
274 if not oinfo['found']:
278 if not oinfo['found']:
275 return None
279 return None
276
280
277 if callable(oinfo['obj']) \
281 if callable(oinfo['obj']) \
278 and (not re_exclude_auto.match(l_info.theRest)) \
282 and (not re_exclude_auto.match(l_info.theRest)) \
279 and re_fun_name.match(l_info.iFun):
283 and re_fun_name.match(l_info.iFun):
280 #print 'going auto' # dbg
284 #print 'going auto' # dbg
281 return ip.handle_auto
285 return ip.handle_auto
282 else:
286 else:
283 #print 'was callable?', callable(l_info.oinfo['obj']) # dbg
287 #print 'was callable?', callable(l_info.oinfo['obj']) # dbg
284 return None
288 return None
285
289
286 # RegExp to identify potential function names
290 # RegExp to identify potential function names
287 re_fun_name = re.compile(r'[a-zA-Z_]([a-zA-Z0-9_.]*) *$')
291 re_fun_name = re.compile(r'[a-zA-Z_]([a-zA-Z0-9_.]*) *$')
288
292
289 # RegExp to exclude strings with this start from autocalling. In
293 # RegExp to exclude strings with this start from autocalling. In
290 # particular, all binary operators should be excluded, so that if foo is
294 # particular, all binary operators should be excluded, so that if foo is
291 # callable, foo OP bar doesn't become foo(OP bar), which is invalid. The
295 # callable, foo OP bar doesn't become foo(OP bar), which is invalid. The
292 # characters '!=()' don't need to be checked for, as the checkPythonChars
296 # characters '!=()' don't need to be checked for, as the checkPythonChars
293 # routine explicitely does so, to catch direct calls and rebindings of
297 # routine explicitely does so, to catch direct calls and rebindings of
294 # existing names.
298 # existing names.
295
299
296 # Warning: the '-' HAS TO BE AT THE END of the first group, otherwise
300 # Warning: the '-' HAS TO BE AT THE END of the first group, otherwise
297 # it affects the rest of the group in square brackets.
301 # it affects the rest of the group in square brackets.
298 re_exclude_auto = re.compile(r'^[,&^\|\*/\+-]'
302 re_exclude_auto = re.compile(r'^[,&^\|\*/\+-]'
299 r'|^is |^not |^in |^and |^or ')
303 r'|^is |^not |^in |^and |^or ')
300
304
301 # try to catch also methods for stuff in lists/tuples/dicts: off
305 # try to catch also methods for stuff in lists/tuples/dicts: off
302 # (experimental). For this to work, the line_split regexp would need
306 # (experimental). For this to work, the line_split regexp would need
303 # to be modified so it wouldn't break things at '['. That line is
307 # to be modified so it wouldn't break things at '['. That line is
304 # nasty enough that I shouldn't change it until I can test it _well_.
308 # nasty enough that I shouldn't change it until I can test it _well_.
305 #self.re_fun_name = re.compile (r'[a-zA-Z_]([a-zA-Z0-9_.\[\]]*) ?$')
309 #self.re_fun_name = re.compile (r'[a-zA-Z_]([a-zA-Z0-9_.\[\]]*) ?$')
306
310
307 # Handler Check Utilities
311 # Handler Check Utilities
308 def isShadowed(identifier,ip):
312 def isShadowed(identifier,ip):
309 """Is the given identifier defined in one of the namespaces which shadow
313 """Is the given identifier defined in one of the namespaces which shadow
310 the alias and magic namespaces? Note that an identifier is different
314 the alias and magic namespaces? Note that an identifier is different
311 than iFun, because it can not contain a '.' character."""
315 than iFun, because it can not contain a '.' character."""
312 # This is much safer than calling ofind, which can change state
316 # This is much safer than calling ofind, which can change state
313 return (identifier in ip.user_ns \
317 return (identifier in ip.user_ns \
314 or identifier in ip.internal_ns \
318 or identifier in ip.internal_ns \
315 or identifier in ip.ns_table['builtin'])
319 or identifier in ip.ns_table['builtin'])
316
320
@@ -1,439 +1,440 b''
1 """
1 """
2 Test which prefilter transformations get called for various input lines.
2 Test which prefilter transformations get called for various input lines.
3 Note that this does *not* test the transformations themselves -- it's just
3 Note that this does *not* test the transformations themselves -- it's just
4 verifying that a particular combination of, e.g. config options and escape
4 verifying that a particular combination of, e.g. config options and escape
5 chars trigger the proper handle_X transform of the input line.
5 chars trigger the proper handle_X transform of the input line.
6
6
7 Usage: run from the command line with *normal* python, not ipython:
7 Usage: run from the command line with *normal* python, not ipython:
8 > python test_prefilter.py
8 > python test_prefilter.py
9
9
10 Fairly quiet output by default. Pass in -v to get everyone's favorite dots.
10 Fairly quiet output by default. Pass in -v to get everyone's favorite dots.
11 """
11 """
12
12
13 # The prefilter always ends in a call to some self.handle_X method. We swap
13 # The prefilter always ends in a call to some self.handle_X method. We swap
14 # all of those out so that we can capture which one was called.
14 # all of those out so that we can capture which one was called.
15
15
16 import sys
16 import sys
17 sys.path.append('..')
17 sys.path.append('..')
18 import IPython
18 import IPython
19 import IPython.ipapi
19 import IPython.ipapi
20
20
21 verbose = False
21 verbose = False
22 if len(sys.argv) > 1:
22 if len(sys.argv) > 1:
23 if sys.argv[1] == '-v':
23 if sys.argv[1] == '-v':
24 sys.argv = sys.argv[:-1] # IPython is confused by -v, apparently
24 sys.argv = sys.argv[:-1] # IPython is confused by -v, apparently
25 verbose = True
25 verbose = True
26
26
27 IPython.Shell.start()
27 IPython.Shell.start()
28
28
29 ip = IPython.ipapi.get()
29 ip = IPython.ipapi.get()
30
30
31 # Collect failed tests + stats and print them at the end
31 # Collect failed tests + stats and print them at the end
32 failures = []
32 failures = []
33 num_tests = 0
33 num_tests = 0
34
34
35 # Store the results in module vars as we go
35 # Store the results in module vars as we go
36 last_line = None
36 last_line = None
37 handler_called = None
37 handler_called = None
38 def install_mock_handler(name):
38 def install_mock_handler(name):
39 """Swap out one of the IP.handle_x methods with a function which can
39 """Swap out one of the IP.handle_x methods with a function which can
40 record which handler was called and what line was produced. The mock
40 record which handler was called and what line was produced. The mock
41 handler func always returns '', which causes ipython to cease handling
41 handler func always returns '', which causes ipython to cease handling
42 the string immediately. That way, that it doesn't echo output, raise
42 the string immediately. That way, that it doesn't echo output, raise
43 exceptions, etc. But do note that testing multiline strings thus gets
43 exceptions, etc. But do note that testing multiline strings thus gets
44 a bit hard."""
44 a bit hard."""
45 def mock_handler(self, line, continue_prompt=None,
45 def mock_handler(self, line, continue_prompt=None,
46 pre=None,iFun=None,theRest=None,
46 pre=None,iFun=None,theRest=None,
47 obj=None):
47 obj=None):
48 #print "Inside %s with '%s'" % (name, line)
48 #print "Inside %s with '%s'" % (name, line)
49 global last_line, handler_called
49 global last_line, handler_called
50 last_line = line
50 last_line = line
51 handler_called = name
51 handler_called = name
52 return ''
52 return ''
53 mock_handler.name = name
53 mock_handler.name = name
54 setattr(IPython.iplib.InteractiveShell, name, mock_handler)
54 setattr(IPython.iplib.InteractiveShell, name, mock_handler)
55
55
56 install_mock_handler('handle_normal')
56 install_mock_handler('handle_normal')
57 install_mock_handler('handle_auto')
57 install_mock_handler('handle_auto')
58 install_mock_handler('handle_magic')
58 install_mock_handler('handle_magic')
59 install_mock_handler('handle_help')
59 install_mock_handler('handle_help')
60 install_mock_handler('handle_shell_escape')
60 install_mock_handler('handle_shell_escape')
61 install_mock_handler('handle_alias')
61 install_mock_handler('handle_alias')
62 install_mock_handler('handle_emacs')
62 install_mock_handler('handle_emacs')
63
63
64
64
65 def reset_esc_handlers():
65 def reset_esc_handlers():
66 """The escape handlers are stored in a hash (as an attribute of the
66 """The escape handlers are stored in a hash (as an attribute of the
67 InteractiveShell *instance*), so we have to rebuild that hash to get our
67 InteractiveShell *instance*), so we have to rebuild that hash to get our
68 new handlers in there."""
68 new handlers in there."""
69 s = ip.IP
69 s = ip.IP
70 s.esc_handlers = {s.ESC_PAREN : s.handle_auto,
70 s.esc_handlers = {s.ESC_PAREN : s.handle_auto,
71 s.ESC_QUOTE : s.handle_auto,
71 s.ESC_QUOTE : s.handle_auto,
72 s.ESC_QUOTE2 : s.handle_auto,
72 s.ESC_QUOTE2 : s.handle_auto,
73 s.ESC_MAGIC : s.handle_magic,
73 s.ESC_MAGIC : s.handle_magic,
74 s.ESC_HELP : s.handle_help,
74 s.ESC_HELP : s.handle_help,
75 s.ESC_SHELL : s.handle_shell_escape,
75 s.ESC_SHELL : s.handle_shell_escape,
76 s.ESC_SH_CAP : s.handle_shell_escape,
76 s.ESC_SH_CAP : s.handle_shell_escape,
77 }
77 }
78 reset_esc_handlers()
78 reset_esc_handlers()
79
79
80 # This is so I don't have to quote over and over. Gotta be a better way.
80 # This is so I don't have to quote over and over. Gotta be a better way.
81 handle_normal = 'handle_normal'
81 handle_normal = 'handle_normal'
82 handle_auto = 'handle_auto'
82 handle_auto = 'handle_auto'
83 handle_magic = 'handle_magic'
83 handle_magic = 'handle_magic'
84 handle_help = 'handle_help'
84 handle_help = 'handle_help'
85 handle_shell_escape = 'handle_shell_escape'
85 handle_shell_escape = 'handle_shell_escape'
86 handle_alias = 'handle_alias'
86 handle_alias = 'handle_alias'
87 handle_emacs = 'handle_emacs'
87 handle_emacs = 'handle_emacs'
88
88
89 def check(assertion, failure_msg):
89 def check(assertion, failure_msg):
90 """Check a boolean assertion and fail with a message if necessary. Store
90 """Check a boolean assertion and fail with a message if necessary. Store
91 an error essage in module-level failures list in case of failure. Print
91 an error essage in module-level failures list in case of failure. Print
92 '.' or 'F' if module var Verbose is true.
92 '.' or 'F' if module var Verbose is true.
93 """
93 """
94 global num_tests
94 global num_tests
95 num_tests += 1
95 num_tests += 1
96 if assertion:
96 if assertion:
97 if verbose:
97 if verbose:
98 sys.stdout.write('.')
98 sys.stdout.write('.')
99 sys.stdout.flush()
99 sys.stdout.flush()
100 else:
100 else:
101 if verbose:
101 if verbose:
102 sys.stdout.write('F')
102 sys.stdout.write('F')
103 sys.stdout.flush()
103 sys.stdout.flush()
104 failures.append(failure_msg)
104 failures.append(failure_msg)
105
105
106
106
107 def check_handler(expected_handler, line):
107 def check_handler(expected_handler, line):
108 """Verify that the expected hander was called (for the given line,
108 """Verify that the expected hander was called (for the given line,
109 passed in for failure reporting).
109 passed in for failure reporting).
110
110
111 Pulled out to its own function so that tests which don't use
111 Pulled out to its own function so that tests which don't use
112 run_handler_tests can still take advantage of it."""
112 run_handler_tests can still take advantage of it."""
113 check(handler_called == expected_handler,
113 check(handler_called == expected_handler,
114 "Expected %s to be called for %s, "
114 "Expected %s to be called for %s, "
115 "instead %s called" % (expected_handler,
115 "instead %s called" % (expected_handler,
116 repr(line),
116 repr(line),
117 handler_called))
117 handler_called))
118
118
119
119
120 def run_handler_tests(h_tests):
120 def run_handler_tests(h_tests):
121 """Loop through a series of (input_line, handler_name) pairs, verifying
121 """Loop through a series of (input_line, handler_name) pairs, verifying
122 that, for each ip calls the given handler for the given line.
122 that, for each ip calls the given handler for the given line.
123
123
124 The verbose complaint includes the line passed in, so if that line can
124 The verbose complaint includes the line passed in, so if that line can
125 include enough info to find the error, the tests are modestly
125 include enough info to find the error, the tests are modestly
126 self-documenting.
126 self-documenting.
127 """
127 """
128 for ln, expected_handler in h_tests:
128 for ln, expected_handler in h_tests:
129 global handler_called
129 global handler_called
130 handler_called = None
130 handler_called = None
131 ip.runlines(ln)
131 ip.runlines(ln)
132 check_handler(expected_handler, ln)
132 check_handler(expected_handler, ln)
133
133
134 def run_one_test(ln, expected_handler):
134 def run_one_test(ln, expected_handler):
135 run_handler_tests([(ln, expected_handler)])
135 run_handler_tests([(ln, expected_handler)])
136
136
137
137
138 # =========================================
138 # =========================================
139 # Tests
139 # Tests
140 # =========================================
140 # =========================================
141
141
142
142
143 # Fundamental escape characters + whitespace & misc
143 # Fundamental escape characters + whitespace & misc
144 # =================================================
144 # =================================================
145 esc_handler_tests = [
145 esc_handler_tests = [
146 ( '?thing', handle_help, ),
146 ( '?thing', handle_help, ),
147 ( 'thing?', handle_help ), # '?' can trail...
147 ( 'thing?', handle_help ), # '?' can trail...
148 ( 'thing!', handle_normal), # but only '?' can trail
148 ( 'thing!', handle_normal), # but only '?' can trail
149 ( ' ?thing', handle_normal), # leading whitespace turns off esc chars
149 ( ' ?thing', handle_normal), # leading whitespace turns off esc chars
150 ( '!ls', handle_shell_escape),
150 ( '!ls', handle_shell_escape),
151 ( '! true', handle_shell_escape),
151 ( '! true', handle_shell_escape),
152 ( '!! true', handle_shell_escape),
152 ( '!! true', handle_shell_escape),
153 ( '%magic', handle_magic),
153 ( '%magic', handle_magic),
154 # XXX Possibly, add test for /,; once those are unhooked from %autocall
154 # XXX Possibly, add test for /,; once those are unhooked from %autocall
155 ( 'emacs_mode # PYTHON-MODE', handle_emacs ),
155 ( 'emacs_mode # PYTHON-MODE', handle_emacs ),
156 ( ' ', handle_normal),
156 ( ' ', handle_normal),
157
157
158 # Trailing qmark combos. Odd special cases abound
158 # Trailing qmark combos. Odd special cases abound
159
159
160 # ! always takes priority!
160 # ! always takes priority!
161 ( '!thing?', handle_shell_escape),
161 ( '!thing?', handle_shell_escape),
162 ( '!thing arg?', handle_shell_escape),
162 ( '!thing arg?', handle_shell_escape),
163 ( '!!thing?', handle_shell_escape),
163 ( '!!thing?', handle_shell_escape),
164 ( '!!thing arg?', handle_shell_escape),
164 ( '!!thing arg?', handle_shell_escape),
165 ( ' !!thing arg?', handle_shell_escape),
165
166
166 # For all other leading esc chars, we always trigger help
167 # For all other leading esc chars, we always trigger help
167 ( '%cmd?', handle_help),
168 ( '%cmd?', handle_help),
168 ( '%cmd ?', handle_help),
169 ( '%cmd ?', handle_help),
169 ( '/cmd?', handle_help),
170 ( '/cmd?', handle_help),
170 ( '/cmd ?', handle_help),
171 ( '/cmd ?', handle_help),
171 ( ';cmd?', handle_help),
172 ( ';cmd?', handle_help),
172 ( ',cmd?', handle_help),
173 ( ',cmd?', handle_help),
173 ]
174 ]
174 run_handler_tests(esc_handler_tests)
175 run_handler_tests(esc_handler_tests)
175
176
176
177
177
178
178 # Shell Escapes in Multi-line statements
179 # Shell Escapes in Multi-line statements
179 # ======================================
180 # ======================================
180 #
181 #
181 # We can't test this via runlines, since the hacked-over-for-testing
182 # We can't test this via runlines, since the hacked-over-for-testing
182 # handlers all return None, so continue_prompt never becomes true. Instead
183 # handlers all return None, so continue_prompt never becomes true. Instead
183 # we drop into prefilter directly and pass in continue_prompt.
184 # we drop into prefilter directly and pass in continue_prompt.
184
185
185 old_mls = ip.options.multi_line_specials
186 old_mls = ip.options.multi_line_specials
186 for ln in [ ' !ls $f multi_line_specials %s',
187 for ln in [ ' !ls $f multi_line_specials %s',
187 ' !!ls $f multi_line_specials %s', # !! escapes work on mls
188 ' !!ls $f multi_line_specials %s', # !! escapes work on mls
188 # Trailing ? doesn't trigger help:
189 # Trailing ? doesn't trigger help:
189 ' !ls $f multi_line_specials %s ?',
190 ' !ls $f multi_line_specials %s ?',
190 ' !!ls $f multi_line_specials %s ?',
191 ' !!ls $f multi_line_specials %s ?',
191 ]:
192 ]:
192 ip.options.multi_line_specials = 1
193 ip.options.multi_line_specials = 1
193 on_ln = ln % 'on'
194 on_ln = ln % 'on'
194 ignore = ip.IP.prefilter(on_ln, continue_prompt=True)
195 ignore = ip.IP.prefilter(on_ln, continue_prompt=True)
195 check_handler(handle_shell_escape, on_ln)
196 check_handler(handle_shell_escape, on_ln)
196
197
197 ip.options.multi_line_specials = 0
198 ip.options.multi_line_specials = 0
198 off_ln = ln % 'off'
199 off_ln = ln % 'off'
199 ignore = ip.IP.prefilter(off_ln, continue_prompt=True)
200 ignore = ip.IP.prefilter(off_ln, continue_prompt=True)
200 check_handler(handle_normal, off_ln)
201 check_handler(handle_normal, off_ln)
201
202
202 ip.options.multi_line_specials = old_mls
203 ip.options.multi_line_specials = old_mls
203
204
204
205
205 # Automagic
206 # Automagic
206 # =========
207 # =========
207
208
208 # Pick one magic fun and one non_magic fun, make sure both exist
209 # Pick one magic fun and one non_magic fun, make sure both exist
209 assert hasattr(ip.IP, "magic_cpaste")
210 assert hasattr(ip.IP, "magic_cpaste")
210 assert not hasattr(ip.IP, "magic_does_not_exist")
211 assert not hasattr(ip.IP, "magic_does_not_exist")
211 ip.options.autocall = 0 # gotta have this off to get handle_normal
212 ip.options.autocall = 0 # gotta have this off to get handle_normal
212 ip.options.automagic = 0
213 ip.options.automagic = 0
213 run_handler_tests([
214 run_handler_tests([
214 # Without automagic, only shows up with explicit escape
215 # Without automagic, only shows up with explicit escape
215 ( 'cpaste', handle_normal),
216 ( 'cpaste', handle_normal),
216 ( '%cpaste', handle_magic),
217 ( '%cpaste', handle_magic),
217 ( '%does_not_exist', handle_magic),
218 ( '%does_not_exist', handle_magic),
218 ])
219 ])
219 ip.options.automagic = 1
220 ip.options.automagic = 1
220 run_handler_tests([
221 run_handler_tests([
221 ( 'cpaste', handle_magic),
222 ( 'cpaste', handle_magic),
222 ( '%cpaste', handle_magic),
223 ( '%cpaste', handle_magic),
223 ( 'does_not_exist', handle_normal),
224 ( 'does_not_exist', handle_normal),
224 ( '%does_not_exist', handle_magic),
225 ( '%does_not_exist', handle_magic),
225 ( 'cd /', handle_magic),
226 ( 'cd /', handle_magic),
226 ( 'cd = 2', handle_normal),
227 ( 'cd = 2', handle_normal),
227 ( 'r', handle_magic),
228 ( 'r', handle_magic),
228 ( 'r thing', handle_magic),
229 ( 'r thing', handle_magic),
229 ( 'r"str"', handle_normal),
230 ( 'r"str"', handle_normal),
230 ])
231 ])
231
232
232 # If next elt starts with anything that could be an assignment, func call,
233 # If next elt starts with anything that could be an assignment, func call,
233 # etc, we don't call the magic func, unless explicitly escaped to do so.
234 # etc, we don't call the magic func, unless explicitly escaped to do so.
234 #magic_killing_tests = []
235 #magic_killing_tests = []
235 #for c in list('!=()<>,'):
236 #for c in list('!=()<>,'):
236 # magic_killing_tests.append(('cpaste %s killed_automagic' % c, handle_normal))
237 # magic_killing_tests.append(('cpaste %s killed_automagic' % c, handle_normal))
237 # magic_killing_tests.append(('%%cpaste %s escaped_magic' % c, handle_magic))
238 # magic_killing_tests.append(('%%cpaste %s escaped_magic' % c, handle_magic))
238 #run_handler_tests(magic_killing_tests)
239 #run_handler_tests(magic_killing_tests)
239
240
240 # magic on indented continuation lines -- on iff multi_line_specials == 1
241 # magic on indented continuation lines -- on iff multi_line_specials == 1
241 ip.options.multi_line_specials = 0
242 ip.options.multi_line_specials = 0
242 ln = ' cpaste multi_line off kills magic'
243 ln = ' cpaste multi_line off kills magic'
243 ignore = ip.IP.prefilter(ln, continue_prompt=True)
244 ignore = ip.IP.prefilter(ln, continue_prompt=True)
244 check_handler(handle_normal, ln)
245 check_handler(handle_normal, ln)
245
246
246 ip.options.multi_line_specials = 1
247 ip.options.multi_line_specials = 1
247 ln = ' cpaste multi_line on enables magic'
248 ln = ' cpaste multi_line on enables magic'
248 ignore = ip.IP.prefilter(ln, continue_prompt=True)
249 ignore = ip.IP.prefilter(ln, continue_prompt=True)
249 check_handler(handle_magic, ln)
250 check_handler(handle_magic, ln)
250
251
251 # user namespace shadows the magic one unless shell escaped
252 # user namespace shadows the magic one unless shell escaped
252 ip.user_ns['cpaste'] = 'user_ns'
253 ip.user_ns['cpaste'] = 'user_ns'
253 run_handler_tests([
254 run_handler_tests([
254 ( 'cpaste', handle_normal),
255 ( 'cpaste', handle_normal),
255 ( '%cpaste', handle_magic)])
256 ( '%cpaste', handle_magic)])
256 del ip.user_ns['cpaste']
257 del ip.user_ns['cpaste']
257
258
258
259
259
260
260 # Check for !=() turning off .ofind
261 # Check for !=() turning off .ofind
261 # =================================
262 # =================================
262 class AttributeMutator(object):
263 class AttributeMutator(object):
263 """A class which will be modified on attribute access, to test ofind"""
264 """A class which will be modified on attribute access, to test ofind"""
264 def __init__(self):
265 def __init__(self):
265 self.called = False
266 self.called = False
266
267
267 def getFoo(self): self.called = True
268 def getFoo(self): self.called = True
268 foo = property(getFoo)
269 foo = property(getFoo)
269
270
270 attr_mutator = AttributeMutator()
271 attr_mutator = AttributeMutator()
271 ip.to_user_ns('attr_mutator')
272 ip.to_user_ns('attr_mutator')
272
273
273 ip.options.autocall = 1
274 ip.options.autocall = 1
274
275
275 run_one_test('attr_mutator.foo should mutate', handle_normal)
276 run_one_test('attr_mutator.foo should mutate', handle_normal)
276 check(attr_mutator.called, 'ofind should be called in absence of assign characters')
277 check(attr_mutator.called, 'ofind should be called in absence of assign characters')
277
278
278 for c in list('!=()<>+*/%^&|'):
279 for c in list('!=()<>+*/%^&|'):
279 attr_mutator.called = False
280 attr_mutator.called = False
280 run_one_test('attr_mutator.foo %s should *not* mutate' % c, handle_normal)
281 run_one_test('attr_mutator.foo %s should *not* mutate' % c, handle_normal)
281 run_one_test('attr_mutator.foo%s should *not* mutate' % c, handle_normal)
282 run_one_test('attr_mutator.foo%s should *not* mutate' % c, handle_normal)
282
283
283 check(not attr_mutator.called,
284 check(not attr_mutator.called,
284 'ofind should not be called near character %s' % c)
285 'ofind should not be called near character %s' % c)
285
286
286
287
287
288
288 # Alias expansion
289 # Alias expansion
289 # ===============
290 # ===============
290
291
291 # With autocall on or off, aliases should be shadowed by user, internal and
292 # With autocall on or off, aliases should be shadowed by user, internal and
292 # __builtin__ namespaces
293 # __builtin__ namespaces
293 #
294 #
294 # XXX Can aliases have '.' in their name? With autocall off, that works,
295 # XXX Can aliases have '.' in their name? With autocall off, that works,
295 # with autocall on, it doesn't. Hmmm.
296 # with autocall on, it doesn't. Hmmm.
296 import __builtin__
297 import __builtin__
297 for ac_state in [0,1]:
298 for ac_state in [0,1]:
298 ip.options.autocall = ac_state
299 ip.options.autocall = ac_state
299 ip.IP.alias_table['alias_cmd'] = 'alias_result'
300 ip.IP.alias_table['alias_cmd'] = 'alias_result'
300 ip.IP.alias_table['alias_head.with_dot'] = 'alias_result'
301 ip.IP.alias_table['alias_head.with_dot'] = 'alias_result'
301 run_handler_tests([
302 run_handler_tests([
302 ("alias_cmd", handle_alias),
303 ("alias_cmd", handle_alias),
303 # XXX See note above
304 # XXX See note above
304 #("alias_head.with_dot unshadowed, autocall=%s" % ac_state, handle_alias),
305 #("alias_head.with_dot unshadowed, autocall=%s" % ac_state, handle_alias),
305 ("alias_cmd.something aliases must match whole expr", handle_normal),
306 ("alias_cmd.something aliases must match whole expr", handle_normal),
306 ("alias_cmd /", handle_alias),
307 ("alias_cmd /", handle_alias),
307 ])
308 ])
308
309
309 for ns in [ip.user_ns, ip.IP.internal_ns, __builtin__.__dict__ ]:
310 for ns in [ip.user_ns, ip.IP.internal_ns, __builtin__.__dict__ ]:
310 ns['alias_cmd'] = 'a user value'
311 ns['alias_cmd'] = 'a user value'
311 ns['alias_head'] = 'a user value'
312 ns['alias_head'] = 'a user value'
312 run_handler_tests([
313 run_handler_tests([
313 ("alias_cmd", handle_normal),
314 ("alias_cmd", handle_normal),
314 ("alias_head.with_dot", handle_normal)])
315 ("alias_head.with_dot", handle_normal)])
315 del ns['alias_cmd']
316 del ns['alias_cmd']
316 del ns['alias_head']
317 del ns['alias_head']
317
318
318 ip.options.autocall = 1
319 ip.options.autocall = 1
319
320
320
321
321
322
322
323
323 # Autocall
324 # Autocall
324 # ========
325 # ========
325
326
326 # For all the tests below, 'len' is callable / 'thing' is not
327 # For all the tests below, 'len' is callable / 'thing' is not
327
328
328 # Objects which are instances of IPyAutocall are *always* autocalled
329 # Objects which are instances of IPyAutocall are *always* autocalled
329 import IPython.ipapi
330 import IPython.ipapi
330 class Autocallable(IPython.ipapi.IPyAutocall):
331 class Autocallable(IPython.ipapi.IPyAutocall):
331 def __call__(self):
332 def __call__(self):
332 return "called"
333 return "called"
333
334
334 autocallable = Autocallable()
335 autocallable = Autocallable()
335 ip.to_user_ns('autocallable')
336 ip.to_user_ns('autocallable')
336
337
337
338
338 # First, with autocalling fully off
339 # First, with autocalling fully off
339 ip.options.autocall = 0
340 ip.options.autocall = 0
340 run_handler_tests( [
341 run_handler_tests( [
341 # With no escapes, no autocalling expansions happen, callable or not,
342 # With no escapes, no autocalling expansions happen, callable or not,
342 # unless the obj extends IPyAutocall
343 # unless the obj extends IPyAutocall
343 ( 'len autocall_0', handle_normal),
344 ( 'len autocall_0', handle_normal),
344 ( 'thing autocall_0', handle_normal),
345 ( 'thing autocall_0', handle_normal),
345 ( 'autocallable', handle_auto),
346 ( 'autocallable', handle_auto),
346
347
347 # With explicit escapes, callable and non-callables both get expanded,
348 # With explicit escapes, callable and non-callables both get expanded,
348 # regardless of the %autocall setting:
349 # regardless of the %autocall setting:
349 ( '/len autocall_0', handle_auto),
350 ( '/len autocall_0', handle_auto),
350 ( ',len autocall_0 b0', handle_auto),
351 ( ',len autocall_0 b0', handle_auto),
351 ( ';len autocall_0 b0', handle_auto),
352 ( ';len autocall_0 b0', handle_auto),
352
353
353 ( '/thing autocall_0', handle_auto),
354 ( '/thing autocall_0', handle_auto),
354 ( ',thing autocall_0 b0', handle_auto),
355 ( ',thing autocall_0 b0', handle_auto),
355 ( ';thing autocall_0 b0', handle_auto),
356 ( ';thing autocall_0 b0', handle_auto),
356
357
357 # Explicit autocall should not trigger if there is leading whitespace
358 # Explicit autocall should not trigger if there is leading whitespace
358 ( ' /len autocall_0', handle_normal),
359 ( ' /len autocall_0', handle_normal),
359 ( ' ;len autocall_0', handle_normal),
360 ( ' ;len autocall_0', handle_normal),
360 ( ' ,len autocall_0', handle_normal),
361 ( ' ,len autocall_0', handle_normal),
361 ( ' / len autocall_0', handle_normal),
362 ( ' / len autocall_0', handle_normal),
362
363
363 # But should work if the whitespace comes after the esc char
364 # But should work if the whitespace comes after the esc char
364 ( '/ len autocall_0', handle_auto),
365 ( '/ len autocall_0', handle_auto),
365 ( '; len autocall_0', handle_auto),
366 ( '; len autocall_0', handle_auto),
366 ( ', len autocall_0', handle_auto),
367 ( ', len autocall_0', handle_auto),
367 ( '/ len autocall_0', handle_auto),
368 ( '/ len autocall_0', handle_auto),
368 ])
369 ])
369
370
370
371
371 # Now, with autocall in default, 'smart' mode
372 # Now, with autocall in default, 'smart' mode
372 ip.options.autocall = 1
373 ip.options.autocall = 1
373 run_handler_tests( [
374 run_handler_tests( [
374 # Autocalls without escapes -- only expand if it's callable
375 # Autocalls without escapes -- only expand if it's callable
375 ( 'len a1', handle_auto),
376 ( 'len a1', handle_auto),
376 ( 'thing a1', handle_normal),
377 ( 'thing a1', handle_normal),
377 ( 'autocallable', handle_auto),
378 ( 'autocallable', handle_auto),
378
379
379 # As above, all explicit escapes generate auto-calls, callable or not
380 # As above, all explicit escapes generate auto-calls, callable or not
380 ( '/len a1', handle_auto),
381 ( '/len a1', handle_auto),
381 ( ',len a1 b1', handle_auto),
382 ( ',len a1 b1', handle_auto),
382 ( ';len a1 b1', handle_auto),
383 ( ';len a1 b1', handle_auto),
383 ( '/thing a1', handle_auto),
384 ( '/thing a1', handle_auto),
384 ( ',thing a1 b1', handle_auto),
385 ( ',thing a1 b1', handle_auto),
385 ( ';thing a1 b1', handle_auto),
386 ( ';thing a1 b1', handle_auto),
386
387
387 # Autocalls only happen on things which look like funcs, even if
388 # Autocalls only happen on things which look like funcs, even if
388 # explicitly requested. Which, in this case means they look like a
389 # explicitly requested. Which, in this case means they look like a
389 # sequence of identifiers and . attribute references. Possibly the
390 # sequence of identifiers and . attribute references. Possibly the
390 # second of these two should trigger handle_auto. But not for now.
391 # second of these two should trigger handle_auto. But not for now.
391 ( '"abc".join range(4)', handle_normal),
392 ( '"abc".join range(4)', handle_normal),
392 ( '/"abc".join range(4)', handle_normal),
393 ( '/"abc".join range(4)', handle_normal),
393 ])
394 ])
394
395
395
396
396 # No tests for autocall = 2, since the extra magic there happens inside the
397 # No tests for autocall = 2, since the extra magic there happens inside the
397 # handle_auto function, which our test doesn't examine.
398 # handle_auto function, which our test doesn't examine.
398
399
399 # Note that we leave autocall in default, 1, 'smart' mode
400 # Note that we leave autocall in default, 1, 'smart' mode
400
401
401
402
402 # Autocall / Binary operators
403 # Autocall / Binary operators
403 # ==========================
404 # ==========================
404
405
405 # Even with autocall on, 'len in thing' won't transform.
406 # Even with autocall on, 'len in thing' won't transform.
406 # But ';len in thing' will
407 # But ';len in thing' will
407
408
408 # Note, the tests below don't check for multi-char ops. It could.
409 # Note, the tests below don't check for multi-char ops. It could.
409
410
410 # XXX % is a binary op and should be in the list, too, but fails
411 # XXX % is a binary op and should be in the list, too, but fails
411 bin_ops = list(r'<>,&^|*/+-') + 'is not in and or'.split()
412 bin_ops = list(r'<>,&^|*/+-') + 'is not in and or'.split()
412 bin_tests = []
413 bin_tests = []
413 for b in bin_ops:
414 for b in bin_ops:
414 bin_tests.append(('len %s binop_autocall' % b, handle_normal))
415 bin_tests.append(('len %s binop_autocall' % b, handle_normal))
415 bin_tests.append((';len %s binop_autocall' % b, handle_auto))
416 bin_tests.append((';len %s binop_autocall' % b, handle_auto))
416 bin_tests.append((',len %s binop_autocall' % b, handle_auto))
417 bin_tests.append((',len %s binop_autocall' % b, handle_auto))
417 bin_tests.append(('/len %s binop_autocall' % b, handle_auto))
418 bin_tests.append(('/len %s binop_autocall' % b, handle_auto))
418
419
419 # Who loves auto-generating tests?
420 # Who loves auto-generating tests?
420 run_handler_tests(bin_tests)
421 run_handler_tests(bin_tests)
421
422
422
423
423 # Possibly add tests for namespace shadowing (really ofind's business?).
424 # Possibly add tests for namespace shadowing (really ofind's business?).
424 #
425 #
425 # user > ipython internal > python builtin > alias > magic
426 # user > ipython internal > python builtin > alias > magic
426
427
427
428
428 # ============
429 # ============
429 # Test Summary
430 # Test Summary
430 # ============
431 # ============
431 num_f = len(failures)
432 num_f = len(failures)
432 if verbose:
433 if verbose:
433 print
434 print
434 print "%s tests run, %s failure%s" % (num_tests,
435 print "%s tests run, %s failure%s" % (num_tests,
435 num_f,
436 num_f,
436 num_f != 1 and "s" or "")
437 num_f != 1 and "s" or "")
437 for f in failures:
438 for f in failures:
438 print f
439 print f
439
440
General Comments 0
You need to be logged in to leave comments. Login now