##// END OF EJS Templates
Major refactoring of prefilter mechanism. Much of the transformation process has been moved out of the iplib.InteractiveShell class and into a separate module, IPython.prefilter. In addition, extensive tests have been added for prefiltering.
dan.milstein -
Show More
@@ -0,0 +1,298 b''
1 # -*- coding: utf-8 -*-
2 """
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
5 pieces and triggering the appropriate handlers in iplib to do the actual
6 transforming work.
7 """
8 __docformat__ = "restructuredtext en"
9
10 import re
11 import IPython.ipapi
12
13 class LineInfo(object):
14 """A single line of input and associated info.
15
16 Includes the following as properties:
17
18 line
19 The original, raw line
20
21 continue_prompt
22 Is this line a continuation in a sequence of multiline input?
23
24 pre
25 The initial esc character or whitespace.
26
27 preChar
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
30 always be a single character.
31
32 preWhitespace
33 The leading whitespace from pre if it exists. If there is a preChar,
34 this is just ''.
35
36 iFun
37 The 'function part', which is basically the maximal initial sequence
38 of valid python identifiers and the '.' character. This is what is
39 checked for alias and magic transformations, used for auto-calling,
40 etc.
41
42 theRest
43 Everything else on the line.
44 """
45 def __init__(self, line, continue_prompt):
46 self.line = line
47 self.continue_prompt = continue_prompt
48 self.pre, self.iFun, self.theRest = splitUserInput(line)
49
50 self.preChar = self.pre.strip()
51 if self.preChar:
52 self.preWhitespace = '' # No whitespace allowd before esc chars
53 else:
54 self.preWhitespace = self.pre
55
56 self._oinfo = None
57
58 def ofind(self, ip):
59 """Do a full, attribute-walking lookup of the iFun in the various
60 namespaces for the given IPython InteractiveShell instance.
61
62 Return a dict with keys: found,obj,ospace,ismagic
63
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
66 other, less dangerous handlers.
67
68 Does cache the results of the call, so can be called multiple times
69 without worrying about *further* damaging state.
70 """
71 if not self._oinfo:
72 self._oinfo = ip._ofind(self.iFun)
73 return self._oinfo
74
75
76 def splitUserInput(line, pattern=None):
77 """Split user input into pre-char/whitespace, function part and rest.
78
79 Mostly internal to this module, but also used by iplib.expand_aliases,
80 which passes in a shell pattern.
81 """
82 # It seems to me that the shell splitting should be a separate method.
83
84 if not pattern:
85 pattern = line_split
86 match = pattern.match(line)
87 if not match:
88 #print "match failed for line '%s'" % line
89 try:
90 iFun,theRest = line.split(None,1)
91 except ValueError:
92 #print "split failed for line '%s'" % line
93 iFun,theRest = line,''
94 pre = re.match('^(\s*)(.*)',line).groups()[0]
95 else:
96 pre,iFun,theRest = match.groups()
97
98 # iFun has to be a valid python identifier, so it better be only pure
99 # ascii, no unicode:
100 try:
101 iFun = iFun.encode('ascii')
102 except UnicodeEncodeError:
103 theRest = iFun + u' ' + theRest
104 iFun = u''
105
106 #print 'line:<%s>' % line # dbg
107 #print 'pre <%s> iFun <%s> rest <%s>' % (pre,iFun.strip(),theRest) # dbg
108 return pre,iFun.strip(),theRest
109
110
111 # RegExp for splitting line contents into pre-char//first word-method//rest.
112 # For clarity, each group in on one line.
113
114 # WARNING: update the regexp if the escapes in iplib are changed, as they
115 # are hardwired in.
116
117 # Although it's not solely driven by the regex, note that:
118 # ,;/% only trigger if they are the first character on the line
119 # ! and !! trigger if they are first char(s) *or* follow an indent
120 # ? triggers as first or last char.
121
122 # The three parts of the regex are:
123 # 1) pre: pre_char *or* initial whitespace
124 # 2) iFun: first word/method (mix of \w and '.')
125 # 3) theRest: rest of line
126 line_split = re.compile(r'^([,;/%?]|!!?|\s*)'
127 r'\s*([\w\.]+)\s*'
128 r'(.*)$')
129
130 shell_line_split = re.compile(r'^(\s*)(\S*\s*)(.*$)')
131
132 def prefilter(line_info, ip):
133 """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
135 value, even if it's a blank ('')."""
136 # Note: the order of these checks does matter.
137 for check in [ checkEmacs,
138 checkIPyAutocall,
139 checkMultiLineShell,
140 checkEscChars,
141 checkPythonChars,
142 checkAutomagic,
143 checkAlias,
144 checkAutocall,
145 ]:
146 handler = check(line_info, ip)
147 if handler:
148 return handler(line_info)
149
150 return ip.handle_normal(line_info)
151
152 # Handler checks
153 #
154 # All have the same interface: they take a LineInfo object and a ref to the
155 # iplib.InteractiveShell object. They check the line to see if a particular
156 # handler should be called, and return either a handler or None. The
157 # handlers which they return are *bound* methods of the InteractiveShell
158 # object.
159 #
160 # In general, these checks should only take responsibility for their 'own'
161 # handler. If it doesn't get triggered, they should just return None and
162 # let the rest of the check sequence run.
163 def checkEmacs(l_info,ip):
164 "Emacs ipython-mode tags certain input lines."
165 if l_info.line.endswith('# PYTHON-MODE'):
166 return ip.handle_emacs
167 else:
168 return None
169
170 def checkIPyAutocall(l_info,ip):
171 "Instances of IPyAutocall in user_ns get autocalled immediately"
172 obj = ip.user_ns.get(l_info.iFun, None)
173 if isinstance(obj, IPython.ipapi.IPyAutocall):
174 obj.set_ip(ip.api)
175 return ip.handle_auto
176 else:
177 return None
178
179
180 def checkMultiLineShell(l_info,ip):
181 "Allow ! and !! in multi-line statements if multi_line_specials is on"
182 # Note that this one of the only places we check the first character of
183 # iFun and *not* the preChar. Also note that the below test matches
184 # both ! and !!.
185 if l_info.continue_prompt \
186 and ip.rc.multi_line_specials \
187 and l_info.iFun.startswith(ip.ESC_SHELL):
188 return ip.handle_shell_escape
189 else:
190 return None
191
192 def checkEscChars(l_info,ip):
193 """Check for escape character and return either a handler to handle it,
194 or None if there is no escape char."""
195 if l_info.line[-1] == ip.ESC_HELP \
196 and l_info.preChar != ip.ESC_SHELL \
197 and l_info.preChar != ip.ESC_SH_CAP:
198 # the ? can be at the end, but *not* for either kind of shell escape,
199 # because a ? can be a vaild final char in a shell cmd
200 return ip.handle_help
201 elif l_info.preChar in ip.esc_handlers:
202 return ip.esc_handlers[l_info.preChar]
203 else:
204 return None
205
206 def checkPythonChars(l_info,ip):
207 """If the 'rest' of the line begins with an (in)equality, assginment,
208 function call or tuple comma, we should simply execute the line
209 (regardless of whether or not there's a possible alias, automagic or
210 autocall expansion). This both avoids spurious geattr() accesses on
211 objects upon assignment, and also allows users to assign to either alias
212 or magic names true python variables (the magic/alias systems always
213 take second seat to true python code). E.g. ls='hi', or ls,that=1,2"""
214 if l_info.theRest and l_info.theRest[0] in '!=()<>,+*/%^&|':
215 return ip.handle_normal
216 else:
217 return None
218
219 def checkAutomagic(l_info,ip):
220 """If the iFun is magic, and automagic is on, run it. Note: normal,
221 non-auto magic would already have been triggered via '%' in
222 check_esc_chars. This just checks for automagic."""
223 if not ip.rc.automagic or not hasattr(ip,'magic_'+l_info.iFun):
224 return None
225
226 # We have a likely magic method. Make sure we should actually call it.
227 if l_info.continue_prompt and not ip.rc.multi_line_specials:
228 return None
229
230 head = l_info.iFun.split('.',1)[0]
231 if isShadowed(head,ip):
232 return None
233
234 return ip.handle_magic
235
236
237 def checkAlias(l_info,ip):
238 "Check if the initital identifier on the line is an alias."
239 # Note: aliases can not contain '.'
240 head = l_info.iFun.split('.',1)[0]
241
242 if l_info.iFun not in ip.alias_table \
243 or head not in ip.alias_table \
244 or isShadowed(head,ip):
245 return None
246
247 return ip.handle_alias
248
249
250 def checkAutocall(l_info,ip):
251 "Check if the initial word/function is callable and autocall is on."
252 if not ip.rc.autocall:
253 return None
254
255 oinfo = l_info.ofind(ip) # This can mutate state via getattr
256 if not oinfo['found']:
257 return None
258
259 if callable(oinfo['obj']) \
260 and (not re_exclude_auto.match(l_info.theRest)) \
261 and re_fun_name.match(l_info.iFun):
262 #print 'going auto' # dbg
263 return ip.handle_auto
264 else:
265 #print 'was callable?', callable(l_info.oinfo['obj']) # dbg
266 return None
267
268 # RegExp to identify potential function names
269 re_fun_name = re.compile(r'[a-zA-Z_]([a-zA-Z0-9_.]*) *$')
270
271 # RegExp to exclude strings with this start from autocalling. In
272 # particular, all binary operators should be excluded, so that if foo is
273 # callable, foo OP bar doesn't become foo(OP bar), which is invalid. The
274 # characters '!=()' don't need to be checked for, as the checkPythonChars
275 # routine explicitely does so, to catch direct calls and rebindings of
276 # existing names.
277
278 # Warning: the '-' HAS TO BE AT THE END of the first group, otherwise
279 # it affects the rest of the group in square brackets.
280 re_exclude_auto = re.compile(r'^[,&^\|\*/\+-]'
281 r'|^is |^not |^in |^and |^or ')
282
283 # try to catch also methods for stuff in lists/tuples/dicts: off
284 # (experimental). For this to work, the line_split regexp would need
285 # to be modified so it wouldn't break things at '['. That line is
286 # nasty enough that I shouldn't change it until I can test it _well_.
287 #self.re_fun_name = re.compile (r'[a-zA-Z_]([a-zA-Z0-9_.\[\]]*) ?$')
288
289 # Handler Check Utilities
290 def isShadowed(identifier,ip):
291 """Is the given identifier defined in one of the namespaces which shadow
292 the alias and magic namespaces? Note that an identifier is different
293 than iFun, because it can not contain a '.' character."""
294 # This is much safer than calling ofind, which can change state
295 return (identifier in ip.user_ns \
296 or identifier in ip.internal_ns \
297 or identifier in ip.ns_table['builtin'])
298
@@ -0,0 +1,200 b''
1 """Test the various handlers which do the actual rewriting of the line."""
2
3 from StringIO import StringIO
4 import sys
5
6 failures = []
7 num_tests = 0
8
9 def run(tests):
10 """Loop through a list of (pre, post) inputs, where pre is the string
11 handed to ipython, and post is how that string looks after it's been
12 transformed (i.e. ipython's notion of _i)"""
13 for pre, post in tests:
14 global num_tests
15 num_tests += 1
16 ip.runlines(pre)
17 ip.runlines('_i') # Not sure why I need this...
18 actual = ip.user_ns['_i']
19 if actual != None: actual = actual.rstrip('\n')
20 if actual != post:
21 failures.append('Expected %r to become %r, found %r' % (
22 pre, post, actual))
23
24
25 # Shutdown stdout/stderr so that ipython isn't noisy during tests. Have to
26 # do this *before* importing IPython below.
27 #
28 # NOTE: this means that, if you stick print statements into code as part of
29 # debugging, you won't see the results (unless you comment out some of the
30 # below). I keep on doing this, so apparently it's easy. Or I am an idiot.
31 old_stdout = sys.stdout
32 old_stderr = sys.stderr
33
34 sys.stdout = StringIO()
35 sys.stderr = StringIO()
36
37 import IPython
38 import IPython.ipapi
39
40 IPython.Shell.start()
41 ip = IPython.ipapi.get()
42
43 class CallableIndexable(object):
44 def __getitem__(self, idx): return True
45 def __call__(self, *args, **kws): return True
46
47
48 try:
49 # alias expansion
50
51 # We're using 'true' as our syscall of choice because it doesn't
52 # write anything to stdout.
53
54 # Turn off actual execution of aliases, because it's noisy
55 old_system_cmd = ip.IP.system
56 ip.IP.system = lambda cmd: None
57
58
59 ip.IP.alias_table['an_alias'] = (0, 'true')
60 # These are useful for checking a particular recursive alias issue
61 ip.IP.alias_table['top'] = (0, 'd:/cygwin/top')
62 ip.IP.alias_table['d'] = (0, 'true')
63 run([("an_alias", '_ip.system("true ")'), # alias
64 # Below: recursive aliases should expand whitespace-surrounded
65 # chars, *not* initial chars which happen to be aliases:
66 ("top", '_ip.system("d:/cygwin/top ")'),
67 ])
68 ip.IP.system = old_system_cmd
69
70
71 call_idx = CallableIndexable()
72 ip.to_user_ns('call_idx')
73
74 # For many of the below, we're also checking that leading whitespace
75 # turns off the esc char, which it should unless there is a continuation
76 # line.
77 run([('"no change"', '"no change"'), # normal
78 ("!true", '_ip.system("true")'), # shell_escapes
79 ("!! true", '_ip.magic("sx true")'), # shell_escapes + magic
80 ("!!true", '_ip.magic("sx true")'), # shell_escapes + magic
81 ("%lsmagic", '_ip.magic("lsmagic ")'), # magic
82 ("lsmagic", '_ip.magic("lsmagic ")'), # magic
83 ("a = b # PYTHON-MODE", '_i'), # emacs -- avoids _in cache
84
85 # post-esc-char whitespace goes inside
86 ("! true", '_ip.system(" true")'),
87
88 # Leading whitespace generally turns off escape characters
89 (" ! true", ' ! true'),
90 (" !true", ' !true'),
91
92 # handle_help
93
94 # These are weak tests -- just looking at what the help handlers
95 # logs, which is not how it really does its work. But it still
96 # lets us check the key paths through the handler.
97
98 ("x=1 # what?", "x=1 # what?"), # no help if valid python
99 ("len?", "#?len"), # this is what help logs when it runs
100 ("len??", "#?len?"),
101 ("?len", "#?len"),
102 ])
103
104 # multi_line_specials
105 ip.options.multi_line_specials = 0
106 # W/ multi_line_specials off, leading ws kills esc chars/autoexpansion
107 run([
108 ('if 1:\n !true', 'if 1:\n !true'),
109 ('if 1:\n lsmagic', 'if 1:\n lsmagic'),
110 ('if 1:\n an_alias', 'if 1:\n an_alias'),
111 ])
112
113 ip.options.multi_line_specials = 1
114 # initial indents must be preserved.
115 run([
116 ('if 1:\n !true', 'if 1:\n _ip.system("true")'),
117 ('if 1:\n lsmagic', 'if 1:\n _ip.magic("lsmagic ")'),
118 ('if 1:\n an_alias', 'if 1:\n _ip.system("true ")'),
119 # Weird one
120 ('if 1:\n !!true', 'if 1:\n _ip.magic("sx true")'),
121
122
123 # Even with m_l_s on, all esc_chars except ! are off
124 ('if 1:\n %lsmagic', 'if 1:\n %lsmagic'),
125 ('if 1:\n /fun 1 2', 'if 1:\n /fun 1 2'),
126 ('if 1:\n ;fun 1 2', 'if 1:\n ;fun 1 2'),
127 ('if 1:\n ,fun 1 2', 'if 1:\n ,fun 1 2'),
128 ('if 1:\n ?fun 1 2', 'if 1:\n ?fun 1 2'),
129 # What about !!
130 ])
131
132
133 # Objects which are instances of IPyAutocall are *always* autocalled
134 import IPython.ipapi
135 class Autocallable(IPython.ipapi.IPyAutocall):
136 def __call__(self):
137 return "called"
138
139 autocallable = Autocallable()
140 ip.to_user_ns('autocallable')
141
142 # auto
143 ip.options.autocall = 0
144 # Only explicit escapes or instances of IPyAutocallable should get
145 # expanded
146 run([
147 ('len "abc"', 'len "abc"'),
148 ('autocallable', 'autocallable()'),
149 (",list 1 2 3", 'list("1", "2", "3")'),
150 (";list 1 2 3", 'list("1 2 3")'),
151 ("/len range(1,4)", 'len(range(1,4))'),
152 ])
153 ip.options.autocall = 1
154 run([
155 (",list 1 2 3", 'list("1", "2", "3")'),
156 (";list 1 2 3", 'list("1 2 3")'),
157 ("/len range(1,4)", 'len(range(1,4))'),
158 ('len "abc"', 'len("abc")'),
159 ('len "abc";', 'len("abc");'), # ; is special -- moves out of parens
160 # Autocall is turned off if first arg is [] and the object
161 # is both callable and indexable. Like so:
162 ('len [1,2]', 'len([1,2])'), # len doesn't support __getitem__...
163 ('call_idx [1]', 'call_idx [1]'), # call_idx *does*..
164 ('call_idx 1', 'call_idx(1)'),
165 ('len', 'len '), # only at 2 does it auto-call on single args
166 ])
167
168 ip.options.autocall = 2
169 run([
170 (",list 1 2 3", 'list("1", "2", "3")'),
171 (";list 1 2 3", 'list("1 2 3")'),
172 ("/len range(1,4)", 'len(range(1,4))'),
173 ('len "abc"', 'len("abc")'),
174 ('len "abc";', 'len("abc");'),
175 ('len [1,2]', 'len([1,2])'),
176 ('call_idx [1]', 'call_idx [1]'),
177 ('call_idx 1', 'call_idx(1)'),
178 # This is what's different:
179 ('len', 'len()'), # only at 2 does it auto-call on single args
180 ])
181 ip.options.autocall = 1
182
183 # Ignoring handle_emacs, 'cause it doesn't do anything.
184 finally:
185 sys.stdout = old_stdout
186 sys.stderr = old_stderr
187
188
189
190
191 num_f = len(failures)
192 #if verbose:
193 # print
194
195
196 print "%s tests run, %s failure%s" % (num_tests,
197 num_f,
198 num_f != 1 and "s" or "")
199 for f in failures:
200 print f
@@ -6,7 +6,7 b' Requires Python 2.3 or newer.'
6 6
7 7 This file contains all the classes and helper functions specific to IPython.
8 8
9 $Id: iplib.py 2350 2007-05-15 16:56:44Z vivainio $
9 $Id: iplib.py 2354 2007-05-16 13:06:12Z dan.milstein $
10 10 """
11 11
12 12 #*****************************************************************************
@@ -75,6 +75,8 b' from IPython.genutils import *'
75 75 from IPython.strdispatch import StrDispatch
76 76 import IPython.ipapi
77 77
78 import IPython.prefilter as prefilter
79
78 80 # Globals
79 81
80 82 # store the builtin raw_input globally, and use this always, in case user code
@@ -385,6 +387,7 b' class InteractiveShell(object,Magic):'
385 387
386 388 # escapes for automatic behavior on the command line
387 389 self.ESC_SHELL = '!'
390 self.ESC_SH_CAP = '!!'
388 391 self.ESC_HELP = '?'
389 392 self.ESC_MAGIC = '%'
390 393 self.ESC_QUOTE = ','
@@ -398,6 +401,7 b' class InteractiveShell(object,Magic):'
398 401 self.ESC_MAGIC : self.handle_magic,
399 402 self.ESC_HELP : self.handle_help,
400 403 self.ESC_SHELL : self.handle_shell_escape,
404 self.ESC_SH_CAP : self.handle_shell_escape,
401 405 }
402 406
403 407 # class initializations
@@ -484,57 +488,6 b' class InteractiveShell(object,Magic):'
484 488 header=self.rc.system_header,
485 489 verbose=self.rc.system_verbose)
486 490
487 # RegExp for splitting line contents into pre-char//first
488 # word-method//rest. For clarity, each group in on one line.
489
490 # WARNING: update the regexp if the above escapes are changed, as they
491 # are hardwired in.
492
493 # Don't get carried away with trying to make the autocalling catch too
494 # much: it's better to be conservative rather than to trigger hidden
495 # evals() somewhere and end up causing side effects.
496 self.line_split = re.compile(r'^(\s*[,;/]?\s*)'
497 r'([\?\w\.]+\w*\s*)'
498 r'(\(?.*$)')
499
500 self.shell_line_split = re.compile(r'^(\s*)'
501 r'(\S*\s*)'
502 r'(\(?.*$)')
503
504 # A simpler regexp used as a fallback if the above doesn't work. This
505 # one is more conservative in how it partitions the input. This code
506 # can probably be cleaned up to do everything with just one regexp, but
507 # I'm afraid of breaking something; do it once the unit tests are in
508 # place.
509 self.line_split_fallback = re.compile(r'^(\s*)'
510 r'([%\!\?\w\.]*)'
511 r'(.*)')
512
513 # Original re, keep around for a while in case changes break something
514 #self.line_split = re.compile(r'(^[\s*!\?%,/]?)'
515 # r'(\s*[\?\w\.]+\w*\s*)'
516 # r'(\(?.*$)')
517
518 # RegExp to identify potential function names
519 self.re_fun_name = re.compile(r'[a-zA-Z_]([a-zA-Z0-9_.]*) *$')
520
521 # RegExp to exclude strings with this start from autocalling. In
522 # particular, all binary operators should be excluded, so that if foo
523 # is callable, foo OP bar doesn't become foo(OP bar), which is
524 # invalid. The characters '!=()' don't need to be checked for, as the
525 # _prefilter routine explicitely does so, to catch direct calls and
526 # rebindings of existing names.
527
528 # Warning: the '-' HAS TO BE AT THE END of the first group, otherwise
529 # it affects the rest of the group in square brackets.
530 self.re_exclude_auto = re.compile(r'^[<>,&^\|\*/\+-]'
531 '|^is |^not |^in |^and |^or ')
532
533 # try to catch also methods for stuff in lists/tuples/dicts: off
534 # (experimental). For this to work, the line_split regexp would need
535 # to be modified so it wouldn't break things at '['. That line is
536 # nasty enough that I shouldn't change it until I can test it _well_.
537 #self.re_fun_name = re.compile (r'[a-zA-Z_]([a-zA-Z0-9_.\[\]]*) ?$')
538 491
539 492 # keep track of where we started running (mainly for crash post-mortem)
540 493 self.starting_dir = os.getcwd()
@@ -1731,8 +1684,8 b' want to merge them back into the new files.""" % locals()'
1731 1684
1732 1685 done = Set()
1733 1686 while 1:
1734 pre,fn,rest = self.split_user_input(line, pattern = self.shell_line_split)
1735 # print "!",fn,"!",rest # dbg
1687 pre,fn,rest = prefilter.splitUserInput(line,
1688 prefilter.shell_line_split)
1736 1689 if fn in self.alias_table:
1737 1690 if fn in done:
1738 1691 warn("Cyclic alias definition, repeated '%s'" % fn)
@@ -2056,53 +2009,6 b' want to merge them back into the new files.""" % locals()'
2056 2009 else:
2057 2010 return lineout
2058 2011
2059 def split_user_input(self,line, pattern = None):
2060 """Split user input into pre-char, function part and rest."""
2061
2062 if pattern is None:
2063 pattern = self.line_split
2064
2065 lsplit = pattern.match(line)
2066 if lsplit is None: # no regexp match returns None
2067 #print "match failed for line '%s'" % line # dbg
2068 try:
2069 iFun,theRest = line.split(None,1)
2070 except ValueError:
2071 #print "split failed for line '%s'" % line # dbg
2072 iFun,theRest = line,''
2073 pre = re.match('^(\s*)(.*)',line).groups()[0]
2074 else:
2075 pre,iFun,theRest = lsplit.groups()
2076
2077 # iFun has to be a valid python identifier, so it better be only pure
2078 #ascii, no unicode:
2079 try:
2080 iFun = iFun.encode('ascii')
2081 except UnicodeEncodeError:
2082 theRest = iFun+u' '+theRest
2083 iFun = u''
2084
2085 #print 'line:<%s>' % line # dbg
2086 #print 'pre <%s> iFun <%s> rest <%s>' % (pre,iFun.strip(),theRest) # dbg
2087 return pre,iFun.strip(),theRest
2088
2089 # THIS VERSION IS BROKEN!!! It was intended to prevent spurious attribute
2090 # accesses with a more stringent check of inputs, but it introduced other
2091 # bugs. Disable it for now until I can properly fix it.
2092 def split_user_inputBROKEN(self,line):
2093 """Split user input into pre-char, function part and rest."""
2094
2095 lsplit = self.line_split.match(line)
2096 if lsplit is None: # no regexp match returns None
2097 lsplit = self.line_split_fallback.match(line)
2098
2099 #pre,iFun,theRest = lsplit.groups() # dbg
2100 #print 'line:<%s>' % line # dbg
2101 #print 'pre <%s> iFun <%s> rest <%s>' % (pre,iFun.strip(),theRest) # dbg
2102 #return pre,iFun.strip(),theRest # dbg
2103
2104 return lsplit.groups()
2105
2106 2012 def _prefilter(self, line, continue_prompt):
2107 2013 """Calls different preprocessors, depending on the form of line."""
2108 2014
@@ -2112,15 +2018,6 b' want to merge them back into the new files.""" % locals()'
2112 2018 # needed, update the cache AND log it (so that the input cache array
2113 2019 # stays synced).
2114 2020
2115 # This function is _very_ delicate, and since it's also the one which
2116 # determines IPython's response to user input, it must be as efficient
2117 # as possible. For this reason it has _many_ returns in it, trying
2118 # always to exit as quickly as it can figure out what it needs to do.
2119
2120 # This function is the main responsible for maintaining IPython's
2121 # behavior respectful of Python's semantics. So be _very_ careful if
2122 # making changes to anything here.
2123
2124 2021 #.....................................................................
2125 2022 # Code begins
2126 2023
@@ -2132,145 +2029,33 b' want to merge them back into the new files.""" % locals()'
2132 2029
2133 2030 #print '***line: <%s>' % line # dbg
2134 2031
2032 line_info = prefilter.LineInfo(line, continue_prompt)
2033
2135 2034 # the input history needs to track even empty lines
2136 2035 stripped = line.strip()
2137 2036
2138 2037 if not stripped:
2139 2038 if not continue_prompt:
2140 2039 self.outputcache.prompt_count -= 1
2141 return self.handle_normal(line,continue_prompt)
2142 #return self.handle_normal('',continue_prompt)
2040 return self.handle_normal(line_info)
2143 2041
2144 2042 # print '***cont',continue_prompt # dbg
2145 2043 # special handlers are only allowed for single line statements
2146 2044 if continue_prompt and not self.rc.multi_line_specials:
2147 return self.handle_normal(line,continue_prompt)
2148
2045 return self.handle_normal(line_info)
2149 2046
2150 # For the rest, we need the structure of the input
2151 pre,iFun,theRest = self.split_user_input(line)
2152 2047
2153 2048 # See whether any pre-existing handler can take care of it
2154
2155 2049 rewritten = self.hooks.input_prefilter(stripped)
2156 2050 if rewritten != stripped: # ok, some prefilter did something
2157 rewritten = pre + rewritten # add indentation
2158 return self.handle_normal(rewritten)
2051 rewritten = line_info.pre + rewritten # add indentation
2052 return self.handle_normal(prefilter.LineInfo(rewritten,
2053 continue_prompt))
2159 2054
2160 2055 #print 'pre <%s> iFun <%s> rest <%s>' % (pre,iFun,theRest) # dbg
2161 2056
2162 # Next, check if we can automatically execute this thing
2163
2164 # Allow ! in multi-line statements if multi_line_specials is on:
2165 if continue_prompt and self.rc.multi_line_specials and \
2166 iFun.startswith(self.ESC_SHELL):
2167 return self.handle_shell_escape(line,continue_prompt,
2168 pre=pre,iFun=iFun,
2169 theRest=theRest)
2170
2171 # First check for explicit escapes in the last/first character
2172 handler = None
2173 if line[-1] == self.ESC_HELP and line[0] != self.ESC_SHELL:
2174 handler = self.esc_handlers.get(line[-1]) # the ? can be at the end
2175 if handler is None:
2176 # look at the first character of iFun, NOT of line, so we skip
2177 # leading whitespace in multiline input
2178 handler = self.esc_handlers.get(iFun[0:1])
2179 if handler is not None:
2180 return handler(line,continue_prompt,pre,iFun,theRest)
2181 # Emacs ipython-mode tags certain input lines
2182 if line.endswith('# PYTHON-MODE'):
2183 return self.handle_emacs(line,continue_prompt)
2184
2185 # instances of IPyAutocall in user_ns get autocalled immediately
2186 obj = self.user_ns.get(iFun,None)
2187 if isinstance(obj, IPython.ipapi.IPyAutocall):
2188 obj.set_ip(self.api)
2189 return self.handle_auto(line,continue_prompt,
2190 pre,iFun,theRest,obj)
2191
2192 # Let's try to find if the input line is a magic fn
2193 oinfo = None
2194 if hasattr(self,'magic_'+iFun):
2195 # WARNING: _ofind uses getattr(), so it can consume generators and
2196 # cause other side effects.
2197 oinfo = self._ofind(iFun) # FIXME - _ofind is part of Magic
2198 if oinfo['ismagic']:
2199 # Be careful not to call magics when a variable assignment is
2200 # being made (ls='hi', for example)
2201 if self.rc.automagic and \
2202 (len(theRest)==0 or theRest[0] not in '!=()<>,') and \
2203 (self.rc.multi_line_specials or not continue_prompt):
2204 return self.handle_magic(line,continue_prompt,
2205 pre,iFun,theRest)
2206 else:
2207 return self.handle_normal(line,continue_prompt)
2208
2209 # If the rest of the line begins with an (in)equality, assginment or
2210 # function call, we should not call _ofind but simply execute it.
2211 # This avoids spurious geattr() accesses on objects upon assignment.
2212 #
2213 # It also allows users to assign to either alias or magic names true
2214 # python variables (the magic/alias systems always take second seat to
2215 # true python code).
2216 if theRest and theRest[0] in '!=()':
2217 return self.handle_normal(line,continue_prompt)
2218
2219 if oinfo is None:
2220 # let's try to ensure that _oinfo is ONLY called when autocall is
2221 # on. Since it has inevitable potential side effects, at least
2222 # having autocall off should be a guarantee to the user that no
2223 # weird things will happen.
2224
2225 if self.rc.autocall:
2226 oinfo = self._ofind(iFun) # FIXME - _ofind is part of Magic
2227 else:
2228 # in this case, all that's left is either an alias or
2229 # processing the line normally.
2230 if iFun in self.alias_table:
2231 # if autocall is off, by not running _ofind we won't know
2232 # whether the given name may also exist in one of the
2233 # user's namespace. At this point, it's best to do a
2234 # quick check just to be sure that we don't let aliases
2235 # shadow variables.
2236 head = iFun.split('.',1)[0]
2237 if head in self.user_ns or head in self.internal_ns \
2238 or head in __builtin__.__dict__:
2239 return self.handle_normal(line,continue_prompt)
2240 else:
2241 return self.handle_alias(line,continue_prompt,
2242 pre,iFun,theRest)
2243
2244 else:
2245 return self.handle_normal(line,continue_prompt)
2246
2247 if not oinfo['found']:
2248 return self.handle_normal(line,continue_prompt)
2249 else:
2250 #print 'pre<%s> iFun <%s> rest <%s>' % (pre,iFun,theRest) # dbg
2251 if oinfo['isalias']:
2252 return self.handle_alias(line,continue_prompt,
2253 pre,iFun,theRest)
2254
2255 if (self.rc.autocall
2256 and
2257 (
2258 #only consider exclusion re if not "," or ";" autoquoting
2259 (pre == self.ESC_QUOTE or pre == self.ESC_QUOTE2
2260 or pre == self.ESC_PAREN) or
2261 (not self.re_exclude_auto.match(theRest)))
2262 and
2263 self.re_fun_name.match(iFun) and
2264 callable(oinfo['obj'])) :
2265 #print 'going auto' # dbg
2266 return self.handle_auto(line,continue_prompt,
2267 pre,iFun,theRest,oinfo['obj'])
2268 else:
2269 #print 'was callable?', callable(oinfo['obj']) # dbg
2270 return self.handle_normal(line,continue_prompt)
2057 return prefilter.prefilter(line_info, self)
2271 2058
2272 # If we get here, we have a normal Python line. Log and return.
2273 return self.handle_normal(line,continue_prompt)
2274 2059
2275 2060 def _prefilter_dumb(self, line, continue_prompt):
2276 2061 """simple prefilter function, for debugging"""
@@ -2293,8 +2078,7 b' want to merge them back into the new files.""" % locals()'
2293 2078 # Set the default prefilter() function (this can be user-overridden)
2294 2079 prefilter = multiline_prefilter
2295 2080
2296 def handle_normal(self,line,continue_prompt=None,
2297 pre=None,iFun=None,theRest=None):
2081 def handle_normal(self,line_info):
2298 2082 """Handle normal input lines. Use as a template for handlers."""
2299 2083
2300 2084 # With autoindent on, we need some way to exit the input loop, and I
@@ -2302,6 +2086,8 b' want to merge them back into the new files.""" % locals()'
2302 2086 # clear the line. The rule will be in this case, that either two
2303 2087 # lines of pure whitespace in a row, or a line of pure whitespace but
2304 2088 # of a size different to the indent level, will exit the input loop.
2089 line = line_info.line
2090 continue_prompt = line_info.continue_prompt
2305 2091
2306 2092 if (continue_prompt and self.autoindent and line.isspace() and
2307 2093 (0 < abs(len(line) - self.indent_current_nsp) <= 2 or
@@ -2311,55 +2097,62 b' want to merge them back into the new files.""" % locals()'
2311 2097 self.log(line,line,continue_prompt)
2312 2098 return line
2313 2099
2314 def handle_alias(self,line,continue_prompt=None,
2315 pre=None,iFun=None,theRest=None):
2100 def handle_alias(self,line_info):
2316 2101 """Handle alias input lines. """
2102 transformed = self.expand_aliases(line_info.iFun,line_info.theRest)
2317 2103
2318 2104 # pre is needed, because it carries the leading whitespace. Otherwise
2319 2105 # aliases won't work in indented sections.
2320 transformed = self.expand_aliases(iFun, theRest)
2321 line_out = '%s_ip.system(%s)' % (pre, make_quoted_expr( transformed ))
2322 self.log(line,line_out,continue_prompt)
2106 line_out = '%s_ip.system(%s)' % (line_info.preWhitespace,
2107 make_quoted_expr( transformed ))
2108
2109 self.log(line_info.line,line_out,line_info.continue_prompt)
2323 2110 #print 'line out:',line_out # dbg
2324 2111 return line_out
2325 2112
2326 def handle_shell_escape(self, line, continue_prompt=None,
2327 pre=None,iFun=None,theRest=None):
2113 def handle_shell_escape(self, line_info):
2328 2114 """Execute the line in a shell, empty return value"""
2329
2330 2115 #print 'line in :', `line` # dbg
2331 # Example of a special handler. Others follow a similar pattern.
2116 line = line_info.line
2332 2117 if line.lstrip().startswith('!!'):
2333 # rewrite iFun/theRest to properly hold the call to %sx and
2334 # the actual command to be executed, so handle_magic can work
2335 # correctly
2336 theRest = '%s %s' % (iFun[2:],theRest)
2337 iFun = 'sx'
2338 return self.handle_magic('%ssx %s' % (self.ESC_MAGIC,
2339 line.lstrip()[2:]),
2340 continue_prompt,pre,iFun,theRest)
2118 # rewrite LineInfo's line, iFun and theRest to properly hold the
2119 # call to %sx and the actual command to be executed, so
2120 # handle_magic can work correctly. Note that this works even if
2121 # the line is indented, so it handles multi_line_specials
2122 # properly.
2123 new_rest = line.lstrip()[2:]
2124 line_info.line = '%ssx %s' % (self.ESC_MAGIC,new_rest)
2125 line_info.iFun = 'sx'
2126 line_info.theRest = new_rest
2127 return self.handle_magic(line_info)
2341 2128 else:
2342 2129 cmd=line.lstrip().lstrip('!')
2343 line_out = '%s_ip.system(%s)' % (pre,make_quoted_expr(cmd))
2130 line_out = '%s_ip.system(%s)' % (line_info.preWhitespace,
2131 make_quoted_expr(cmd))
2344 2132 # update cache/log and return
2345 self.log(line,line_out,continue_prompt)
2133 self.log(line,line_out,line_info.continue_prompt)
2346 2134 return line_out
2347 2135
2348 def handle_magic(self, line, continue_prompt=None,
2349 pre=None,iFun=None,theRest=None):
2136 def handle_magic(self, line_info):
2350 2137 """Execute magic functions."""
2351
2352
2353 cmd = '%s_ip.magic(%s)' % (pre,make_quoted_expr(iFun + " " + theRest))
2354 self.log(line,cmd,continue_prompt)
2138 iFun = line_info.iFun
2139 theRest = line_info.theRest
2140 cmd = '%s_ip.magic(%s)' % (line_info.preWhitespace,
2141 make_quoted_expr(iFun + " " + theRest))
2142 self.log(line_info.line,cmd,line_info.continue_prompt)
2355 2143 #print 'in handle_magic, cmd=<%s>' % cmd # dbg
2356 2144 return cmd
2357 2145
2358 def handle_auto(self, line, continue_prompt=None,
2359 pre=None,iFun=None,theRest=None,obj=None):
2146 def handle_auto(self, line_info):
2360 2147 """Hande lines which can be auto-executed, quoting if requested."""
2361 2148
2362 2149 #print 'pre <%s> iFun <%s> rest <%s>' % (pre,iFun,theRest) # dbg
2150 line = line_info.line
2151 iFun = line_info.iFun
2152 theRest = line_info.theRest
2153 pre = line_info.pre
2154 continue_prompt = line_info.continue_prompt
2155 obj = line_info.ofind(self)['obj']
2363 2156
2364 2157 # This should only be active for single-line input!
2365 2158 if continue_prompt:
@@ -2408,14 +2201,14 b' want to merge them back into the new files.""" % locals()'
2408 2201 self.log(line,newcmd,continue_prompt)
2409 2202 return newcmd
2410 2203
2411 def handle_help(self, line, continue_prompt=None,
2412 pre=None,iFun=None,theRest=None):
2204 def handle_help(self, line_info):
2413 2205 """Try to get some help for the object.
2414 2206
2415 2207 obj? or ?obj -> basic information.
2416 2208 obj?? or ??obj -> more details.
2417 2209 """
2418 2210
2211 line = line_info.line
2419 2212 # We need to make sure that we don't process lines which would be
2420 2213 # otherwise valid python, such as "x=1 # what?"
2421 2214 try:
@@ -2426,7 +2219,7 b' want to merge them back into the new files.""" % locals()'
2426 2219 line = line[1:]
2427 2220 elif line[-1]==self.ESC_HELP:
2428 2221 line = line[:-1]
2429 self.log(line,'#?'+line,continue_prompt)
2222 self.log(line,'#?'+line,line_info.continue_prompt)
2430 2223 if line:
2431 2224 #print 'line:<%r>' % line # dbg
2432 2225 self.magic_pinfo(line)
@@ -2435,10 +2228,10 b' want to merge them back into the new files.""" % locals()'
2435 2228 return '' # Empty string is needed here!
2436 2229 except:
2437 2230 # Pass any other exceptions through to the normal handler
2438 return self.handle_normal(line,continue_prompt)
2231 return self.handle_normal(line_info)
2439 2232 else:
2440 2233 # If the code compiles ok, we should handle it normally
2441 return self.handle_normal(line,continue_prompt)
2234 return self.handle_normal(line_info)
2442 2235
2443 2236 def getapi(self):
2444 2237 """ Get an IPApi object for this shell instance
@@ -2452,16 +2245,15 b' want to merge them back into the new files.""" % locals()'
2452 2245 """
2453 2246 return self.api
2454 2247
2455 def handle_emacs(self,line,continue_prompt=None,
2456 pre=None,iFun=None,theRest=None):
2248 def handle_emacs(self, line_info):
2457 2249 """Handle input lines marked by python-mode."""
2458 2250
2459 2251 # Currently, nothing is done. Later more functionality can be added
2460 2252 # here if needed.
2461 2253
2462 2254 # The input cache shouldn't be updated
2255 return line_info.line
2463 2256
2464 return line
2465 2257
2466 2258 def mktempfile(self,data=None):
2467 2259 """Make a new tempfile and return its filename.
@@ -73,6 +73,7 b' def reset_esc_handlers():'
73 73 s.ESC_MAGIC : s.handle_magic,
74 74 s.ESC_HELP : s.handle_help,
75 75 s.ESC_SHELL : s.handle_shell_escape,
76 s.ESC_SH_CAP : s.handle_shell_escape,
76 77 }
77 78 reset_esc_handlers()
78 79
@@ -145,7 +146,14 b' esc_handler_tests = ['
145 146 ( '?thing', handle_help, ),
146 147 ( 'thing?', handle_help ), # '?' can trail...
147 148 ( 'thing!', handle_normal), # but only '?' can trail
148 ( ' ?thing', handle_help), # ignore leading whitespace
149 ( ' ?thing', handle_normal), # leading whitespace turns off esc chars
150 ( '!ls', handle_shell_escape),
151 ( '! true', handle_shell_escape),
152 ( '!! true', handle_shell_escape),
153 ( '%magic', handle_magic),
154 # XXX Possibly, add test for /,; once those are unhooked from %autocall
155 ( 'emacs_mode # PYTHON-MODE', handle_emacs ),
156 ( ' ', handle_normal),
149 157 # Trailing qmark combos. Odd special cases abound
150 158 ( '!thing?', handle_shell_escape), # trailing '?' loses to shell esc
151 159 ( '!thing ?', handle_shell_escape),
@@ -154,11 +162,6 b' esc_handler_tests = ['
154 162 ( '/cmd?', handle_help),
155 163 ( ';cmd?', handle_help),
156 164 ( ',cmd?', handle_help),
157 ( '!ls', handle_shell_escape ),
158 ( '%magic', handle_magic),
159 # Possibly, add test for /,; once those are unhooked from %autocall
160 ( 'emacs_mode # PYTHON-MODE', handle_emacs ),
161 ( ' ', handle_normal),
162 165 ]
163 166 run_handler_tests(esc_handler_tests)
164 167
@@ -167,19 +170,26 b' run_handler_tests(esc_handler_tests)'
167 170 # Shell Escapes in Multi-line statements
168 171 # ======================================
169 172 #
170 # We can't test this via runlines, since the hacked over-handlers all
171 # return None, so continue_prompt never becomes true. Instead we drop
172 # into prefilter directly and pass in continue_prompt.
173 # We can't test this via runlines, since the hacked-over-for-testing
174 # handlers all return None, so continue_prompt never becomes true. Instead
175 # we drop into prefilter directly and pass in continue_prompt.
173 176
174 177 old_mls = ip.options.multi_line_specials
175 ln = '!ls $f multi_line_specials on'
176 ignore = ip.IP.prefilter(ln, continue_prompt=True)
177 check_handler(handle_shell_escape, ln)
178 for ln in [ ' !ls $f multi_line_specials %s',
179 ' !!ls $f multi_line_specials %s', # !! escapes work on mls
180 # Trailing ? doesn't trigger help:
181 ' !ls $f multi_line_specials %s ?',
182 ' !!ls $f multi_line_specials %s ?',
183 ]:
184 ip.options.multi_line_specials = 1
185 on_ln = ln % 'on'
186 ignore = ip.IP.prefilter(on_ln, continue_prompt=True)
187 check_handler(handle_shell_escape, on_ln)
178 188
179 189 ip.options.multi_line_specials = 0
180 ln = '!ls $f multi_line_specials off'
181 ignore = ip.IP.prefilter(ln, continue_prompt=True)
182 check_handler(handle_normal, ln)
190 off_ln = ln % 'off'
191 ignore = ip.IP.prefilter(off_ln, continue_prompt=True)
192 check_handler(handle_normal, off_ln)
183 193
184 194 ip.options.multi_line_specials = old_mls
185 195
@@ -190,6 +200,7 b' ip.options.multi_line_specials = old_mls'
190 200 # Pick one magic fun and one non_magic fun, make sure both exist
191 201 assert hasattr(ip.IP, "magic_cpaste")
192 202 assert not hasattr(ip.IP, "magic_does_not_exist")
203 ip.options.autocall = 0 # gotta have this off to get handle_normal
193 204 ip.options.automagic = 0
194 205 run_handler_tests([
195 206 # Without automagic, only shows up with explicit escape
@@ -231,6 +242,7 b' run_handler_tests(['
231 242 del ip.user_ns['cpaste']
232 243
233 244
245
234 246 # Check for !=() turning off .ofind
235 247 # =================================
236 248 class AttributeMutator(object):
@@ -249,7 +261,7 b' ip.options.autocall = 1'
249 261 run_one_test('attr_mutator.foo should mutate', handle_normal)
250 262 check(attr_mutator.called, 'ofind should be called in absence of assign characters')
251 263
252 for c in list('!=()'): # XXX What about <> -- they *are* important above
264 for c in list('!=()<>+*/%^&|'):
253 265 attr_mutator.called = False
254 266 run_one_test('attr_mutator.foo %s should *not* mutate' % c, handle_normal)
255 267 run_one_test('attr_mutator.foo%s should *not* mutate' % c, handle_normal)
@@ -296,51 +308,73 b' ip.options.autocall = 1'
296 308 # Autocall
297 309 # ========
298 310
299 # First, with autocalling fully off
300 ip.options.autocall = 0
301 run_handler_tests( [
302 # Since len is callable, these *should* get auto-called
311 # For all the tests below, 'len' is callable / 'thing' is not
303 312
304 # XXX Except, at the moment, they're *not*, because the code is wrong
305 # XXX So I'm commenting 'em out to keep the tests quiet
313 # Objects which are instances of IPyAutocall are *always* autocalled
314 import IPython.ipapi
315 class Autocallable(IPython.ipapi.IPyAutocall):
316 def __call__(self):
317 return "called"
306 318
307 #( '/len autocall_0', handle_auto),
308 #( ',len autocall_0 b0', handle_auto),
309 #( ';len autocall_0 b0', handle_auto),
319 autocallable = Autocallable()
320 ip.to_user_ns('autocallable')
310 321
311 # But these, since fun is not a callable, should *not* get auto-called
312 ( '/fun autocall_0', handle_normal),
313 ( ',fun autocall_0 b0', handle_normal),
314 ( ';fun autocall_0 b0', handle_normal),
315 322
316 # With no escapes, no autocalling should happen, callable or not
323 # First, with autocalling fully off
324 ip.options.autocall = 0
325 run_handler_tests( [
326 # With no escapes, no autocalling expansions happen, callable or not,
327 # unless the obj extends IPyAutocall
317 328 ( 'len autocall_0', handle_normal),
318 ( 'fun autocall_0', handle_normal),
329 ( 'thing autocall_0', handle_normal),
330 ( 'autocallable', handle_auto),
331
332 # With explicit escapes, callable and non-callables both get expanded,
333 # regardless of the %autocall setting:
334 ( '/len autocall_0', handle_auto),
335 ( ',len autocall_0 b0', handle_auto),
336 ( ';len autocall_0 b0', handle_auto),
337
338 ( '/thing autocall_0', handle_auto),
339 ( ',thing autocall_0 b0', handle_auto),
340 ( ';thing autocall_0 b0', handle_auto),
341
342 # Explicit autocall should not trigger if there is leading whitespace
343 ( ' /len autocall_0', handle_normal),
344 ( ' ;len autocall_0', handle_normal),
345 ( ' ,len autocall_0', handle_normal),
346 ( ' / len autocall_0', handle_normal),
347
348 # But should work if the whitespace comes after the esc char
349 ( '/ len autocall_0', handle_auto),
350 ( '; len autocall_0', handle_auto),
351 ( ', len autocall_0', handle_auto),
352 ( '/ len autocall_0', handle_auto),
319 353 ])
320 354
321 355
322 356 # Now, with autocall in default, 'smart' mode
323 357 ip.options.autocall = 1
324 358 run_handler_tests( [
325 # Since len is callable, these *do* get auto-called
359 # Autocalls without escapes -- only expand if it's callable
360 ( 'len a1', handle_auto),
361 ( 'thing a1', handle_normal),
362 ( 'autocallable', handle_auto),
363
364 # As above, all explicit escapes generate auto-calls, callable or not
326 365 ( '/len a1', handle_auto),
327 366 ( ',len a1 b1', handle_auto),
328 367 ( ';len a1 b1', handle_auto),
329 # But these, since fun is not a callable, should *not* get auto-called
330 ( '/fun a1', handle_normal),
331 ( ',fun a1 b1', handle_normal),
332 ( ';fun a1 b1', handle_normal),
333 # Autocalls without escapes
334 ( 'len a1', handle_auto),
335 ( 'fun a1', handle_normal), # Not callable -> no add
368 ( '/thing a1', handle_auto),
369 ( ',thing a1 b1', handle_auto),
370 ( ';thing a1 b1', handle_auto),
371
336 372 # Autocalls only happen on things which look like funcs, even if
337 373 # explicitly requested. Which, in this case means they look like a
338 # sequence of identifiers and . attribute references. So the second
339 # test should pass, but it's not at the moment (meaning, IPython is
340 # attempting to run an autocall). Though it does blow up in ipython
341 # later (because of how lines are split, I think).
374 # sequence of identifiers and . attribute references. Possibly the
375 # second of these two should trigger handle_auto. But not for now.
342 376 ( '"abc".join range(4)', handle_normal),
343 # XXX ( '/"abc".join range(4)', handle_normal),
377 ( '/"abc".join range(4)', handle_normal),
344 378 ])
345 379
346 380
General Comments 0
You need to be logged in to leave comments. Login now