##// END OF EJS Templates
Fix handling of lines like '%%foo?' in cell magic logic.
Fernando Perez -
Show More
@@ -1,903 +1,902 b''
1 """Analysis of text input into executable blocks.
1 """Analysis of text input into executable blocks.
2
2
3 The main class in this module, :class:`InputSplitter`, is designed to break
3 The main class in this module, :class:`InputSplitter`, is designed to break
4 input from either interactive, line-by-line environments or block-based ones,
4 input from either interactive, line-by-line environments or block-based ones,
5 into standalone blocks that can be executed by Python as 'single' statements
5 into standalone blocks that can be executed by Python as 'single' statements
6 (thus triggering sys.displayhook).
6 (thus triggering sys.displayhook).
7
7
8 A companion, :class:`IPythonInputSplitter`, provides the same functionality but
8 A companion, :class:`IPythonInputSplitter`, provides the same functionality but
9 with full support for the extended IPython syntax (magics, system calls, etc).
9 with full support for the extended IPython syntax (magics, system calls, etc).
10
10
11 For more details, see the class docstring below.
11 For more details, see the class docstring below.
12
12
13 Syntax Transformations
13 Syntax Transformations
14 ----------------------
14 ----------------------
15
15
16 One of the main jobs of the code in this file is to apply all syntax
16 One of the main jobs of the code in this file is to apply all syntax
17 transformations that make up 'the IPython language', i.e. magics, shell
17 transformations that make up 'the IPython language', i.e. magics, shell
18 escapes, etc. All transformations should be implemented as *fully stateless*
18 escapes, etc. All transformations should be implemented as *fully stateless*
19 entities, that simply take one line as their input and return a line.
19 entities, that simply take one line as their input and return a line.
20 Internally for implementation purposes they may be a normal function or a
20 Internally for implementation purposes they may be a normal function or a
21 callable object, but the only input they receive will be a single line and they
21 callable object, but the only input they receive will be a single line and they
22 should only return a line, without holding any data-dependent state between
22 should only return a line, without holding any data-dependent state between
23 calls.
23 calls.
24
24
25 As an example, the EscapedTransformer is a class so we can more clearly group
25 As an example, the EscapedTransformer is a class so we can more clearly group
26 together the functionality of dispatching to individual functions based on the
26 together the functionality of dispatching to individual functions based on the
27 starting escape character, but the only method for public use is its call
27 starting escape character, but the only method for public use is its call
28 method.
28 method.
29
29
30
30
31 ToDo
31 ToDo
32 ----
32 ----
33
33
34 - Should we make push() actually raise an exception once push_accepts_more()
34 - Should we make push() actually raise an exception once push_accepts_more()
35 returns False?
35 returns False?
36
36
37 - Naming cleanups. The tr_* names aren't the most elegant, though now they are
37 - Naming cleanups. The tr_* names aren't the most elegant, though now they are
38 at least just attributes of a class so not really very exposed.
38 at least just attributes of a class so not really very exposed.
39
39
40 - Think about the best way to support dynamic things: automagic, autocall,
40 - Think about the best way to support dynamic things: automagic, autocall,
41 macros, etc.
41 macros, etc.
42
42
43 - Think of a better heuristic for the application of the transforms in
43 - Think of a better heuristic for the application of the transforms in
44 IPythonInputSplitter.push() than looking at the buffer ending in ':'. Idea:
44 IPythonInputSplitter.push() than looking at the buffer ending in ':'. Idea:
45 track indentation change events (indent, dedent, nothing) and apply them only
45 track indentation change events (indent, dedent, nothing) and apply them only
46 if the indentation went up, but not otherwise.
46 if the indentation went up, but not otherwise.
47
47
48 - Think of the cleanest way for supporting user-specified transformations (the
48 - Think of the cleanest way for supporting user-specified transformations (the
49 user prefilters we had before).
49 user prefilters we had before).
50
50
51 Authors
51 Authors
52 -------
52 -------
53
53
54 * Fernando Perez
54 * Fernando Perez
55 * Brian Granger
55 * Brian Granger
56 """
56 """
57 #-----------------------------------------------------------------------------
57 #-----------------------------------------------------------------------------
58 # Copyright (C) 2010 The IPython Development Team
58 # Copyright (C) 2010 The IPython Development Team
59 #
59 #
60 # Distributed under the terms of the BSD License. The full license is in
60 # Distributed under the terms of the BSD License. The full license is in
61 # the file COPYING, distributed as part of this software.
61 # the file COPYING, distributed as part of this software.
62 #-----------------------------------------------------------------------------
62 #-----------------------------------------------------------------------------
63 from __future__ import print_function
64
63
65 #-----------------------------------------------------------------------------
64 #-----------------------------------------------------------------------------
66 # Imports
65 # Imports
67 #-----------------------------------------------------------------------------
66 #-----------------------------------------------------------------------------
68 # stdlib
67 # stdlib
69 import ast
68 import ast
70 import codeop
69 import codeop
71 import re
70 import re
72 import sys
71 import sys
73 import tokenize
72 import tokenize
74 from StringIO import StringIO
73 from StringIO import StringIO
75
74
76 # IPython modules
75 # IPython modules
77 from IPython.core.splitinput import split_user_input, LineInfo
76 from IPython.core.splitinput import split_user_input, LineInfo
78 from IPython.utils.py3compat import cast_unicode
77 from IPython.utils.py3compat import cast_unicode
79
78
80 #-----------------------------------------------------------------------------
79 #-----------------------------------------------------------------------------
81 # Globals
80 # Globals
82 #-----------------------------------------------------------------------------
81 #-----------------------------------------------------------------------------
83
82
84 # The escape sequences that define the syntax transformations IPython will
83 # The escape sequences that define the syntax transformations IPython will
85 # apply to user input. These can NOT be just changed here: many regular
84 # apply to user input. These can NOT be just changed here: many regular
86 # expressions and other parts of the code may use their hardcoded values, and
85 # expressions and other parts of the code may use their hardcoded values, and
87 # for all intents and purposes they constitute the 'IPython syntax', so they
86 # for all intents and purposes they constitute the 'IPython syntax', so they
88 # should be considered fixed.
87 # should be considered fixed.
89
88
90 ESC_SHELL = '!' # Send line to underlying system shell
89 ESC_SHELL = '!' # Send line to underlying system shell
91 ESC_SH_CAP = '!!' # Send line to system shell and capture output
90 ESC_SH_CAP = '!!' # Send line to system shell and capture output
92 ESC_HELP = '?' # Find information about object
91 ESC_HELP = '?' # Find information about object
93 ESC_HELP2 = '??' # Find extra-detailed information about object
92 ESC_HELP2 = '??' # Find extra-detailed information about object
94 ESC_MAGIC = '%' # Call magic function
93 ESC_MAGIC = '%' # Call magic function
95 ESC_QUOTE = ',' # Split args on whitespace, quote each as string and call
94 ESC_QUOTE = ',' # Split args on whitespace, quote each as string and call
96 ESC_QUOTE2 = ';' # Quote all args as a single string, call
95 ESC_QUOTE2 = ';' # Quote all args as a single string, call
97 ESC_PAREN = '/' # Call first argument with rest of line as arguments
96 ESC_PAREN = '/' # Call first argument with rest of line as arguments
98
97
99 #-----------------------------------------------------------------------------
98 #-----------------------------------------------------------------------------
100 # Utilities
99 # Utilities
101 #-----------------------------------------------------------------------------
100 #-----------------------------------------------------------------------------
102
101
103 # FIXME: These are general-purpose utilities that later can be moved to the
102 # FIXME: These are general-purpose utilities that later can be moved to the
104 # general ward. Kept here for now because we're being very strict about test
103 # general ward. Kept here for now because we're being very strict about test
105 # coverage with this code, and this lets us ensure that we keep 100% coverage
104 # coverage with this code, and this lets us ensure that we keep 100% coverage
106 # while developing.
105 # while developing.
107
106
108 # compiled regexps for autoindent management
107 # compiled regexps for autoindent management
109 dedent_re = re.compile('|'.join([
108 dedent_re = re.compile('|'.join([
110 r'^\s+raise(\s.*)?$', # raise statement (+ space + other stuff, maybe)
109 r'^\s+raise(\s.*)?$', # raise statement (+ space + other stuff, maybe)
111 r'^\s+raise\([^\)]*\).*$', # wacky raise with immediate open paren
110 r'^\s+raise\([^\)]*\).*$', # wacky raise with immediate open paren
112 r'^\s+return(\s.*)?$', # normal return (+ space + other stuff, maybe)
111 r'^\s+return(\s.*)?$', # normal return (+ space + other stuff, maybe)
113 r'^\s+return\([^\)]*\).*$', # wacky return with immediate open paren
112 r'^\s+return\([^\)]*\).*$', # wacky return with immediate open paren
114 r'^\s+pass\s*$' # pass (optionally followed by trailing spaces)
113 r'^\s+pass\s*$' # pass (optionally followed by trailing spaces)
115 ]))
114 ]))
116 ini_spaces_re = re.compile(r'^([ \t\r\f\v]+)')
115 ini_spaces_re = re.compile(r'^([ \t\r\f\v]+)')
117
116
118 # regexp to match pure comment lines so we don't accidentally insert 'if 1:'
117 # regexp to match pure comment lines so we don't accidentally insert 'if 1:'
119 # before pure comments
118 # before pure comments
120 comment_line_re = re.compile('^\s*\#')
119 comment_line_re = re.compile('^\s*\#')
121
120
122
121
123 def num_ini_spaces(s):
122 def num_ini_spaces(s):
124 """Return the number of initial spaces in a string.
123 """Return the number of initial spaces in a string.
125
124
126 Note that tabs are counted as a single space. For now, we do *not* support
125 Note that tabs are counted as a single space. For now, we do *not* support
127 mixing of tabs and spaces in the user's input.
126 mixing of tabs and spaces in the user's input.
128
127
129 Parameters
128 Parameters
130 ----------
129 ----------
131 s : string
130 s : string
132
131
133 Returns
132 Returns
134 -------
133 -------
135 n : int
134 n : int
136 """
135 """
137
136
138 ini_spaces = ini_spaces_re.match(s)
137 ini_spaces = ini_spaces_re.match(s)
139 if ini_spaces:
138 if ini_spaces:
140 return ini_spaces.end()
139 return ini_spaces.end()
141 else:
140 else:
142 return 0
141 return 0
143
142
144 def last_blank(src):
143 def last_blank(src):
145 """Determine if the input source ends in a blank.
144 """Determine if the input source ends in a blank.
146
145
147 A blank is either a newline or a line consisting of whitespace.
146 A blank is either a newline or a line consisting of whitespace.
148
147
149 Parameters
148 Parameters
150 ----------
149 ----------
151 src : string
150 src : string
152 A single or multiline string.
151 A single or multiline string.
153 """
152 """
154 if not src: return False
153 if not src: return False
155 ll = src.splitlines()[-1]
154 ll = src.splitlines()[-1]
156 return (ll == '') or ll.isspace()
155 return (ll == '') or ll.isspace()
157
156
158
157
159 last_two_blanks_re = re.compile(r'\n\s*\n\s*$', re.MULTILINE)
158 last_two_blanks_re = re.compile(r'\n\s*\n\s*$', re.MULTILINE)
160 last_two_blanks_re2 = re.compile(r'.+\n\s*\n\s+$', re.MULTILINE)
159 last_two_blanks_re2 = re.compile(r'.+\n\s*\n\s+$', re.MULTILINE)
161
160
162 def last_two_blanks(src):
161 def last_two_blanks(src):
163 """Determine if the input source ends in two blanks.
162 """Determine if the input source ends in two blanks.
164
163
165 A blank is either a newline or a line consisting of whitespace.
164 A blank is either a newline or a line consisting of whitespace.
166
165
167 Parameters
166 Parameters
168 ----------
167 ----------
169 src : string
168 src : string
170 A single or multiline string.
169 A single or multiline string.
171 """
170 """
172 if not src: return False
171 if not src: return False
173 # The logic here is tricky: I couldn't get a regexp to work and pass all
172 # The logic here is tricky: I couldn't get a regexp to work and pass all
174 # the tests, so I took a different approach: split the source by lines,
173 # the tests, so I took a different approach: split the source by lines,
175 # grab the last two and prepend '###\n' as a stand-in for whatever was in
174 # grab the last two and prepend '###\n' as a stand-in for whatever was in
176 # the body before the last two lines. Then, with that structure, it's
175 # the body before the last two lines. Then, with that structure, it's
177 # possible to analyze with two regexps. Not the most elegant solution, but
176 # possible to analyze with two regexps. Not the most elegant solution, but
178 # it works. If anyone tries to change this logic, make sure to validate
177 # it works. If anyone tries to change this logic, make sure to validate
179 # the whole test suite first!
178 # the whole test suite first!
180 new_src = '\n'.join(['###\n'] + src.splitlines()[-2:])
179 new_src = '\n'.join(['###\n'] + src.splitlines()[-2:])
181 return (bool(last_two_blanks_re.match(new_src)) or
180 return (bool(last_two_blanks_re.match(new_src)) or
182 bool(last_two_blanks_re2.match(new_src)) )
181 bool(last_two_blanks_re2.match(new_src)) )
183
182
184
183
185 def remove_comments(src):
184 def remove_comments(src):
186 """Remove all comments from input source.
185 """Remove all comments from input source.
187
186
188 Note: comments are NOT recognized inside of strings!
187 Note: comments are NOT recognized inside of strings!
189
188
190 Parameters
189 Parameters
191 ----------
190 ----------
192 src : string
191 src : string
193 A single or multiline input string.
192 A single or multiline input string.
194
193
195 Returns
194 Returns
196 -------
195 -------
197 String with all Python comments removed.
196 String with all Python comments removed.
198 """
197 """
199
198
200 return re.sub('#.*', '', src)
199 return re.sub('#.*', '', src)
201
200
202 def has_comment(src):
201 def has_comment(src):
203 """Indicate whether an input line has (i.e. ends in, or is) a comment.
202 """Indicate whether an input line has (i.e. ends in, or is) a comment.
204
203
205 This uses tokenize, so it can distinguish comments from # inside strings.
204 This uses tokenize, so it can distinguish comments from # inside strings.
206
205
207 Parameters
206 Parameters
208 ----------
207 ----------
209 src : string
208 src : string
210 A single line input string.
209 A single line input string.
211
210
212 Returns
211 Returns
213 -------
212 -------
214 Boolean: True if source has a comment.
213 Boolean: True if source has a comment.
215 """
214 """
216 readline = StringIO(src).readline
215 readline = StringIO(src).readline
217 toktypes = set()
216 toktypes = set()
218 try:
217 try:
219 for t in tokenize.generate_tokens(readline):
218 for t in tokenize.generate_tokens(readline):
220 toktypes.add(t[0])
219 toktypes.add(t[0])
221 except tokenize.TokenError:
220 except tokenize.TokenError:
222 pass
221 pass
223 return(tokenize.COMMENT in toktypes)
222 return(tokenize.COMMENT in toktypes)
224
223
225
224
226 def get_input_encoding():
225 def get_input_encoding():
227 """Return the default standard input encoding.
226 """Return the default standard input encoding.
228
227
229 If sys.stdin has no encoding, 'ascii' is returned."""
228 If sys.stdin has no encoding, 'ascii' is returned."""
230 # There are strange environments for which sys.stdin.encoding is None. We
229 # There are strange environments for which sys.stdin.encoding is None. We
231 # ensure that a valid encoding is returned.
230 # ensure that a valid encoding is returned.
232 encoding = getattr(sys.stdin, 'encoding', None)
231 encoding = getattr(sys.stdin, 'encoding', None)
233 if encoding is None:
232 if encoding is None:
234 encoding = 'ascii'
233 encoding = 'ascii'
235 return encoding
234 return encoding
236
235
237 #-----------------------------------------------------------------------------
236 #-----------------------------------------------------------------------------
238 # Classes and functions for normal Python syntax handling
237 # Classes and functions for normal Python syntax handling
239 #-----------------------------------------------------------------------------
238 #-----------------------------------------------------------------------------
240
239
241 class InputSplitter(object):
240 class InputSplitter(object):
242 """An object that can accumulate lines of Python source before execution.
241 """An object that can accumulate lines of Python source before execution.
243
242
244 This object is designed to be fed python source line-by-line, using
243 This object is designed to be fed python source line-by-line, using
245 :meth:`push`. It will return on each push whether the currently pushed
244 :meth:`push`. It will return on each push whether the currently pushed
246 code could be executed already. In addition, it provides a method called
245 code could be executed already. In addition, it provides a method called
247 :meth:`push_accepts_more` that can be used to query whether more input
246 :meth:`push_accepts_more` that can be used to query whether more input
248 can be pushed into a single interactive block.
247 can be pushed into a single interactive block.
249
248
250 This is a simple example of how an interactive terminal-based client can use
249 This is a simple example of how an interactive terminal-based client can use
251 this tool::
250 this tool::
252
251
253 isp = InputSplitter()
252 isp = InputSplitter()
254 while isp.push_accepts_more():
253 while isp.push_accepts_more():
255 indent = ' '*isp.indent_spaces
254 indent = ' '*isp.indent_spaces
256 prompt = '>>> ' + indent
255 prompt = '>>> ' + indent
257 line = indent + raw_input(prompt)
256 line = indent + raw_input(prompt)
258 isp.push(line)
257 isp.push(line)
259 print 'Input source was:\n', isp.source_reset(),
258 print 'Input source was:\n', isp.source_reset(),
260 """
259 """
261 # Number of spaces of indentation computed from input that has been pushed
260 # Number of spaces of indentation computed from input that has been pushed
262 # so far. This is the attributes callers should query to get the current
261 # so far. This is the attributes callers should query to get the current
263 # indentation level, in order to provide auto-indent facilities.
262 # indentation level, in order to provide auto-indent facilities.
264 indent_spaces = 0
263 indent_spaces = 0
265 # String, indicating the default input encoding. It is computed by default
264 # String, indicating the default input encoding. It is computed by default
266 # at initialization time via get_input_encoding(), but it can be reset by a
265 # at initialization time via get_input_encoding(), but it can be reset by a
267 # client with specific knowledge of the encoding.
266 # client with specific knowledge of the encoding.
268 encoding = ''
267 encoding = ''
269 # String where the current full source input is stored, properly encoded.
268 # String where the current full source input is stored, properly encoded.
270 # Reading this attribute is the normal way of querying the currently pushed
269 # Reading this attribute is the normal way of querying the currently pushed
271 # source code, that has been properly encoded.
270 # source code, that has been properly encoded.
272 source = ''
271 source = ''
273 # Code object corresponding to the current source. It is automatically
272 # Code object corresponding to the current source. It is automatically
274 # synced to the source, so it can be queried at any time to obtain the code
273 # synced to the source, so it can be queried at any time to obtain the code
275 # object; it will be None if the source doesn't compile to valid Python.
274 # object; it will be None if the source doesn't compile to valid Python.
276 code = None
275 code = None
277 # Input mode
276 # Input mode
278 input_mode = 'line'
277 input_mode = 'line'
279
278
280 # Private attributes
279 # Private attributes
281
280
282 # List with lines of input accumulated so far
281 # List with lines of input accumulated so far
283 _buffer = None
282 _buffer = None
284 # Command compiler
283 # Command compiler
285 _compile = None
284 _compile = None
286 # Mark when input has changed indentation all the way back to flush-left
285 # Mark when input has changed indentation all the way back to flush-left
287 _full_dedent = False
286 _full_dedent = False
288 # Boolean indicating whether the current block is complete
287 # Boolean indicating whether the current block is complete
289 _is_complete = None
288 _is_complete = None
290
289
291 def __init__(self, input_mode=None):
290 def __init__(self, input_mode=None):
292 """Create a new InputSplitter instance.
291 """Create a new InputSplitter instance.
293
292
294 Parameters
293 Parameters
295 ----------
294 ----------
296 input_mode : str
295 input_mode : str
297
296
298 One of ['line', 'cell']; default is 'line'.
297 One of ['line', 'cell']; default is 'line'.
299
298
300 The input_mode parameter controls how new inputs are used when fed via
299 The input_mode parameter controls how new inputs are used when fed via
301 the :meth:`push` method:
300 the :meth:`push` method:
302
301
303 - 'line': meant for line-oriented clients, inputs are appended one at a
302 - 'line': meant for line-oriented clients, inputs are appended one at a
304 time to the internal buffer and the whole buffer is compiled.
303 time to the internal buffer and the whole buffer is compiled.
305
304
306 - 'cell': meant for clients that can edit multi-line 'cells' of text at
305 - 'cell': meant for clients that can edit multi-line 'cells' of text at
307 a time. A cell can contain one or more blocks that can be compile in
306 a time. A cell can contain one or more blocks that can be compile in
308 'single' mode by Python. In this mode, each new input new input
307 'single' mode by Python. In this mode, each new input new input
309 completely replaces all prior inputs. Cell mode is thus equivalent
308 completely replaces all prior inputs. Cell mode is thus equivalent
310 to prepending a full reset() to every push() call.
309 to prepending a full reset() to every push() call.
311 """
310 """
312 self._buffer = []
311 self._buffer = []
313 self._compile = codeop.CommandCompiler()
312 self._compile = codeop.CommandCompiler()
314 self.encoding = get_input_encoding()
313 self.encoding = get_input_encoding()
315 self.input_mode = InputSplitter.input_mode if input_mode is None \
314 self.input_mode = InputSplitter.input_mode if input_mode is None \
316 else input_mode
315 else input_mode
317
316
318 def reset(self):
317 def reset(self):
319 """Reset the input buffer and associated state."""
318 """Reset the input buffer and associated state."""
320 self.indent_spaces = 0
319 self.indent_spaces = 0
321 self._buffer[:] = []
320 self._buffer[:] = []
322 self.source = ''
321 self.source = ''
323 self.code = None
322 self.code = None
324 self._is_complete = False
323 self._is_complete = False
325 self._full_dedent = False
324 self._full_dedent = False
326
325
327 def source_reset(self):
326 def source_reset(self):
328 """Return the input source and perform a full reset.
327 """Return the input source and perform a full reset.
329 """
328 """
330 out = self.source
329 out = self.source
331 self.reset()
330 self.reset()
332 return out
331 return out
333
332
334 def push(self, lines):
333 def push(self, lines):
335 """Push one or more lines of input.
334 """Push one or more lines of input.
336
335
337 This stores the given lines and returns a status code indicating
336 This stores the given lines and returns a status code indicating
338 whether the code forms a complete Python block or not.
337 whether the code forms a complete Python block or not.
339
338
340 Any exceptions generated in compilation are swallowed, but if an
339 Any exceptions generated in compilation are swallowed, but if an
341 exception was produced, the method returns True.
340 exception was produced, the method returns True.
342
341
343 Parameters
342 Parameters
344 ----------
343 ----------
345 lines : string
344 lines : string
346 One or more lines of Python input.
345 One or more lines of Python input.
347
346
348 Returns
347 Returns
349 -------
348 -------
350 is_complete : boolean
349 is_complete : boolean
351 True if the current input source (the result of the current input
350 True if the current input source (the result of the current input
352 plus prior inputs) forms a complete Python execution block. Note that
351 plus prior inputs) forms a complete Python execution block. Note that
353 this value is also stored as a private attribute (_is_complete), so it
352 this value is also stored as a private attribute (_is_complete), so it
354 can be queried at any time.
353 can be queried at any time.
355 """
354 """
356 if self.input_mode == 'cell':
355 if self.input_mode == 'cell':
357 self.reset()
356 self.reset()
358
357
359 self._store(lines)
358 self._store(lines)
360 source = self.source
359 source = self.source
361
360
362 # Before calling _compile(), reset the code object to None so that if an
361 # Before calling _compile(), reset the code object to None so that if an
363 # exception is raised in compilation, we don't mislead by having
362 # exception is raised in compilation, we don't mislead by having
364 # inconsistent code/source attributes.
363 # inconsistent code/source attributes.
365 self.code, self._is_complete = None, None
364 self.code, self._is_complete = None, None
366
365
367 # Honor termination lines properly
366 # Honor termination lines properly
368 if source.rstrip().endswith('\\'):
367 if source.rstrip().endswith('\\'):
369 return False
368 return False
370
369
371 self._update_indent(lines)
370 self._update_indent(lines)
372 try:
371 try:
373 self.code = self._compile(source, symbol="exec")
372 self.code = self._compile(source, symbol="exec")
374 # Invalid syntax can produce any of a number of different errors from
373 # Invalid syntax can produce any of a number of different errors from
375 # inside the compiler, so we have to catch them all. Syntax errors
374 # inside the compiler, so we have to catch them all. Syntax errors
376 # immediately produce a 'ready' block, so the invalid Python can be
375 # immediately produce a 'ready' block, so the invalid Python can be
377 # sent to the kernel for evaluation with possible ipython
376 # sent to the kernel for evaluation with possible ipython
378 # special-syntax conversion.
377 # special-syntax conversion.
379 except (SyntaxError, OverflowError, ValueError, TypeError,
378 except (SyntaxError, OverflowError, ValueError, TypeError,
380 MemoryError):
379 MemoryError):
381 self._is_complete = True
380 self._is_complete = True
382 else:
381 else:
383 # Compilation didn't produce any exceptions (though it may not have
382 # Compilation didn't produce any exceptions (though it may not have
384 # given a complete code object)
383 # given a complete code object)
385 self._is_complete = self.code is not None
384 self._is_complete = self.code is not None
386
385
387 return self._is_complete
386 return self._is_complete
388
387
389 def push_accepts_more(self):
388 def push_accepts_more(self):
390 """Return whether a block of interactive input can accept more input.
389 """Return whether a block of interactive input can accept more input.
391
390
392 This method is meant to be used by line-oriented frontends, who need to
391 This method is meant to be used by line-oriented frontends, who need to
393 guess whether a block is complete or not based solely on prior and
392 guess whether a block is complete or not based solely on prior and
394 current input lines. The InputSplitter considers it has a complete
393 current input lines. The InputSplitter considers it has a complete
395 interactive block and will not accept more input only when either a
394 interactive block and will not accept more input only when either a
396 SyntaxError is raised, or *all* of the following are true:
395 SyntaxError is raised, or *all* of the following are true:
397
396
398 1. The input compiles to a complete statement.
397 1. The input compiles to a complete statement.
399
398
400 2. The indentation level is flush-left (because if we are indented,
399 2. The indentation level is flush-left (because if we are indented,
401 like inside a function definition or for loop, we need to keep
400 like inside a function definition or for loop, we need to keep
402 reading new input).
401 reading new input).
403
402
404 3. There is one extra line consisting only of whitespace.
403 3. There is one extra line consisting only of whitespace.
405
404
406 Because of condition #3, this method should be used only by
405 Because of condition #3, this method should be used only by
407 *line-oriented* frontends, since it means that intermediate blank lines
406 *line-oriented* frontends, since it means that intermediate blank lines
408 are not allowed in function definitions (or any other indented block).
407 are not allowed in function definitions (or any other indented block).
409
408
410 If the current input produces a syntax error, this method immediately
409 If the current input produces a syntax error, this method immediately
411 returns False but does *not* raise the syntax error exception, as
410 returns False but does *not* raise the syntax error exception, as
412 typically clients will want to send invalid syntax to an execution
411 typically clients will want to send invalid syntax to an execution
413 backend which might convert the invalid syntax into valid Python via
412 backend which might convert the invalid syntax into valid Python via
414 one of the dynamic IPython mechanisms.
413 one of the dynamic IPython mechanisms.
415 """
414 """
416
415
417 # With incomplete input, unconditionally accept more
416 # With incomplete input, unconditionally accept more
418 if not self._is_complete:
417 if not self._is_complete:
419 return True
418 return True
420
419
421 # If we already have complete input and we're flush left, the answer
420 # If we already have complete input and we're flush left, the answer
422 # depends. In line mode, if there hasn't been any indentation,
421 # depends. In line mode, if there hasn't been any indentation,
423 # that's it. If we've come back from some indentation, we need
422 # that's it. If we've come back from some indentation, we need
424 # the blank final line to finish.
423 # the blank final line to finish.
425 # In cell mode, we need to check how many blocks the input so far
424 # In cell mode, we need to check how many blocks the input so far
426 # compiles into, because if there's already more than one full
425 # compiles into, because if there's already more than one full
427 # independent block of input, then the client has entered full
426 # independent block of input, then the client has entered full
428 # 'cell' mode and is feeding lines that each is complete. In this
427 # 'cell' mode and is feeding lines that each is complete. In this
429 # case we should then keep accepting. The Qt terminal-like console
428 # case we should then keep accepting. The Qt terminal-like console
430 # does precisely this, to provide the convenience of terminal-like
429 # does precisely this, to provide the convenience of terminal-like
431 # input of single expressions, but allowing the user (with a
430 # input of single expressions, but allowing the user (with a
432 # separate keystroke) to switch to 'cell' mode and type multiple
431 # separate keystroke) to switch to 'cell' mode and type multiple
433 # expressions in one shot.
432 # expressions in one shot.
434 if self.indent_spaces==0:
433 if self.indent_spaces==0:
435 if self.input_mode=='line':
434 if self.input_mode=='line':
436 if not self._full_dedent:
435 if not self._full_dedent:
437 return False
436 return False
438 else:
437 else:
439 try:
438 try:
440 code_ast = ast.parse(u''.join(self._buffer))
439 code_ast = ast.parse(u''.join(self._buffer))
441 except Exception:
440 except Exception:
442 return False
441 return False
443 else:
442 else:
444 if len(code_ast.body) == 1:
443 if len(code_ast.body) == 1:
445 return False
444 return False
446
445
447 # When input is complete, then termination is marked by an extra blank
446 # When input is complete, then termination is marked by an extra blank
448 # line at the end.
447 # line at the end.
449 last_line = self.source.splitlines()[-1]
448 last_line = self.source.splitlines()[-1]
450 return bool(last_line and not last_line.isspace())
449 return bool(last_line and not last_line.isspace())
451
450
452 #------------------------------------------------------------------------
451 #------------------------------------------------------------------------
453 # Private interface
452 # Private interface
454 #------------------------------------------------------------------------
453 #------------------------------------------------------------------------
455
454
456 def _find_indent(self, line):
455 def _find_indent(self, line):
457 """Compute the new indentation level for a single line.
456 """Compute the new indentation level for a single line.
458
457
459 Parameters
458 Parameters
460 ----------
459 ----------
461 line : str
460 line : str
462 A single new line of non-whitespace, non-comment Python input.
461 A single new line of non-whitespace, non-comment Python input.
463
462
464 Returns
463 Returns
465 -------
464 -------
466 indent_spaces : int
465 indent_spaces : int
467 New value for the indent level (it may be equal to self.indent_spaces
466 New value for the indent level (it may be equal to self.indent_spaces
468 if indentation doesn't change.
467 if indentation doesn't change.
469
468
470 full_dedent : boolean
469 full_dedent : boolean
471 Whether the new line causes a full flush-left dedent.
470 Whether the new line causes a full flush-left dedent.
472 """
471 """
473 indent_spaces = self.indent_spaces
472 indent_spaces = self.indent_spaces
474 full_dedent = self._full_dedent
473 full_dedent = self._full_dedent
475
474
476 inisp = num_ini_spaces(line)
475 inisp = num_ini_spaces(line)
477 if inisp < indent_spaces:
476 if inisp < indent_spaces:
478 indent_spaces = inisp
477 indent_spaces = inisp
479 if indent_spaces <= 0:
478 if indent_spaces <= 0:
480 #print 'Full dedent in text',self.source # dbg
479 #print 'Full dedent in text',self.source # dbg
481 full_dedent = True
480 full_dedent = True
482
481
483 if line.rstrip()[-1] == ':':
482 if line.rstrip()[-1] == ':':
484 indent_spaces += 4
483 indent_spaces += 4
485 elif dedent_re.match(line):
484 elif dedent_re.match(line):
486 indent_spaces -= 4
485 indent_spaces -= 4
487 if indent_spaces <= 0:
486 if indent_spaces <= 0:
488 full_dedent = True
487 full_dedent = True
489
488
490 # Safety
489 # Safety
491 if indent_spaces < 0:
490 if indent_spaces < 0:
492 indent_spaces = 0
491 indent_spaces = 0
493 #print 'safety' # dbg
492 #print 'safety' # dbg
494
493
495 return indent_spaces, full_dedent
494 return indent_spaces, full_dedent
496
495
497 def _update_indent(self, lines):
496 def _update_indent(self, lines):
498 for line in remove_comments(lines).splitlines():
497 for line in remove_comments(lines).splitlines():
499 if line and not line.isspace():
498 if line and not line.isspace():
500 self.indent_spaces, self._full_dedent = self._find_indent(line)
499 self.indent_spaces, self._full_dedent = self._find_indent(line)
501
500
502 def _store(self, lines, buffer=None, store='source'):
501 def _store(self, lines, buffer=None, store='source'):
503 """Store one or more lines of input.
502 """Store one or more lines of input.
504
503
505 If input lines are not newline-terminated, a newline is automatically
504 If input lines are not newline-terminated, a newline is automatically
506 appended."""
505 appended."""
507
506
508 if buffer is None:
507 if buffer is None:
509 buffer = self._buffer
508 buffer = self._buffer
510
509
511 if lines.endswith('\n'):
510 if lines.endswith('\n'):
512 buffer.append(lines)
511 buffer.append(lines)
513 else:
512 else:
514 buffer.append(lines+'\n')
513 buffer.append(lines+'\n')
515 setattr(self, store, self._set_source(buffer))
514 setattr(self, store, self._set_source(buffer))
516
515
517 def _set_source(self, buffer):
516 def _set_source(self, buffer):
518 return u''.join(buffer)
517 return u''.join(buffer)
519
518
520
519
521 #-----------------------------------------------------------------------------
520 #-----------------------------------------------------------------------------
522 # Functions and classes for IPython-specific syntactic support
521 # Functions and classes for IPython-specific syntactic support
523 #-----------------------------------------------------------------------------
522 #-----------------------------------------------------------------------------
524
523
525 # The escaped translators ALL receive a line where their own escape has been
524 # The escaped translators ALL receive a line where their own escape has been
526 # stripped. Only '?' is valid at the end of the line, all others can only be
525 # stripped. Only '?' is valid at the end of the line, all others can only be
527 # placed at the start.
526 # placed at the start.
528
527
529 # Transformations of the special syntaxes that don't rely on an explicit escape
528 # Transformations of the special syntaxes that don't rely on an explicit escape
530 # character but instead on patterns on the input line
529 # character but instead on patterns on the input line
531
530
532 # The core transformations are implemented as standalone functions that can be
531 # The core transformations are implemented as standalone functions that can be
533 # tested and validated in isolation. Each of these uses a regexp, we
532 # tested and validated in isolation. Each of these uses a regexp, we
534 # pre-compile these and keep them close to each function definition for clarity
533 # pre-compile these and keep them close to each function definition for clarity
535
534
536 _assign_system_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
535 _assign_system_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
537 r'\s*=\s*!\s*(?P<cmd>.*)')
536 r'\s*=\s*!\s*(?P<cmd>.*)')
538
537
539 def transform_assign_system(line):
538 def transform_assign_system(line):
540 """Handle the `files = !ls` syntax."""
539 """Handle the `files = !ls` syntax."""
541 m = _assign_system_re.match(line)
540 m = _assign_system_re.match(line)
542 if m is not None:
541 if m is not None:
543 cmd = m.group('cmd')
542 cmd = m.group('cmd')
544 lhs = m.group('lhs')
543 lhs = m.group('lhs')
545 new_line = '%s = get_ipython().getoutput(%r)' % (lhs, cmd)
544 new_line = '%s = get_ipython().getoutput(%r)' % (lhs, cmd)
546 return new_line
545 return new_line
547 return line
546 return line
548
547
549
548
550 _assign_magic_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
549 _assign_magic_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
551 r'\s*=\s*%\s*(?P<cmd>.*)')
550 r'\s*=\s*%\s*(?P<cmd>.*)')
552
551
553 def transform_assign_magic(line):
552 def transform_assign_magic(line):
554 """Handle the `a = %who` syntax."""
553 """Handle the `a = %who` syntax."""
555 m = _assign_magic_re.match(line)
554 m = _assign_magic_re.match(line)
556 if m is not None:
555 if m is not None:
557 cmd = m.group('cmd')
556 cmd = m.group('cmd')
558 lhs = m.group('lhs')
557 lhs = m.group('lhs')
559 new_line = '%s = get_ipython().magic(%r)' % (lhs, cmd)
558 new_line = '%s = get_ipython().magic(%r)' % (lhs, cmd)
560 return new_line
559 return new_line
561 return line
560 return line
562
561
563
562
564 _classic_prompt_re = re.compile(r'^([ \t]*>>> |^[ \t]*\.\.\. )')
563 _classic_prompt_re = re.compile(r'^([ \t]*>>> |^[ \t]*\.\.\. )')
565
564
566 def transform_classic_prompt(line):
565 def transform_classic_prompt(line):
567 """Handle inputs that start with '>>> ' syntax."""
566 """Handle inputs that start with '>>> ' syntax."""
568
567
569 if not line or line.isspace():
568 if not line or line.isspace():
570 return line
569 return line
571 m = _classic_prompt_re.match(line)
570 m = _classic_prompt_re.match(line)
572 if m:
571 if m:
573 return line[len(m.group(0)):]
572 return line[len(m.group(0)):]
574 else:
573 else:
575 return line
574 return line
576
575
577
576
578 _ipy_prompt_re = re.compile(r'^([ \t]*In \[\d+\]: |^[ \t]*\ \ \ \.\.\.+: )')
577 _ipy_prompt_re = re.compile(r'^([ \t]*In \[\d+\]: |^[ \t]*\ \ \ \.\.\.+: )')
579
578
580 def transform_ipy_prompt(line):
579 def transform_ipy_prompt(line):
581 """Handle inputs that start classic IPython prompt syntax."""
580 """Handle inputs that start classic IPython prompt syntax."""
582
581
583 if not line or line.isspace():
582 if not line or line.isspace():
584 return line
583 return line
585 #print 'LINE: %r' % line # dbg
584 #print 'LINE: %r' % line # dbg
586 m = _ipy_prompt_re.match(line)
585 m = _ipy_prompt_re.match(line)
587 if m:
586 if m:
588 #print 'MATCH! %r -> %r' % (line, line[len(m.group(0)):]) # dbg
587 #print 'MATCH! %r -> %r' % (line, line[len(m.group(0)):]) # dbg
589 return line[len(m.group(0)):]
588 return line[len(m.group(0)):]
590 else:
589 else:
591 return line
590 return line
592
591
593
592
594 def _make_help_call(target, esc, lspace, next_input=None):
593 def _make_help_call(target, esc, lspace, next_input=None):
595 """Prepares a pinfo(2)/psearch call from a target name and the escape
594 """Prepares a pinfo(2)/psearch call from a target name and the escape
596 (i.e. ? or ??)"""
595 (i.e. ? or ??)"""
597 method = 'pinfo2' if esc == '??' \
596 method = 'pinfo2' if esc == '??' \
598 else 'psearch' if '*' in target \
597 else 'psearch' if '*' in target \
599 else 'pinfo'
598 else 'pinfo'
600 arg = " ".join([method, target])
599 arg = " ".join([method, target])
601
602 if next_input is None:
600 if next_input is None:
603 return '%sget_ipython().magic(%r)' % (lspace, arg)
601 return '%sget_ipython().magic(%r)' % (lspace, arg)
604 else:
602 else:
605 return '%sget_ipython().set_next_input(%r);get_ipython().magic(%r)' % \
603 return '%sget_ipython().set_next_input(%r);get_ipython().magic(%r)' % \
606 (lspace, next_input, arg)
604 (lspace, next_input, arg)
607
605
608
606
609 _initial_space_re = re.compile(r'\s*')
607 _initial_space_re = re.compile(r'\s*')
610
608
611 _help_end_re = re.compile(r"""(%?
609 _help_end_re = re.compile(r"""(%{0,2}
612 [a-zA-Z_*][\w*]* # Variable name
610 [a-zA-Z_*][\w*]* # Variable name
613 (\.[a-zA-Z_*][\w*]*)* # .etc.etc
611 (\.[a-zA-Z_*][\w*]*)* # .etc.etc
614 )
612 )
615 (\?\??)$ # ? or ??""",
613 (\?\??)$ # ? or ??""",
616 re.VERBOSE)
614 re.VERBOSE)
617
615
618
616
619 def transform_help_end(line):
617 def transform_help_end(line):
620 """Translate lines with ?/?? at the end"""
618 """Translate lines with ?/?? at the end"""
621 m = _help_end_re.search(line)
619 m = _help_end_re.search(line)
622 if m is None or has_comment(line):
620 if m is None or has_comment(line):
623 return line
621 return line
624 target = m.group(1)
622 target = m.group(1)
625 esc = m.group(3)
623 esc = m.group(3)
626 lspace = _initial_space_re.match(line).group(0)
624 lspace = _initial_space_re.match(line).group(0)
627
625
628 # If we're mid-command, put it back on the next prompt for the user.
626 # If we're mid-command, put it back on the next prompt for the user.
629 next_input = line.rstrip('?') if line.strip() != m.group(0) else None
627 next_input = line.rstrip('?') if line.strip() != m.group(0) else None
630
628
631 return _make_help_call(target, esc, lspace, next_input)
629 return _make_help_call(target, esc, lspace, next_input)
632
630
633
631
634 class EscapedTransformer(object):
632 class EscapedTransformer(object):
635 """Class to transform lines that are explicitly escaped out."""
633 """Class to transform lines that are explicitly escaped out."""
636
634
637 def __init__(self):
635 def __init__(self):
638 tr = { ESC_SHELL : self._tr_system,
636 tr = { ESC_SHELL : self._tr_system,
639 ESC_SH_CAP : self._tr_system2,
637 ESC_SH_CAP : self._tr_system2,
640 ESC_HELP : self._tr_help,
638 ESC_HELP : self._tr_help,
641 ESC_HELP2 : self._tr_help,
639 ESC_HELP2 : self._tr_help,
642 ESC_MAGIC : self._tr_magic,
640 ESC_MAGIC : self._tr_magic,
643 ESC_QUOTE : self._tr_quote,
641 ESC_QUOTE : self._tr_quote,
644 ESC_QUOTE2 : self._tr_quote2,
642 ESC_QUOTE2 : self._tr_quote2,
645 ESC_PAREN : self._tr_paren }
643 ESC_PAREN : self._tr_paren }
646 self.tr = tr
644 self.tr = tr
647
645
648 # Support for syntax transformations that use explicit escapes typed by the
646 # Support for syntax transformations that use explicit escapes typed by the
649 # user at the beginning of a line
647 # user at the beginning of a line
650 @staticmethod
648 @staticmethod
651 def _tr_system(line_info):
649 def _tr_system(line_info):
652 "Translate lines escaped with: !"
650 "Translate lines escaped with: !"
653 cmd = line_info.line.lstrip().lstrip(ESC_SHELL)
651 cmd = line_info.line.lstrip().lstrip(ESC_SHELL)
654 return '%sget_ipython().system(%r)' % (line_info.pre, cmd)
652 return '%sget_ipython().system(%r)' % (line_info.pre, cmd)
655
653
656 @staticmethod
654 @staticmethod
657 def _tr_system2(line_info):
655 def _tr_system2(line_info):
658 "Translate lines escaped with: !!"
656 "Translate lines escaped with: !!"
659 cmd = line_info.line.lstrip()[2:]
657 cmd = line_info.line.lstrip()[2:]
660 return '%sget_ipython().getoutput(%r)' % (line_info.pre, cmd)
658 return '%sget_ipython().getoutput(%r)' % (line_info.pre, cmd)
661
659
662 @staticmethod
660 @staticmethod
663 def _tr_help(line_info):
661 def _tr_help(line_info):
664 "Translate lines escaped with: ?/??"
662 "Translate lines escaped with: ?/??"
665 # A naked help line should just fire the intro help screen
663 # A naked help line should just fire the intro help screen
666 if not line_info.line[1:]:
664 if not line_info.line[1:]:
667 return 'get_ipython().show_usage()'
665 return 'get_ipython().show_usage()'
668
666
669 return _make_help_call(line_info.ifun, line_info.esc, line_info.pre)
667 return _make_help_call(line_info.ifun, line_info.esc, line_info.pre)
670
668
671 @staticmethod
669 @staticmethod
672 def _tr_magic(line_info):
670 def _tr_magic(line_info):
673 "Translate lines escaped with: %"
671 "Translate lines escaped with: %"
674 tpl = '%sget_ipython().magic(%r)'
672 tpl = '%sget_ipython().magic(%r)'
675 cmd = ' '.join([line_info.ifun, line_info.the_rest]).strip()
673 cmd = ' '.join([line_info.ifun, line_info.the_rest]).strip()
676 return tpl % (line_info.pre, cmd)
674 return tpl % (line_info.pre, cmd)
677
675
678 @staticmethod
676 @staticmethod
679 def _tr_quote(line_info):
677 def _tr_quote(line_info):
680 "Translate lines escaped with: ,"
678 "Translate lines escaped with: ,"
681 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
679 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
682 '", "'.join(line_info.the_rest.split()) )
680 '", "'.join(line_info.the_rest.split()) )
683
681
684 @staticmethod
682 @staticmethod
685 def _tr_quote2(line_info):
683 def _tr_quote2(line_info):
686 "Translate lines escaped with: ;"
684 "Translate lines escaped with: ;"
687 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
685 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
688 line_info.the_rest)
686 line_info.the_rest)
689
687
690 @staticmethod
688 @staticmethod
691 def _tr_paren(line_info):
689 def _tr_paren(line_info):
692 "Translate lines escaped with: /"
690 "Translate lines escaped with: /"
693 return '%s%s(%s)' % (line_info.pre, line_info.ifun,
691 return '%s%s(%s)' % (line_info.pre, line_info.ifun,
694 ", ".join(line_info.the_rest.split()))
692 ", ".join(line_info.the_rest.split()))
695
693
696 def __call__(self, line):
694 def __call__(self, line):
697 """Class to transform lines that are explicitly escaped out.
695 """Class to transform lines that are explicitly escaped out.
698
696
699 This calls the above _tr_* static methods for the actual line
697 This calls the above _tr_* static methods for the actual line
700 translations."""
698 translations."""
701
699
702 # Empty lines just get returned unmodified
700 # Empty lines just get returned unmodified
703 if not line or line.isspace():
701 if not line or line.isspace():
704 return line
702 return line
705
703
706 # Get line endpoints, where the escapes can be
704 # Get line endpoints, where the escapes can be
707 line_info = LineInfo(line)
705 line_info = LineInfo(line)
708
706
709 if not line_info.esc in self.tr:
707 if not line_info.esc in self.tr:
710 # If we don't recognize the escape, don't modify the line
708 # If we don't recognize the escape, don't modify the line
711 return line
709 return line
712
710
713 return self.tr[line_info.esc](line_info)
711 return self.tr[line_info.esc](line_info)
714
712
715
713
716 # A function-looking object to be used by the rest of the code. The purpose of
714 # A function-looking object to be used by the rest of the code. The purpose of
717 # the class in this case is to organize related functionality, more than to
715 # the class in this case is to organize related functionality, more than to
718 # manage state.
716 # manage state.
719 transform_escaped = EscapedTransformer()
717 transform_escaped = EscapedTransformer()
720
718
721
719
722 class IPythonInputSplitter(InputSplitter):
720 class IPythonInputSplitter(InputSplitter):
723 """An input splitter that recognizes all of IPython's special syntax."""
721 """An input splitter that recognizes all of IPython's special syntax."""
724
722
725 # String with raw, untransformed input.
723 # String with raw, untransformed input.
726 source_raw = ''
724 source_raw = ''
727
725
728 # Flag to track when we're in the middle of processing a cell magic, since
726 # Flag to track when we're in the middle of processing a cell magic, since
729 # the logic has to change. In that case, we apply no transformations at
727 # the logic has to change. In that case, we apply no transformations at
730 # all.
728 # all.
731 processing_cell_magic = False
729 processing_cell_magic = False
732
730
733 # Storage for all blocks of input that make up a cell magic
731 # Storage for all blocks of input that make up a cell magic
734 cell_magic_parts = []
732 cell_magic_parts = []
735
733
736 # Private attributes
734 # Private attributes
737
735
738 # List with lines of raw input accumulated so far.
736 # List with lines of raw input accumulated so far.
739 _buffer_raw = None
737 _buffer_raw = None
740
738
741 def __init__(self, input_mode=None):
739 def __init__(self, input_mode=None):
742 super(IPythonInputSplitter, self).__init__(input_mode)
740 super(IPythonInputSplitter, self).__init__(input_mode)
743 self._buffer_raw = []
741 self._buffer_raw = []
744 self._validate = True
742 self._validate = True
745
743
746 def reset(self):
744 def reset(self):
747 """Reset the input buffer and associated state."""
745 """Reset the input buffer and associated state."""
748 super(IPythonInputSplitter, self).reset()
746 super(IPythonInputSplitter, self).reset()
749 self._buffer_raw[:] = []
747 self._buffer_raw[:] = []
750 self.source_raw = ''
748 self.source_raw = ''
751 self.cell_magic_parts = []
749 self.cell_magic_parts = []
752 self.processing_cell_magic = False
750 self.processing_cell_magic = False
753
751
754 def source_raw_reset(self):
752 def source_raw_reset(self):
755 """Return input and raw source and perform a full reset.
753 """Return input and raw source and perform a full reset.
756 """
754 """
757 out = self.source
755 out = self.source
758 out_r = self.source_raw
756 out_r = self.source_raw
759 self.reset()
757 self.reset()
760 return out, out_r
758 return out, out_r
761
759
762 def push_accepts_more(self):
760 def push_accepts_more(self):
763 if self.processing_cell_magic:
761 if self.processing_cell_magic:
764 return not self._is_complete
762 return not self._is_complete
765 else:
763 else:
766 return super(IPythonInputSplitter, self).push_accepts_more()
764 return super(IPythonInputSplitter, self).push_accepts_more()
767
765
768 def _handle_cell_magic(self, lines):
766 def _handle_cell_magic(self, lines):
769 """Process lines when they start with %%, which marks cell magics.
767 """Process lines when they start with %%, which marks cell magics.
770 """
768 """
771 self.processing_cell_magic = True
769 self.processing_cell_magic = True
772 first, _, body = lines.partition('\n')
770 first, _, body = lines.partition('\n')
773 magic_name, _, line = first.partition(' ')
771 magic_name, _, line = first.partition(' ')
774 magic_name = magic_name.lstrip(ESC_MAGIC)
772 magic_name = magic_name.lstrip(ESC_MAGIC)
775 # We store the body of the cell and create a call to a method that
773 # We store the body of the cell and create a call to a method that
776 # will use this stored value. This is ugly, but it's a first cut to
774 # will use this stored value. This is ugly, but it's a first cut to
777 # get it all working, as right now changing the return API of our
775 # get it all working, as right now changing the return API of our
778 # methods would require major refactoring.
776 # methods would require major refactoring.
779 self.cell_magic_parts = [body]
777 self.cell_magic_parts = [body]
780 tpl = 'get_ipython()._cell_magic(%r, %r)'
778 tpl = 'get_ipython()._cell_magic(%r, %r)'
781 tlines = tpl % (magic_name, line)
779 tlines = tpl % (magic_name, line)
782 self._store(tlines)
780 self._store(tlines)
783 self._store(lines, self._buffer_raw, 'source_raw')
781 self._store(lines, self._buffer_raw, 'source_raw')
784 # We can actually choose whether to allow for single blank lines here
782 # We can actually choose whether to allow for single blank lines here
785 # during input for clients that use cell mode to decide when to stop
783 # during input for clients that use cell mode to decide when to stop
786 # pushing input (currently only the Qt console).
784 # pushing input (currently only the Qt console).
787 # My first implementation did that, and then I realized it wasn't
785 # My first implementation did that, and then I realized it wasn't
788 # consistent with the terminal behavior, so I've reverted it to one
786 # consistent with the terminal behavior, so I've reverted it to one
789 # line. But I'm leaving it here so we can easily test both behaviors,
787 # line. But I'm leaving it here so we can easily test both behaviors,
790 # I kind of liked having full blank lines allowed in the cell magics...
788 # I kind of liked having full blank lines allowed in the cell magics...
791 #self._is_complete = last_two_blanks(lines)
789 #self._is_complete = last_two_blanks(lines)
792 self._is_complete = last_blank(lines)
790 self._is_complete = last_blank(lines)
793 return self._is_complete
791 return self._is_complete
794
792
795 def _line_mode_cell_append(self, lines):
793 def _line_mode_cell_append(self, lines):
796 """Append new content for a cell magic in line mode.
794 """Append new content for a cell magic in line mode.
797 """
795 """
798 # Only store the raw input. Lines beyond the first one are only only
796 # Only store the raw input. Lines beyond the first one are only only
799 # stored for history purposes; for execution the caller will grab the
797 # stored for history purposes; for execution the caller will grab the
800 # magic pieces from cell_magic_parts and will assemble the cell body
798 # magic pieces from cell_magic_parts and will assemble the cell body
801 self._store(lines, self._buffer_raw, 'source_raw')
799 self._store(lines, self._buffer_raw, 'source_raw')
802 self.cell_magic_parts.append(lines)
800 self.cell_magic_parts.append(lines)
803 # Find out if the last stored block has a whitespace line as its
801 # Find out if the last stored block has a whitespace line as its
804 # last line and also this line is whitespace, case in which we're
802 # last line and also this line is whitespace, case in which we're
805 # done (two contiguous blank lines signal termination). Note that
803 # done (two contiguous blank lines signal termination). Note that
806 # the storage logic *enforces* that every stored block is
804 # the storage logic *enforces* that every stored block is
807 # newline-terminated, so we grab everything but the last character
805 # newline-terminated, so we grab everything but the last character
808 # so we can have the body of the block alone.
806 # so we can have the body of the block alone.
809 last_block = self.cell_magic_parts[-1]
807 last_block = self.cell_magic_parts[-1]
810 self._is_complete = last_blank(last_block) and lines.isspace()
808 self._is_complete = last_blank(last_block) and lines.isspace()
811 return self._is_complete
809 return self._is_complete
812
810
813 def push(self, lines):
811 def push(self, lines):
814 """Push one or more lines of IPython input.
812 """Push one or more lines of IPython input.
815
813
816 This stores the given lines and returns a status code indicating
814 This stores the given lines and returns a status code indicating
817 whether the code forms a complete Python block or not, after processing
815 whether the code forms a complete Python block or not, after processing
818 all input lines for special IPython syntax.
816 all input lines for special IPython syntax.
819
817
820 Any exceptions generated in compilation are swallowed, but if an
818 Any exceptions generated in compilation are swallowed, but if an
821 exception was produced, the method returns True.
819 exception was produced, the method returns True.
822
820
823 Parameters
821 Parameters
824 ----------
822 ----------
825 lines : string
823 lines : string
826 One or more lines of Python input.
824 One or more lines of Python input.
827
825
828 Returns
826 Returns
829 -------
827 -------
830 is_complete : boolean
828 is_complete : boolean
831 True if the current input source (the result of the current input
829 True if the current input source (the result of the current input
832 plus prior inputs) forms a complete Python execution block. Note that
830 plus prior inputs) forms a complete Python execution block. Note that
833 this value is also stored as a private attribute (_is_complete), so it
831 this value is also stored as a private attribute (_is_complete), so it
834 can be queried at any time.
832 can be queried at any time.
835 """
833 """
836 if not lines:
834 if not lines:
837 return super(IPythonInputSplitter, self).push(lines)
835 return super(IPythonInputSplitter, self).push(lines)
838
836
839 # We must ensure all input is pure unicode
837 # We must ensure all input is pure unicode
840 lines = cast_unicode(lines, self.encoding)
838 lines = cast_unicode(lines, self.encoding)
841
839
842 # If the entire input block is a cell magic, return after handling it
840 # If the entire input block is a cell magic, return after handling it
843 # as the rest of the transformation logic should be skipped.
841 # as the rest of the transformation logic should be skipped.
844 if lines.startswith('%%'):
842 if lines.startswith('%%') and not \
843 (len(lines.splitlines()) == 1 and lines.endswith('?')):
845 return self._handle_cell_magic(lines)
844 return self._handle_cell_magic(lines)
846
845
847 # In line mode, a cell magic can arrive in separate pieces
846 # In line mode, a cell magic can arrive in separate pieces
848 if self.input_mode == 'line' and self.processing_cell_magic:
847 if self.input_mode == 'line' and self.processing_cell_magic:
849 return self._line_mode_cell_append(lines)
848 return self._line_mode_cell_append(lines)
850
849
851 # The rest of the processing is for 'normal' content, i.e. IPython
850 # The rest of the processing is for 'normal' content, i.e. IPython
852 # source that we process through our transformations pipeline.
851 # source that we process through our transformations pipeline.
853 lines_list = lines.splitlines()
852 lines_list = lines.splitlines()
854
853
855 transforms = [transform_ipy_prompt, transform_classic_prompt,
854 transforms = [transform_ipy_prompt, transform_classic_prompt,
856 transform_help_end, transform_escaped,
855 transform_help_end, transform_escaped,
857 transform_assign_system, transform_assign_magic]
856 transform_assign_system, transform_assign_magic]
858
857
859 # Transform logic
858 # Transform logic
860 #
859 #
861 # We only apply the line transformers to the input if we have either no
860 # We only apply the line transformers to the input if we have either no
862 # input yet, or complete input, or if the last line of the buffer ends
861 # input yet, or complete input, or if the last line of the buffer ends
863 # with ':' (opening an indented block). This prevents the accidental
862 # with ':' (opening an indented block). This prevents the accidental
864 # transformation of escapes inside multiline expressions like
863 # transformation of escapes inside multiline expressions like
865 # triple-quoted strings or parenthesized expressions.
864 # triple-quoted strings or parenthesized expressions.
866 #
865 #
867 # The last heuristic, while ugly, ensures that the first line of an
866 # The last heuristic, while ugly, ensures that the first line of an
868 # indented block is correctly transformed.
867 # indented block is correctly transformed.
869 #
868 #
870 # FIXME: try to find a cleaner approach for this last bit.
869 # FIXME: try to find a cleaner approach for this last bit.
871
870
872 # If we were in 'block' mode, since we're going to pump the parent
871 # If we were in 'block' mode, since we're going to pump the parent
873 # class by hand line by line, we need to temporarily switch out to
872 # class by hand line by line, we need to temporarily switch out to
874 # 'line' mode, do a single manual reset and then feed the lines one
873 # 'line' mode, do a single manual reset and then feed the lines one
875 # by one. Note that this only matters if the input has more than one
874 # by one. Note that this only matters if the input has more than one
876 # line.
875 # line.
877 changed_input_mode = False
876 changed_input_mode = False
878
877
879 if self.input_mode == 'cell':
878 if self.input_mode == 'cell':
880 self.reset()
879 self.reset()
881 changed_input_mode = True
880 changed_input_mode = True
882 saved_input_mode = 'cell'
881 saved_input_mode = 'cell'
883 self.input_mode = 'line'
882 self.input_mode = 'line'
884
883
885 # Store raw source before applying any transformations to it. Note
884 # Store raw source before applying any transformations to it. Note
886 # that this must be done *after* the reset() call that would otherwise
885 # that this must be done *after* the reset() call that would otherwise
887 # flush the buffer.
886 # flush the buffer.
888 self._store(lines, self._buffer_raw, 'source_raw')
887 self._store(lines, self._buffer_raw, 'source_raw')
889
888
890 try:
889 try:
891 push = super(IPythonInputSplitter, self).push
890 push = super(IPythonInputSplitter, self).push
892 buf = self._buffer
891 buf = self._buffer
893 for line in lines_list:
892 for line in lines_list:
894 if self._is_complete or not buf or \
893 if self._is_complete or not buf or \
895 (buf and buf[-1].rstrip().endswith((':', ','))):
894 (buf and buf[-1].rstrip().endswith((':', ','))):
896 for f in transforms:
895 for f in transforms:
897 line = f(line)
896 line = f(line)
898
897
899 out = push(line)
898 out = push(line)
900 finally:
899 finally:
901 if changed_input_mode:
900 if changed_input_mode:
902 self.input_mode = saved_input_mode
901 self.input_mode = saved_input_mode
903 return out
902 return out
@@ -1,803 +1,807 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tests for the inputsplitter module.
2 """Tests for the inputsplitter module.
3
3
4 Authors
4 Authors
5 -------
5 -------
6 * Fernando Perez
6 * Fernando Perez
7 * Robert Kern
7 * Robert Kern
8 """
8 """
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10 # Copyright (C) 2010-2011 The IPython Development Team
10 # Copyright (C) 2010-2011 The IPython Development Team
11 #
11 #
12 # Distributed under the terms of the BSD License. The full license is in
12 # Distributed under the terms of the BSD License. The full license is in
13 # the file COPYING, distributed as part of this software.
13 # the file COPYING, distributed as part of this software.
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 # Imports
17 # Imports
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # stdlib
19 # stdlib
20 import unittest
20 import unittest
21 import sys
21 import sys
22
22
23 # Third party
23 # Third party
24 import nose.tools as nt
24 import nose.tools as nt
25
25
26 # Our own
26 # Our own
27 from IPython.core import inputsplitter as isp
27 from IPython.core import inputsplitter as isp
28 from IPython.testing import tools as tt
28 from IPython.testing import tools as tt
29 from IPython.utils import py3compat
29 from IPython.utils import py3compat
30
30
31 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
32 # Semi-complete examples (also used as tests)
32 # Semi-complete examples (also used as tests)
33 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
34
34
35 # Note: at the bottom, there's a slightly more complete version of this that
35 # Note: at the bottom, there's a slightly more complete version of this that
36 # can be useful during development of code here.
36 # can be useful during development of code here.
37
37
38 def mini_interactive_loop(input_func):
38 def mini_interactive_loop(input_func):
39 """Minimal example of the logic of an interactive interpreter loop.
39 """Minimal example of the logic of an interactive interpreter loop.
40
40
41 This serves as an example, and it is used by the test system with a fake
41 This serves as an example, and it is used by the test system with a fake
42 raw_input that simulates interactive input."""
42 raw_input that simulates interactive input."""
43
43
44 from IPython.core.inputsplitter import InputSplitter
44 from IPython.core.inputsplitter import InputSplitter
45
45
46 isp = InputSplitter()
46 isp = InputSplitter()
47 # In practice, this input loop would be wrapped in an outside loop to read
47 # In practice, this input loop would be wrapped in an outside loop to read
48 # input indefinitely, until some exit/quit command was issued. Here we
48 # input indefinitely, until some exit/quit command was issued. Here we
49 # only illustrate the basic inner loop.
49 # only illustrate the basic inner loop.
50 while isp.push_accepts_more():
50 while isp.push_accepts_more():
51 indent = ' '*isp.indent_spaces
51 indent = ' '*isp.indent_spaces
52 prompt = '>>> ' + indent
52 prompt = '>>> ' + indent
53 line = indent + input_func(prompt)
53 line = indent + input_func(prompt)
54 isp.push(line)
54 isp.push(line)
55
55
56 # Here we just return input so we can use it in a test suite, but a real
56 # Here we just return input so we can use it in a test suite, but a real
57 # interpreter would instead send it for execution somewhere.
57 # interpreter would instead send it for execution somewhere.
58 src = isp.source_reset()
58 src = isp.source_reset()
59 #print 'Input source was:\n', src # dbg
59 #print 'Input source was:\n', src # dbg
60 return src
60 return src
61
61
62 #-----------------------------------------------------------------------------
62 #-----------------------------------------------------------------------------
63 # Test utilities, just for local use
63 # Test utilities, just for local use
64 #-----------------------------------------------------------------------------
64 #-----------------------------------------------------------------------------
65
65
66 def assemble(block):
66 def assemble(block):
67 """Assemble a block into multi-line sub-blocks."""
67 """Assemble a block into multi-line sub-blocks."""
68 return ['\n'.join(sub_block)+'\n' for sub_block in block]
68 return ['\n'.join(sub_block)+'\n' for sub_block in block]
69
69
70
70
71 def pseudo_input(lines):
71 def pseudo_input(lines):
72 """Return a function that acts like raw_input but feeds the input list."""
72 """Return a function that acts like raw_input but feeds the input list."""
73 ilines = iter(lines)
73 ilines = iter(lines)
74 def raw_in(prompt):
74 def raw_in(prompt):
75 try:
75 try:
76 return next(ilines)
76 return next(ilines)
77 except StopIteration:
77 except StopIteration:
78 return ''
78 return ''
79 return raw_in
79 return raw_in
80
80
81 #-----------------------------------------------------------------------------
81 #-----------------------------------------------------------------------------
82 # Tests
82 # Tests
83 #-----------------------------------------------------------------------------
83 #-----------------------------------------------------------------------------
84 def test_spaces():
84 def test_spaces():
85 tests = [('', 0),
85 tests = [('', 0),
86 (' ', 1),
86 (' ', 1),
87 ('\n', 0),
87 ('\n', 0),
88 (' \n', 1),
88 (' \n', 1),
89 ('x', 0),
89 ('x', 0),
90 (' x', 1),
90 (' x', 1),
91 (' x',2),
91 (' x',2),
92 (' x',4),
92 (' x',4),
93 # Note: tabs are counted as a single whitespace!
93 # Note: tabs are counted as a single whitespace!
94 ('\tx', 1),
94 ('\tx', 1),
95 ('\t x', 2),
95 ('\t x', 2),
96 ]
96 ]
97 tt.check_pairs(isp.num_ini_spaces, tests)
97 tt.check_pairs(isp.num_ini_spaces, tests)
98
98
99
99
100 def test_remove_comments():
100 def test_remove_comments():
101 tests = [('text', 'text'),
101 tests = [('text', 'text'),
102 ('text # comment', 'text '),
102 ('text # comment', 'text '),
103 ('text # comment\n', 'text \n'),
103 ('text # comment\n', 'text \n'),
104 ('text # comment \n', 'text \n'),
104 ('text # comment \n', 'text \n'),
105 ('line # c \nline\n','line \nline\n'),
105 ('line # c \nline\n','line \nline\n'),
106 ('line # c \nline#c2 \nline\nline #c\n\n',
106 ('line # c \nline#c2 \nline\nline #c\n\n',
107 'line \nline\nline\nline \n\n'),
107 'line \nline\nline\nline \n\n'),
108 ]
108 ]
109 tt.check_pairs(isp.remove_comments, tests)
109 tt.check_pairs(isp.remove_comments, tests)
110
110
111 def test_has_comment():
111 def test_has_comment():
112 tests = [('text', False),
112 tests = [('text', False),
113 ('text #comment', True),
113 ('text #comment', True),
114 ('text #comment\n', True),
114 ('text #comment\n', True),
115 ('#comment', True),
115 ('#comment', True),
116 ('#comment\n', True),
116 ('#comment\n', True),
117 ('a = "#string"', False),
117 ('a = "#string"', False),
118 ('a = "#string" # comment', True),
118 ('a = "#string" # comment', True),
119 ('a #comment not "string"', True),
119 ('a #comment not "string"', True),
120 ]
120 ]
121 tt.check_pairs(isp.has_comment, tests)
121 tt.check_pairs(isp.has_comment, tests)
122
122
123
123
124 def test_get_input_encoding():
124 def test_get_input_encoding():
125 encoding = isp.get_input_encoding()
125 encoding = isp.get_input_encoding()
126 nt.assert_true(isinstance(encoding, basestring))
126 nt.assert_true(isinstance(encoding, basestring))
127 # simple-minded check that at least encoding a simple string works with the
127 # simple-minded check that at least encoding a simple string works with the
128 # encoding we got.
128 # encoding we got.
129 nt.assert_equal(u'test'.encode(encoding), b'test')
129 nt.assert_equal(u'test'.encode(encoding), b'test')
130
130
131
131
132 class NoInputEncodingTestCase(unittest.TestCase):
132 class NoInputEncodingTestCase(unittest.TestCase):
133 def setUp(self):
133 def setUp(self):
134 self.old_stdin = sys.stdin
134 self.old_stdin = sys.stdin
135 class X: pass
135 class X: pass
136 fake_stdin = X()
136 fake_stdin = X()
137 sys.stdin = fake_stdin
137 sys.stdin = fake_stdin
138
138
139 def test(self):
139 def test(self):
140 # Verify that if sys.stdin has no 'encoding' attribute we do the right
140 # Verify that if sys.stdin has no 'encoding' attribute we do the right
141 # thing
141 # thing
142 enc = isp.get_input_encoding()
142 enc = isp.get_input_encoding()
143 self.assertEqual(enc, 'ascii')
143 self.assertEqual(enc, 'ascii')
144
144
145 def tearDown(self):
145 def tearDown(self):
146 sys.stdin = self.old_stdin
146 sys.stdin = self.old_stdin
147
147
148
148
149 class InputSplitterTestCase(unittest.TestCase):
149 class InputSplitterTestCase(unittest.TestCase):
150 def setUp(self):
150 def setUp(self):
151 self.isp = isp.InputSplitter()
151 self.isp = isp.InputSplitter()
152
152
153 def test_reset(self):
153 def test_reset(self):
154 isp = self.isp
154 isp = self.isp
155 isp.push('x=1')
155 isp.push('x=1')
156 isp.reset()
156 isp.reset()
157 self.assertEqual(isp._buffer, [])
157 self.assertEqual(isp._buffer, [])
158 self.assertEqual(isp.indent_spaces, 0)
158 self.assertEqual(isp.indent_spaces, 0)
159 self.assertEqual(isp.source, '')
159 self.assertEqual(isp.source, '')
160 self.assertEqual(isp.code, None)
160 self.assertEqual(isp.code, None)
161 self.assertEqual(isp._is_complete, False)
161 self.assertEqual(isp._is_complete, False)
162
162
163 def test_source(self):
163 def test_source(self):
164 self.isp._store('1')
164 self.isp._store('1')
165 self.isp._store('2')
165 self.isp._store('2')
166 self.assertEqual(self.isp.source, '1\n2\n')
166 self.assertEqual(self.isp.source, '1\n2\n')
167 self.assertTrue(len(self.isp._buffer)>0)
167 self.assertTrue(len(self.isp._buffer)>0)
168 self.assertEqual(self.isp.source_reset(), '1\n2\n')
168 self.assertEqual(self.isp.source_reset(), '1\n2\n')
169 self.assertEqual(self.isp._buffer, [])
169 self.assertEqual(self.isp._buffer, [])
170 self.assertEqual(self.isp.source, '')
170 self.assertEqual(self.isp.source, '')
171
171
172 def test_indent(self):
172 def test_indent(self):
173 isp = self.isp # shorthand
173 isp = self.isp # shorthand
174 isp.push('x=1')
174 isp.push('x=1')
175 self.assertEqual(isp.indent_spaces, 0)
175 self.assertEqual(isp.indent_spaces, 0)
176 isp.push('if 1:\n x=1')
176 isp.push('if 1:\n x=1')
177 self.assertEqual(isp.indent_spaces, 4)
177 self.assertEqual(isp.indent_spaces, 4)
178 isp.push('y=2\n')
178 isp.push('y=2\n')
179 self.assertEqual(isp.indent_spaces, 0)
179 self.assertEqual(isp.indent_spaces, 0)
180
180
181 def test_indent2(self):
181 def test_indent2(self):
182 # In cell mode, inputs must be fed in whole blocks, so skip this test
182 # In cell mode, inputs must be fed in whole blocks, so skip this test
183 if self.isp.input_mode == 'cell': return
183 if self.isp.input_mode == 'cell': return
184
184
185 isp = self.isp
185 isp = self.isp
186 isp.push('if 1:')
186 isp.push('if 1:')
187 self.assertEqual(isp.indent_spaces, 4)
187 self.assertEqual(isp.indent_spaces, 4)
188 isp.push(' x=1')
188 isp.push(' x=1')
189 self.assertEqual(isp.indent_spaces, 4)
189 self.assertEqual(isp.indent_spaces, 4)
190 # Blank lines shouldn't change the indent level
190 # Blank lines shouldn't change the indent level
191 isp.push(' '*2)
191 isp.push(' '*2)
192 self.assertEqual(isp.indent_spaces, 4)
192 self.assertEqual(isp.indent_spaces, 4)
193
193
194 def test_indent3(self):
194 def test_indent3(self):
195 # In cell mode, inputs must be fed in whole blocks, so skip this test
195 # In cell mode, inputs must be fed in whole blocks, so skip this test
196 if self.isp.input_mode == 'cell': return
196 if self.isp.input_mode == 'cell': return
197
197
198 isp = self.isp
198 isp = self.isp
199 # When a multiline statement contains parens or multiline strings, we
199 # When a multiline statement contains parens or multiline strings, we
200 # shouldn't get confused.
200 # shouldn't get confused.
201 isp.push("if 1:")
201 isp.push("if 1:")
202 isp.push(" x = (1+\n 2)")
202 isp.push(" x = (1+\n 2)")
203 self.assertEqual(isp.indent_spaces, 4)
203 self.assertEqual(isp.indent_spaces, 4)
204
204
205 def test_indent4(self):
205 def test_indent4(self):
206 # In cell mode, inputs must be fed in whole blocks, so skip this test
206 # In cell mode, inputs must be fed in whole blocks, so skip this test
207 if self.isp.input_mode == 'cell': return
207 if self.isp.input_mode == 'cell': return
208
208
209 isp = self.isp
209 isp = self.isp
210 # whitespace after ':' should not screw up indent level
210 # whitespace after ':' should not screw up indent level
211 isp.push('if 1: \n x=1')
211 isp.push('if 1: \n x=1')
212 self.assertEqual(isp.indent_spaces, 4)
212 self.assertEqual(isp.indent_spaces, 4)
213 isp.push('y=2\n')
213 isp.push('y=2\n')
214 self.assertEqual(isp.indent_spaces, 0)
214 self.assertEqual(isp.indent_spaces, 0)
215 isp.push('if 1:\t\n x=1')
215 isp.push('if 1:\t\n x=1')
216 self.assertEqual(isp.indent_spaces, 4)
216 self.assertEqual(isp.indent_spaces, 4)
217 isp.push('y=2\n')
217 isp.push('y=2\n')
218 self.assertEqual(isp.indent_spaces, 0)
218 self.assertEqual(isp.indent_spaces, 0)
219
219
220 def test_dedent_pass(self):
220 def test_dedent_pass(self):
221 isp = self.isp # shorthand
221 isp = self.isp # shorthand
222 # should NOT cause dedent
222 # should NOT cause dedent
223 isp.push('if 1:\n passes = 5')
223 isp.push('if 1:\n passes = 5')
224 self.assertEqual(isp.indent_spaces, 4)
224 self.assertEqual(isp.indent_spaces, 4)
225 isp.push('if 1:\n pass')
225 isp.push('if 1:\n pass')
226 self.assertEqual(isp.indent_spaces, 0)
226 self.assertEqual(isp.indent_spaces, 0)
227 isp.push('if 1:\n pass ')
227 isp.push('if 1:\n pass ')
228 self.assertEqual(isp.indent_spaces, 0)
228 self.assertEqual(isp.indent_spaces, 0)
229
229
230 def test_dedent_raise(self):
230 def test_dedent_raise(self):
231 isp = self.isp # shorthand
231 isp = self.isp # shorthand
232 # should NOT cause dedent
232 # should NOT cause dedent
233 isp.push('if 1:\n raised = 4')
233 isp.push('if 1:\n raised = 4')
234 self.assertEqual(isp.indent_spaces, 4)
234 self.assertEqual(isp.indent_spaces, 4)
235 isp.push('if 1:\n raise TypeError()')
235 isp.push('if 1:\n raise TypeError()')
236 self.assertEqual(isp.indent_spaces, 0)
236 self.assertEqual(isp.indent_spaces, 0)
237 isp.push('if 1:\n raise')
237 isp.push('if 1:\n raise')
238 self.assertEqual(isp.indent_spaces, 0)
238 self.assertEqual(isp.indent_spaces, 0)
239 isp.push('if 1:\n raise ')
239 isp.push('if 1:\n raise ')
240 self.assertEqual(isp.indent_spaces, 0)
240 self.assertEqual(isp.indent_spaces, 0)
241
241
242 def test_dedent_return(self):
242 def test_dedent_return(self):
243 isp = self.isp # shorthand
243 isp = self.isp # shorthand
244 # should NOT cause dedent
244 # should NOT cause dedent
245 isp.push('if 1:\n returning = 4')
245 isp.push('if 1:\n returning = 4')
246 self.assertEqual(isp.indent_spaces, 4)
246 self.assertEqual(isp.indent_spaces, 4)
247 isp.push('if 1:\n return 5 + 493')
247 isp.push('if 1:\n return 5 + 493')
248 self.assertEqual(isp.indent_spaces, 0)
248 self.assertEqual(isp.indent_spaces, 0)
249 isp.push('if 1:\n return')
249 isp.push('if 1:\n return')
250 self.assertEqual(isp.indent_spaces, 0)
250 self.assertEqual(isp.indent_spaces, 0)
251 isp.push('if 1:\n return ')
251 isp.push('if 1:\n return ')
252 self.assertEqual(isp.indent_spaces, 0)
252 self.assertEqual(isp.indent_spaces, 0)
253 isp.push('if 1:\n return(0)')
253 isp.push('if 1:\n return(0)')
254 self.assertEqual(isp.indent_spaces, 0)
254 self.assertEqual(isp.indent_spaces, 0)
255
255
256 def test_push(self):
256 def test_push(self):
257 isp = self.isp
257 isp = self.isp
258 self.assertTrue(isp.push('x=1'))
258 self.assertTrue(isp.push('x=1'))
259
259
260 def test_push2(self):
260 def test_push2(self):
261 isp = self.isp
261 isp = self.isp
262 self.assertFalse(isp.push('if 1:'))
262 self.assertFalse(isp.push('if 1:'))
263 for line in [' x=1', '# a comment', ' y=2']:
263 for line in [' x=1', '# a comment', ' y=2']:
264 self.assertTrue(isp.push(line))
264 self.assertTrue(isp.push(line))
265
265
266 def test_push3(self):
266 def test_push3(self):
267 isp = self.isp
267 isp = self.isp
268 isp.push('if True:')
268 isp.push('if True:')
269 isp.push(' a = 1')
269 isp.push(' a = 1')
270 self.assertFalse(isp.push('b = [1,'))
270 self.assertFalse(isp.push('b = [1,'))
271
271
272 def test_replace_mode(self):
272 def test_replace_mode(self):
273 isp = self.isp
273 isp = self.isp
274 isp.input_mode = 'cell'
274 isp.input_mode = 'cell'
275 isp.push('x=1')
275 isp.push('x=1')
276 self.assertEqual(isp.source, 'x=1\n')
276 self.assertEqual(isp.source, 'x=1\n')
277 isp.push('x=2')
277 isp.push('x=2')
278 self.assertEqual(isp.source, 'x=2\n')
278 self.assertEqual(isp.source, 'x=2\n')
279
279
280 def test_push_accepts_more(self):
280 def test_push_accepts_more(self):
281 isp = self.isp
281 isp = self.isp
282 isp.push('x=1')
282 isp.push('x=1')
283 self.assertFalse(isp.push_accepts_more())
283 self.assertFalse(isp.push_accepts_more())
284
284
285 def test_push_accepts_more2(self):
285 def test_push_accepts_more2(self):
286 # In cell mode, inputs must be fed in whole blocks, so skip this test
286 # In cell mode, inputs must be fed in whole blocks, so skip this test
287 if self.isp.input_mode == 'cell': return
287 if self.isp.input_mode == 'cell': return
288
288
289 isp = self.isp
289 isp = self.isp
290 isp.push('if 1:')
290 isp.push('if 1:')
291 self.assertTrue(isp.push_accepts_more())
291 self.assertTrue(isp.push_accepts_more())
292 isp.push(' x=1')
292 isp.push(' x=1')
293 self.assertTrue(isp.push_accepts_more())
293 self.assertTrue(isp.push_accepts_more())
294 isp.push('')
294 isp.push('')
295 self.assertFalse(isp.push_accepts_more())
295 self.assertFalse(isp.push_accepts_more())
296
296
297 def test_push_accepts_more3(self):
297 def test_push_accepts_more3(self):
298 isp = self.isp
298 isp = self.isp
299 isp.push("x = (2+\n3)")
299 isp.push("x = (2+\n3)")
300 self.assertFalse(isp.push_accepts_more())
300 self.assertFalse(isp.push_accepts_more())
301
301
302 def test_push_accepts_more4(self):
302 def test_push_accepts_more4(self):
303 # In cell mode, inputs must be fed in whole blocks, so skip this test
303 # In cell mode, inputs must be fed in whole blocks, so skip this test
304 if self.isp.input_mode == 'cell': return
304 if self.isp.input_mode == 'cell': return
305
305
306 isp = self.isp
306 isp = self.isp
307 # When a multiline statement contains parens or multiline strings, we
307 # When a multiline statement contains parens or multiline strings, we
308 # shouldn't get confused.
308 # shouldn't get confused.
309 # FIXME: we should be able to better handle de-dents in statements like
309 # FIXME: we should be able to better handle de-dents in statements like
310 # multiline strings and multiline expressions (continued with \ or
310 # multiline strings and multiline expressions (continued with \ or
311 # parens). Right now we aren't handling the indentation tracking quite
311 # parens). Right now we aren't handling the indentation tracking quite
312 # correctly with this, though in practice it may not be too much of a
312 # correctly with this, though in practice it may not be too much of a
313 # problem. We'll need to see.
313 # problem. We'll need to see.
314 isp.push("if 1:")
314 isp.push("if 1:")
315 isp.push(" x = (2+")
315 isp.push(" x = (2+")
316 isp.push(" 3)")
316 isp.push(" 3)")
317 self.assertTrue(isp.push_accepts_more())
317 self.assertTrue(isp.push_accepts_more())
318 isp.push(" y = 3")
318 isp.push(" y = 3")
319 self.assertTrue(isp.push_accepts_more())
319 self.assertTrue(isp.push_accepts_more())
320 isp.push('')
320 isp.push('')
321 self.assertFalse(isp.push_accepts_more())
321 self.assertFalse(isp.push_accepts_more())
322
322
323 def test_push_accepts_more5(self):
323 def test_push_accepts_more5(self):
324 # In cell mode, inputs must be fed in whole blocks, so skip this test
324 # In cell mode, inputs must be fed in whole blocks, so skip this test
325 if self.isp.input_mode == 'cell': return
325 if self.isp.input_mode == 'cell': return
326
326
327 isp = self.isp
327 isp = self.isp
328 isp.push('try:')
328 isp.push('try:')
329 isp.push(' a = 5')
329 isp.push(' a = 5')
330 isp.push('except:')
330 isp.push('except:')
331 isp.push(' raise')
331 isp.push(' raise')
332 self.assertTrue(isp.push_accepts_more())
332 self.assertTrue(isp.push_accepts_more())
333
333
334 def test_continuation(self):
334 def test_continuation(self):
335 isp = self.isp
335 isp = self.isp
336 isp.push("import os, \\")
336 isp.push("import os, \\")
337 self.assertTrue(isp.push_accepts_more())
337 self.assertTrue(isp.push_accepts_more())
338 isp.push("sys")
338 isp.push("sys")
339 self.assertFalse(isp.push_accepts_more())
339 self.assertFalse(isp.push_accepts_more())
340
340
341 def test_syntax_error(self):
341 def test_syntax_error(self):
342 isp = self.isp
342 isp = self.isp
343 # Syntax errors immediately produce a 'ready' block, so the invalid
343 # Syntax errors immediately produce a 'ready' block, so the invalid
344 # Python can be sent to the kernel for evaluation with possible ipython
344 # Python can be sent to the kernel for evaluation with possible ipython
345 # special-syntax conversion.
345 # special-syntax conversion.
346 isp.push('run foo')
346 isp.push('run foo')
347 self.assertFalse(isp.push_accepts_more())
347 self.assertFalse(isp.push_accepts_more())
348
348
349 def test_unicode(self):
349 def test_unicode(self):
350 self.isp.push(u"PΓ©rez")
350 self.isp.push(u"PΓ©rez")
351 self.isp.push(u'\xc3\xa9')
351 self.isp.push(u'\xc3\xa9')
352 self.isp.push(u"u'\xc3\xa9'")
352 self.isp.push(u"u'\xc3\xa9'")
353
353
354 class InteractiveLoopTestCase(unittest.TestCase):
354 class InteractiveLoopTestCase(unittest.TestCase):
355 """Tests for an interactive loop like a python shell.
355 """Tests for an interactive loop like a python shell.
356 """
356 """
357 def check_ns(self, lines, ns):
357 def check_ns(self, lines, ns):
358 """Validate that the given input lines produce the resulting namespace.
358 """Validate that the given input lines produce the resulting namespace.
359
359
360 Note: the input lines are given exactly as they would be typed in an
360 Note: the input lines are given exactly as they would be typed in an
361 auto-indenting environment, as mini_interactive_loop above already does
361 auto-indenting environment, as mini_interactive_loop above already does
362 auto-indenting and prepends spaces to the input.
362 auto-indenting and prepends spaces to the input.
363 """
363 """
364 src = mini_interactive_loop(pseudo_input(lines))
364 src = mini_interactive_loop(pseudo_input(lines))
365 test_ns = {}
365 test_ns = {}
366 exec src in test_ns
366 exec src in test_ns
367 # We can't check that the provided ns is identical to the test_ns,
367 # We can't check that the provided ns is identical to the test_ns,
368 # because Python fills test_ns with extra keys (copyright, etc). But
368 # because Python fills test_ns with extra keys (copyright, etc). But
369 # we can check that the given dict is *contained* in test_ns
369 # we can check that the given dict is *contained* in test_ns
370 for k,v in ns.iteritems():
370 for k,v in ns.iteritems():
371 self.assertEqual(test_ns[k], v)
371 self.assertEqual(test_ns[k], v)
372
372
373 def test_simple(self):
373 def test_simple(self):
374 self.check_ns(['x=1'], dict(x=1))
374 self.check_ns(['x=1'], dict(x=1))
375
375
376 def test_simple2(self):
376 def test_simple2(self):
377 self.check_ns(['if 1:', 'x=2'], dict(x=2))
377 self.check_ns(['if 1:', 'x=2'], dict(x=2))
378
378
379 def test_xy(self):
379 def test_xy(self):
380 self.check_ns(['x=1; y=2'], dict(x=1, y=2))
380 self.check_ns(['x=1; y=2'], dict(x=1, y=2))
381
381
382 def test_abc(self):
382 def test_abc(self):
383 self.check_ns(['if 1:','a=1','b=2','c=3'], dict(a=1, b=2, c=3))
383 self.check_ns(['if 1:','a=1','b=2','c=3'], dict(a=1, b=2, c=3))
384
384
385 def test_multi(self):
385 def test_multi(self):
386 self.check_ns(['x =(1+','1+','2)'], dict(x=4))
386 self.check_ns(['x =(1+','1+','2)'], dict(x=4))
387
387
388
388
389 def test_LineInfo():
389 def test_LineInfo():
390 """Simple test for LineInfo construction and str()"""
390 """Simple test for LineInfo construction and str()"""
391 linfo = isp.LineInfo(' %cd /home')
391 linfo = isp.LineInfo(' %cd /home')
392 nt.assert_equals(str(linfo), 'LineInfo [ |%|cd|/home]')
392 nt.assert_equals(str(linfo), 'LineInfo [ |%|cd|/home]')
393
393
394 # Transformer tests
394 # Transformer tests
395 def transform_checker(tests, func):
395 def transform_checker(tests, func):
396 """Utility to loop over test inputs"""
396 """Utility to loop over test inputs"""
397 for inp, tr in tests:
397 for inp, tr in tests:
398 nt.assert_equals(func(inp), tr)
398 nt.assert_equals(func(inp), tr)
399
399
400 # Data for all the syntax tests in the form of lists of pairs of
400 # Data for all the syntax tests in the form of lists of pairs of
401 # raw/transformed input. We store it here as a global dict so that we can use
401 # raw/transformed input. We store it here as a global dict so that we can use
402 # it both within single-function tests and also to validate the behavior of the
402 # it both within single-function tests and also to validate the behavior of the
403 # larger objects
403 # larger objects
404
404
405 syntax = \
405 syntax = \
406 dict(assign_system =
406 dict(assign_system =
407 [(i,py3compat.u_format(o)) for i,o in \
407 [(i,py3compat.u_format(o)) for i,o in \
408 [(u'a =! ls', "a = get_ipython().getoutput({u}'ls')"),
408 [(u'a =! ls', "a = get_ipython().getoutput({u}'ls')"),
409 (u'b = !ls', "b = get_ipython().getoutput({u}'ls')"),
409 (u'b = !ls', "b = get_ipython().getoutput({u}'ls')"),
410 ('x=1', 'x=1'), # normal input is unmodified
410 ('x=1', 'x=1'), # normal input is unmodified
411 (' ',' '), # blank lines are kept intact
411 (' ',' '), # blank lines are kept intact
412 ]],
412 ]],
413
413
414 assign_magic =
414 assign_magic =
415 [(i,py3compat.u_format(o)) for i,o in \
415 [(i,py3compat.u_format(o)) for i,o in \
416 [(u'a =% who', "a = get_ipython().magic({u}'who')"),
416 [(u'a =% who', "a = get_ipython().magic({u}'who')"),
417 (u'b = %who', "b = get_ipython().magic({u}'who')"),
417 (u'b = %who', "b = get_ipython().magic({u}'who')"),
418 ('x=1', 'x=1'), # normal input is unmodified
418 ('x=1', 'x=1'), # normal input is unmodified
419 (' ',' '), # blank lines are kept intact
419 (' ',' '), # blank lines are kept intact
420 ]],
420 ]],
421
421
422 classic_prompt =
422 classic_prompt =
423 [('>>> x=1', 'x=1'),
423 [('>>> x=1', 'x=1'),
424 ('x=1', 'x=1'), # normal input is unmodified
424 ('x=1', 'x=1'), # normal input is unmodified
425 (' ', ' '), # blank lines are kept intact
425 (' ', ' '), # blank lines are kept intact
426 ('... ', ''), # continuation prompts
426 ('... ', ''), # continuation prompts
427 ],
427 ],
428
428
429 ipy_prompt =
429 ipy_prompt =
430 [('In [1]: x=1', 'x=1'),
430 [('In [1]: x=1', 'x=1'),
431 ('x=1', 'x=1'), # normal input is unmodified
431 ('x=1', 'x=1'), # normal input is unmodified
432 (' ',' '), # blank lines are kept intact
432 (' ',' '), # blank lines are kept intact
433 (' ....: ', ''), # continuation prompts
433 (' ....: ', ''), # continuation prompts
434 ],
434 ],
435
435
436 # Tests for the escape transformer to leave normal code alone
436 # Tests for the escape transformer to leave normal code alone
437 escaped_noesc =
437 escaped_noesc =
438 [ (' ', ' '),
438 [ (' ', ' '),
439 ('x=1', 'x=1'),
439 ('x=1', 'x=1'),
440 ],
440 ],
441
441
442 # System calls
442 # System calls
443 escaped_shell =
443 escaped_shell =
444 [(i,py3compat.u_format(o)) for i,o in \
444 [(i,py3compat.u_format(o)) for i,o in \
445 [ (u'!ls', "get_ipython().system({u}'ls')"),
445 [ (u'!ls', "get_ipython().system({u}'ls')"),
446 # Double-escape shell, this means to capture the output of the
446 # Double-escape shell, this means to capture the output of the
447 # subprocess and return it
447 # subprocess and return it
448 (u'!!ls', "get_ipython().getoutput({u}'ls')"),
448 (u'!!ls', "get_ipython().getoutput({u}'ls')"),
449 ]],
449 ]],
450
450
451 # Help/object info
451 # Help/object info
452 escaped_help =
452 escaped_help =
453 [(i,py3compat.u_format(o)) for i,o in \
453 [(i,py3compat.u_format(o)) for i,o in \
454 [ (u'?', 'get_ipython().show_usage()'),
454 [ (u'?', 'get_ipython().show_usage()'),
455 (u'?x1', "get_ipython().magic({u}'pinfo x1')"),
455 (u'?x1', "get_ipython().magic({u}'pinfo x1')"),
456 (u'??x2', "get_ipython().magic({u}'pinfo2 x2')"),
456 (u'??x2', "get_ipython().magic({u}'pinfo2 x2')"),
457 (u'?a.*s', "get_ipython().magic({u}'psearch a.*s')"),
457 (u'?a.*s', "get_ipython().magic({u}'psearch a.*s')"),
458 (u'?%hist', "get_ipython().magic({u}'pinfo %hist')"),
458 (u'?%hist1', "get_ipython().magic({u}'pinfo %hist1')"),
459 (u'?%%hist2', "get_ipython().magic({u}'pinfo %%hist2')"),
459 (u'?abc = qwe', "get_ipython().magic({u}'pinfo abc')"),
460 (u'?abc = qwe', "get_ipython().magic({u}'pinfo abc')"),
460 ]],
461 ]],
461
462
462 end_help =
463 end_help =
463 [(i,py3compat.u_format(o)) for i,o in \
464 [(i,py3compat.u_format(o)) for i,o in \
464 [ (u'x3?', "get_ipython().magic({u}'pinfo x3')"),
465 [ (u'x3?', "get_ipython().magic({u}'pinfo x3')"),
465 (u'x4??', "get_ipython().magic({u}'pinfo2 x4')"),
466 (u'x4??', "get_ipython().magic({u}'pinfo2 x4')"),
466 (u'%hist?', "get_ipython().magic({u}'pinfo %hist')"),
467 (u'%hist1?', "get_ipython().magic({u}'pinfo %hist1')"),
468 (u'%hist2??', "get_ipython().magic({u}'pinfo2 %hist2')"),
469 (u'%%hist3?', "get_ipython().magic({u}'pinfo %%hist3')"),
470 (u'%%hist4??', "get_ipython().magic({u}'pinfo2 %%hist4')"),
467 (u'f*?', "get_ipython().magic({u}'psearch f*')"),
471 (u'f*?', "get_ipython().magic({u}'psearch f*')"),
468 (u'ax.*aspe*?', "get_ipython().magic({u}'psearch ax.*aspe*')"),
472 (u'ax.*aspe*?', "get_ipython().magic({u}'psearch ax.*aspe*')"),
469 (u'a = abc?', "get_ipython().set_next_input({u}'a = abc');"
473 (u'a = abc?', "get_ipython().set_next_input({u}'a = abc');"
470 "get_ipython().magic({u}'pinfo abc')"),
474 "get_ipython().magic({u}'pinfo abc')"),
471 (u'a = abc.qe??', "get_ipython().set_next_input({u}'a = abc.qe');"
475 (u'a = abc.qe??', "get_ipython().set_next_input({u}'a = abc.qe');"
472 "get_ipython().magic({u}'pinfo2 abc.qe')"),
476 "get_ipython().magic({u}'pinfo2 abc.qe')"),
473 (u'a = *.items?', "get_ipython().set_next_input({u}'a = *.items');"
477 (u'a = *.items?', "get_ipython().set_next_input({u}'a = *.items');"
474 "get_ipython().magic({u}'psearch *.items')"),
478 "get_ipython().magic({u}'psearch *.items')"),
475 (u'plot(a?', "get_ipython().set_next_input({u}'plot(a');"
479 (u'plot(a?', "get_ipython().set_next_input({u}'plot(a');"
476 "get_ipython().magic({u}'pinfo a')"),
480 "get_ipython().magic({u}'pinfo a')"),
477 (u'a*2 #comment?', 'a*2 #comment?'),
481 (u'a*2 #comment?', 'a*2 #comment?'),
478 ]],
482 ]],
479
483
480 # Explicit magic calls
484 # Explicit magic calls
481 escaped_magic =
485 escaped_magic =
482 [(i,py3compat.u_format(o)) for i,o in \
486 [(i,py3compat.u_format(o)) for i,o in \
483 [ (u'%cd', "get_ipython().magic({u}'cd')"),
487 [ (u'%cd', "get_ipython().magic({u}'cd')"),
484 (u'%cd /home', "get_ipython().magic({u}'cd /home')"),
488 (u'%cd /home', "get_ipython().magic({u}'cd /home')"),
485 # Backslashes need to be escaped.
489 # Backslashes need to be escaped.
486 (u'%cd C:\\User', "get_ipython().magic({u}'cd C:\\\\User')"),
490 (u'%cd C:\\User', "get_ipython().magic({u}'cd C:\\\\User')"),
487 (u' %magic', " get_ipython().magic({u}'magic')"),
491 (u' %magic', " get_ipython().magic({u}'magic')"),
488 ]],
492 ]],
489
493
490 # Quoting with separate arguments
494 # Quoting with separate arguments
491 escaped_quote =
495 escaped_quote =
492 [ (',f', 'f("")'),
496 [ (',f', 'f("")'),
493 (',f x', 'f("x")'),
497 (',f x', 'f("x")'),
494 (' ,f y', ' f("y")'),
498 (' ,f y', ' f("y")'),
495 (',f a b', 'f("a", "b")'),
499 (',f a b', 'f("a", "b")'),
496 ],
500 ],
497
501
498 # Quoting with single argument
502 # Quoting with single argument
499 escaped_quote2 =
503 escaped_quote2 =
500 [ (';f', 'f("")'),
504 [ (';f', 'f("")'),
501 (';f x', 'f("x")'),
505 (';f x', 'f("x")'),
502 (' ;f y', ' f("y")'),
506 (' ;f y', ' f("y")'),
503 (';f a b', 'f("a b")'),
507 (';f a b', 'f("a b")'),
504 ],
508 ],
505
509
506 # Simply apply parens
510 # Simply apply parens
507 escaped_paren =
511 escaped_paren =
508 [ ('/f', 'f()'),
512 [ ('/f', 'f()'),
509 ('/f x', 'f(x)'),
513 ('/f x', 'f(x)'),
510 (' /f y', ' f(y)'),
514 (' /f y', ' f(y)'),
511 ('/f a b', 'f(a, b)'),
515 ('/f a b', 'f(a, b)'),
512 ],
516 ],
513
517
514 # Check that we transform prompts before other transforms
518 # Check that we transform prompts before other transforms
515 mixed =
519 mixed =
516 [(i,py3compat.u_format(o)) for i,o in \
520 [(i,py3compat.u_format(o)) for i,o in \
517 [ (u'In [1]: %lsmagic', "get_ipython().magic({u}'lsmagic')"),
521 [ (u'In [1]: %lsmagic', "get_ipython().magic({u}'lsmagic')"),
518 (u'>>> %lsmagic', "get_ipython().magic({u}'lsmagic')"),
522 (u'>>> %lsmagic', "get_ipython().magic({u}'lsmagic')"),
519 (u'In [2]: !ls', "get_ipython().system({u}'ls')"),
523 (u'In [2]: !ls', "get_ipython().system({u}'ls')"),
520 (u'In [3]: abs?', "get_ipython().magic({u}'pinfo abs')"),
524 (u'In [3]: abs?', "get_ipython().magic({u}'pinfo abs')"),
521 (u'In [4]: b = %who', "b = get_ipython().magic({u}'who')"),
525 (u'In [4]: b = %who', "b = get_ipython().magic({u}'who')"),
522 ]],
526 ]],
523 )
527 )
524
528
525 # multiline syntax examples. Each of these should be a list of lists, with
529 # multiline syntax examples. Each of these should be a list of lists, with
526 # each entry itself having pairs of raw/transformed input. The union (with
530 # each entry itself having pairs of raw/transformed input. The union (with
527 # '\n'.join() of the transformed inputs is what the splitter should produce
531 # '\n'.join() of the transformed inputs is what the splitter should produce
528 # when fed the raw lines one at a time via push.
532 # when fed the raw lines one at a time via push.
529 syntax_ml = \
533 syntax_ml = \
530 dict(classic_prompt =
534 dict(classic_prompt =
531 [ [('>>> for i in range(10):','for i in range(10):'),
535 [ [('>>> for i in range(10):','for i in range(10):'),
532 ('... print i',' print i'),
536 ('... print i',' print i'),
533 ('... ', ''),
537 ('... ', ''),
534 ],
538 ],
535 ],
539 ],
536
540
537 ipy_prompt =
541 ipy_prompt =
538 [ [('In [24]: for i in range(10):','for i in range(10):'),
542 [ [('In [24]: for i in range(10):','for i in range(10):'),
539 (' ....: print i',' print i'),
543 (' ....: print i',' print i'),
540 (' ....: ', ''),
544 (' ....: ', ''),
541 ],
545 ],
542 ],
546 ],
543
547
544 multiline_datastructure =
548 multiline_datastructure =
545 [ [('>>> a = [1,','a = [1,'),
549 [ [('>>> a = [1,','a = [1,'),
546 ('... 2]','2]'),
550 ('... 2]','2]'),
547 ],
551 ],
548 ],
552 ],
549 )
553 )
550
554
551
555
552 def test_assign_system():
556 def test_assign_system():
553 tt.check_pairs(isp.transform_assign_system, syntax['assign_system'])
557 tt.check_pairs(isp.transform_assign_system, syntax['assign_system'])
554
558
555
559
556 def test_assign_magic():
560 def test_assign_magic():
557 tt.check_pairs(isp.transform_assign_magic, syntax['assign_magic'])
561 tt.check_pairs(isp.transform_assign_magic, syntax['assign_magic'])
558
562
559
563
560 def test_classic_prompt():
564 def test_classic_prompt():
561 transform_checker(syntax['classic_prompt'], isp.transform_classic_prompt)
565 transform_checker(syntax['classic_prompt'], isp.transform_classic_prompt)
562 for example in syntax_ml['classic_prompt']:
566 for example in syntax_ml['classic_prompt']:
563 transform_checker(example, isp.transform_classic_prompt)
567 transform_checker(example, isp.transform_classic_prompt)
564
568
565
569
566 def test_ipy_prompt():
570 def test_ipy_prompt():
567 transform_checker(syntax['ipy_prompt'], isp.transform_ipy_prompt)
571 transform_checker(syntax['ipy_prompt'], isp.transform_ipy_prompt)
568 for example in syntax_ml['ipy_prompt']:
572 for example in syntax_ml['ipy_prompt']:
569 transform_checker(example, isp.transform_ipy_prompt)
573 transform_checker(example, isp.transform_ipy_prompt)
570
574
571 def test_end_help():
575 def test_end_help():
572 tt.check_pairs(isp.transform_help_end, syntax['end_help'])
576 tt.check_pairs(isp.transform_help_end, syntax['end_help'])
573
577
574 def test_escaped_noesc():
578 def test_escaped_noesc():
575 tt.check_pairs(isp.transform_escaped, syntax['escaped_noesc'])
579 tt.check_pairs(isp.transform_escaped, syntax['escaped_noesc'])
576
580
577
581
578 def test_escaped_shell():
582 def test_escaped_shell():
579 tt.check_pairs(isp.transform_escaped, syntax['escaped_shell'])
583 tt.check_pairs(isp.transform_escaped, syntax['escaped_shell'])
580
584
581
585
582 def test_escaped_help():
586 def test_escaped_help():
583 tt.check_pairs(isp.transform_escaped, syntax['escaped_help'])
587 tt.check_pairs(isp.transform_escaped, syntax['escaped_help'])
584
588
585
589
586 def test_escaped_magic():
590 def test_escaped_magic():
587 tt.check_pairs(isp.transform_escaped, syntax['escaped_magic'])
591 tt.check_pairs(isp.transform_escaped, syntax['escaped_magic'])
588
592
589
593
590 def test_escaped_quote():
594 def test_escaped_quote():
591 tt.check_pairs(isp.transform_escaped, syntax['escaped_quote'])
595 tt.check_pairs(isp.transform_escaped, syntax['escaped_quote'])
592
596
593
597
594 def test_escaped_quote2():
598 def test_escaped_quote2():
595 tt.check_pairs(isp.transform_escaped, syntax['escaped_quote2'])
599 tt.check_pairs(isp.transform_escaped, syntax['escaped_quote2'])
596
600
597
601
598 def test_escaped_paren():
602 def test_escaped_paren():
599 tt.check_pairs(isp.transform_escaped, syntax['escaped_paren'])
603 tt.check_pairs(isp.transform_escaped, syntax['escaped_paren'])
600
604
601
605
602 class IPythonInputTestCase(InputSplitterTestCase):
606 class IPythonInputTestCase(InputSplitterTestCase):
603 """By just creating a new class whose .isp is a different instance, we
607 """By just creating a new class whose .isp is a different instance, we
604 re-run the same test battery on the new input splitter.
608 re-run the same test battery on the new input splitter.
605
609
606 In addition, this runs the tests over the syntax and syntax_ml dicts that
610 In addition, this runs the tests over the syntax and syntax_ml dicts that
607 were tested by individual functions, as part of the OO interface.
611 were tested by individual functions, as part of the OO interface.
608
612
609 It also makes some checks on the raw buffer storage.
613 It also makes some checks on the raw buffer storage.
610 """
614 """
611
615
612 def setUp(self):
616 def setUp(self):
613 self.isp = isp.IPythonInputSplitter(input_mode='line')
617 self.isp = isp.IPythonInputSplitter(input_mode='line')
614
618
615 def test_syntax(self):
619 def test_syntax(self):
616 """Call all single-line syntax tests from the main object"""
620 """Call all single-line syntax tests from the main object"""
617 isp = self.isp
621 isp = self.isp
618 for example in syntax.itervalues():
622 for example in syntax.itervalues():
619 for raw, out_t in example:
623 for raw, out_t in example:
620 if raw.startswith(' '):
624 if raw.startswith(' '):
621 continue
625 continue
622
626
623 isp.push(raw)
627 isp.push(raw)
624 out, out_raw = isp.source_raw_reset()
628 out, out_raw = isp.source_raw_reset()
625 self.assertEqual(out.rstrip(), out_t,
629 self.assertEqual(out.rstrip(), out_t,
626 tt.pair_fail_msg.format("inputsplitter",raw, out_t, out))
630 tt.pair_fail_msg.format("inputsplitter",raw, out_t, out))
627 self.assertEqual(out_raw.rstrip(), raw.rstrip())
631 self.assertEqual(out_raw.rstrip(), raw.rstrip())
628
632
629 def test_syntax_multiline(self):
633 def test_syntax_multiline(self):
630 isp = self.isp
634 isp = self.isp
631 for example in syntax_ml.itervalues():
635 for example in syntax_ml.itervalues():
632 out_t_parts = []
636 out_t_parts = []
633 raw_parts = []
637 raw_parts = []
634 for line_pairs in example:
638 for line_pairs in example:
635 for lraw, out_t_part in line_pairs:
639 for lraw, out_t_part in line_pairs:
636 isp.push(lraw)
640 isp.push(lraw)
637 out_t_parts.append(out_t_part)
641 out_t_parts.append(out_t_part)
638 raw_parts.append(lraw)
642 raw_parts.append(lraw)
639
643
640 out, out_raw = isp.source_raw_reset()
644 out, out_raw = isp.source_raw_reset()
641 out_t = '\n'.join(out_t_parts).rstrip()
645 out_t = '\n'.join(out_t_parts).rstrip()
642 raw = '\n'.join(raw_parts).rstrip()
646 raw = '\n'.join(raw_parts).rstrip()
643 self.assertEqual(out.rstrip(), out_t)
647 self.assertEqual(out.rstrip(), out_t)
644 self.assertEqual(out_raw.rstrip(), raw)
648 self.assertEqual(out_raw.rstrip(), raw)
645
649
646
650
647 class BlockIPythonInputTestCase(IPythonInputTestCase):
651 class BlockIPythonInputTestCase(IPythonInputTestCase):
648
652
649 # Deactivate tests that don't make sense for the block mode
653 # Deactivate tests that don't make sense for the block mode
650 test_push3 = test_split = lambda s: None
654 test_push3 = test_split = lambda s: None
651
655
652 def setUp(self):
656 def setUp(self):
653 self.isp = isp.IPythonInputSplitter(input_mode='cell')
657 self.isp = isp.IPythonInputSplitter(input_mode='cell')
654
658
655 def test_syntax_multiline(self):
659 def test_syntax_multiline(self):
656 isp = self.isp
660 isp = self.isp
657 for example in syntax_ml.itervalues():
661 for example in syntax_ml.itervalues():
658 raw_parts = []
662 raw_parts = []
659 out_t_parts = []
663 out_t_parts = []
660 for line_pairs in example:
664 for line_pairs in example:
661 for raw, out_t_part in line_pairs:
665 for raw, out_t_part in line_pairs:
662 raw_parts.append(raw)
666 raw_parts.append(raw)
663 out_t_parts.append(out_t_part)
667 out_t_parts.append(out_t_part)
664
668
665 raw = '\n'.join(raw_parts)
669 raw = '\n'.join(raw_parts)
666 out_t = '\n'.join(out_t_parts)
670 out_t = '\n'.join(out_t_parts)
667
671
668 isp.push(raw)
672 isp.push(raw)
669 out, out_raw = isp.source_raw_reset()
673 out, out_raw = isp.source_raw_reset()
670 # Match ignoring trailing whitespace
674 # Match ignoring trailing whitespace
671 self.assertEqual(out.rstrip(), out_t.rstrip())
675 self.assertEqual(out.rstrip(), out_t.rstrip())
672 self.assertEqual(out_raw.rstrip(), raw.rstrip())
676 self.assertEqual(out_raw.rstrip(), raw.rstrip())
673
677
674
678
675 #-----------------------------------------------------------------------------
679 #-----------------------------------------------------------------------------
676 # Main - use as a script, mostly for developer experiments
680 # Main - use as a script, mostly for developer experiments
677 #-----------------------------------------------------------------------------
681 #-----------------------------------------------------------------------------
678
682
679 if __name__ == '__main__':
683 if __name__ == '__main__':
680 # A simple demo for interactive experimentation. This code will not get
684 # A simple demo for interactive experimentation. This code will not get
681 # picked up by any test suite.
685 # picked up by any test suite.
682 from IPython.core.inputsplitter import InputSplitter, IPythonInputSplitter
686 from IPython.core.inputsplitter import InputSplitter, IPythonInputSplitter
683
687
684 # configure here the syntax to use, prompt and whether to autoindent
688 # configure here the syntax to use, prompt and whether to autoindent
685 #isp, start_prompt = InputSplitter(), '>>> '
689 #isp, start_prompt = InputSplitter(), '>>> '
686 isp, start_prompt = IPythonInputSplitter(), 'In> '
690 isp, start_prompt = IPythonInputSplitter(), 'In> '
687
691
688 autoindent = True
692 autoindent = True
689 #autoindent = False
693 #autoindent = False
690
694
691 try:
695 try:
692 while True:
696 while True:
693 prompt = start_prompt
697 prompt = start_prompt
694 while isp.push_accepts_more():
698 while isp.push_accepts_more():
695 indent = ' '*isp.indent_spaces
699 indent = ' '*isp.indent_spaces
696 if autoindent:
700 if autoindent:
697 line = indent + raw_input(prompt+indent)
701 line = indent + raw_input(prompt+indent)
698 else:
702 else:
699 line = raw_input(prompt)
703 line = raw_input(prompt)
700 isp.push(line)
704 isp.push(line)
701 prompt = '... '
705 prompt = '... '
702
706
703 # Here we just return input so we can use it in a test suite, but a
707 # Here we just return input so we can use it in a test suite, but a
704 # real interpreter would instead send it for execution somewhere.
708 # real interpreter would instead send it for execution somewhere.
705 #src = isp.source; raise EOFError # dbg
709 #src = isp.source; raise EOFError # dbg
706 src, raw = isp.source_raw_reset()
710 src, raw = isp.source_raw_reset()
707 print 'Input source was:\n', src
711 print 'Input source was:\n', src
708 print 'Raw source was:\n', raw
712 print 'Raw source was:\n', raw
709 except EOFError:
713 except EOFError:
710 print 'Bye'
714 print 'Bye'
711
715
712 # Tests for cell magics support
716 # Tests for cell magics support
713
717
714 def test_last_blank():
718 def test_last_blank():
715 nt.assert_false(isp.last_blank(''))
719 nt.assert_false(isp.last_blank(''))
716 nt.assert_false(isp.last_blank('abc'))
720 nt.assert_false(isp.last_blank('abc'))
717 nt.assert_false(isp.last_blank('abc\n'))
721 nt.assert_false(isp.last_blank('abc\n'))
718 nt.assert_false(isp.last_blank('abc\na'))
722 nt.assert_false(isp.last_blank('abc\na'))
719
723
720 nt.assert_true(isp.last_blank('\n'))
724 nt.assert_true(isp.last_blank('\n'))
721 nt.assert_true(isp.last_blank('\n '))
725 nt.assert_true(isp.last_blank('\n '))
722 nt.assert_true(isp.last_blank('abc\n '))
726 nt.assert_true(isp.last_blank('abc\n '))
723 nt.assert_true(isp.last_blank('abc\n\n'))
727 nt.assert_true(isp.last_blank('abc\n\n'))
724 nt.assert_true(isp.last_blank('abc\nd\n\n'))
728 nt.assert_true(isp.last_blank('abc\nd\n\n'))
725 nt.assert_true(isp.last_blank('abc\nd\ne\n\n'))
729 nt.assert_true(isp.last_blank('abc\nd\ne\n\n'))
726 nt.assert_true(isp.last_blank('abc \n \n \n\n'))
730 nt.assert_true(isp.last_blank('abc \n \n \n\n'))
727
731
728
732
729 def test_last_two_blanks():
733 def test_last_two_blanks():
730 nt.assert_false(isp.last_two_blanks(''))
734 nt.assert_false(isp.last_two_blanks(''))
731 nt.assert_false(isp.last_two_blanks('abc'))
735 nt.assert_false(isp.last_two_blanks('abc'))
732 nt.assert_false(isp.last_two_blanks('abc\n'))
736 nt.assert_false(isp.last_two_blanks('abc\n'))
733 nt.assert_false(isp.last_two_blanks('abc\n\na'))
737 nt.assert_false(isp.last_two_blanks('abc\n\na'))
734 nt.assert_false(isp.last_two_blanks('abc\n \n'))
738 nt.assert_false(isp.last_two_blanks('abc\n \n'))
735 nt.assert_false(isp.last_two_blanks('abc\n\n'))
739 nt.assert_false(isp.last_two_blanks('abc\n\n'))
736
740
737 nt.assert_true(isp.last_two_blanks('\n\n'))
741 nt.assert_true(isp.last_two_blanks('\n\n'))
738 nt.assert_true(isp.last_two_blanks('\n\n '))
742 nt.assert_true(isp.last_two_blanks('\n\n '))
739 nt.assert_true(isp.last_two_blanks('\n \n'))
743 nt.assert_true(isp.last_two_blanks('\n \n'))
740 nt.assert_true(isp.last_two_blanks('abc\n\n '))
744 nt.assert_true(isp.last_two_blanks('abc\n\n '))
741 nt.assert_true(isp.last_two_blanks('abc\n\n\n'))
745 nt.assert_true(isp.last_two_blanks('abc\n\n\n'))
742 nt.assert_true(isp.last_two_blanks('abc\n\n \n'))
746 nt.assert_true(isp.last_two_blanks('abc\n\n \n'))
743 nt.assert_true(isp.last_two_blanks('abc\n\n \n '))
747 nt.assert_true(isp.last_two_blanks('abc\n\n \n '))
744 nt.assert_true(isp.last_two_blanks('abc\n\n \n \n'))
748 nt.assert_true(isp.last_two_blanks('abc\n\n \n \n'))
745 nt.assert_true(isp.last_two_blanks('abc\nd\n\n\n'))
749 nt.assert_true(isp.last_two_blanks('abc\nd\n\n\n'))
746 nt.assert_true(isp.last_two_blanks('abc\nd\ne\nf\n\n\n'))
750 nt.assert_true(isp.last_two_blanks('abc\nd\ne\nf\n\n\n'))
747
751
748
752
749 class CellModeCellMagics(unittest.TestCase):
753 class CellModeCellMagics(unittest.TestCase):
750 sp = isp.IPythonInputSplitter(input_mode='cell')
754 sp = isp.IPythonInputSplitter(input_mode='cell')
751
755
752 def test_whole_cell(self):
756 def test_whole_cell(self):
753 src = "%%cellm line\nbody\n"
757 src = "%%cellm line\nbody\n"
754 sp = self.sp
758 sp = self.sp
755 sp.push(src)
759 sp.push(src)
756 nt.assert_equal(sp.cell_magic_parts, ['body\n'])
760 nt.assert_equal(sp.cell_magic_parts, ['body\n'])
757 out = sp.source
761 out = sp.source
758 ref = u"get_ipython()._cell_magic(u'cellm', u'line')\n"
762 ref = u"get_ipython()._cell_magic(u'cellm', u'line')\n"
759 nt.assert_equal(out, ref)
763 nt.assert_equal(out, ref)
760
764
761 def test_incremental(self):
765 def test_incremental(self):
762 sp = self.sp
766 sp = self.sp
763 src = '%%cellm line2\n'
767 src = '%%cellm line2\n'
764 sp.push(src)
768 sp.push(src)
765 nt.assert_true(sp.push_accepts_more()) #1
769 nt.assert_true(sp.push_accepts_more()) #1
766 src += '\n'
770 src += '\n'
767 sp.push(src)
771 sp.push(src)
768 # Note: if we ever change the logic to allow full blank lines (see
772 # Note: if we ever change the logic to allow full blank lines (see
769 # _handle_cell_magic), then the following test should change to true
773 # _handle_cell_magic), then the following test should change to true
770 nt.assert_false(sp.push_accepts_more()) #2
774 nt.assert_false(sp.push_accepts_more()) #2
771 # By now, even with full blanks allowed, a second blank should signal
775 # By now, even with full blanks allowed, a second blank should signal
772 # the end. For now this test is only a redundancy safety, but don't
776 # the end. For now this test is only a redundancy safety, but don't
773 # delete it in case we change our mind and the previous one goes to
777 # delete it in case we change our mind and the previous one goes to
774 # true.
778 # true.
775 src += '\n'
779 src += '\n'
776 sp.push(src)
780 sp.push(src)
777 nt.assert_false(sp.push_accepts_more()) #3
781 nt.assert_false(sp.push_accepts_more()) #3
778
782
779 def tearDown(self):
783 def tearDown(self):
780 self.sp.reset()
784 self.sp.reset()
781
785
782
786
783 class LineModeCellMagics(unittest.TestCase):
787 class LineModeCellMagics(unittest.TestCase):
784 sp = isp.IPythonInputSplitter(input_mode='line')
788 sp = isp.IPythonInputSplitter(input_mode='line')
785
789
786 def test_whole_cell(self):
790 def test_whole_cell(self):
787 src = "%%cellm line\nbody\n"
791 src = "%%cellm line\nbody\n"
788 sp = self.sp
792 sp = self.sp
789 sp.push(src)
793 sp.push(src)
790 nt.assert_equal(sp.cell_magic_parts, ['body\n'])
794 nt.assert_equal(sp.cell_magic_parts, ['body\n'])
791 out = sp.source
795 out = sp.source
792 ref = u"get_ipython()._cell_magic(u'cellm', u'line')\n"
796 ref = u"get_ipython()._cell_magic(u'cellm', u'line')\n"
793 nt.assert_equal(out, ref)
797 nt.assert_equal(out, ref)
794
798
795 def test_incremental(self):
799 def test_incremental(self):
796 sp = self.sp
800 sp = self.sp
797 sp.push('%%cellm line2\n')
801 sp.push('%%cellm line2\n')
798 nt.assert_true(sp.push_accepts_more()) #1
802 nt.assert_true(sp.push_accepts_more()) #1
799 sp.push('\n')
803 sp.push('\n')
800 nt.assert_false(sp.push_accepts_more()) #2
804 nt.assert_false(sp.push_accepts_more()) #2
801
805
802 def tearDown(self):
806 def tearDown(self):
803 self.sp.reset()
807 self.sp.reset()
General Comments 0
You need to be logged in to leave comments. Login now