##// END OF EJS Templates
Merge branch 'djv-master': partial fix for issue #678....
Fernando Perez -
r5093:a030f7eb merge
parent child Browse files
Show More
@@ -1,771 +1,773 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
63 from __future__ import print_function
64
64
65 #-----------------------------------------------------------------------------
65 #-----------------------------------------------------------------------------
66 # Imports
66 # Imports
67 #-----------------------------------------------------------------------------
67 #-----------------------------------------------------------------------------
68 # stdlib
68 # stdlib
69 import ast
69 import ast
70 import codeop
70 import codeop
71 import re
71 import re
72 import sys
72 import sys
73 import tokenize
73 import tokenize
74 from StringIO import StringIO
74 from StringIO import StringIO
75
75
76 # IPython modules
76 # IPython modules
77 from IPython.core.splitinput import split_user_input, LineInfo
77 from IPython.core.splitinput import split_user_input, LineInfo
78 from IPython.utils.text import make_quoted_expr
78 from IPython.utils.text import make_quoted_expr
79 from IPython.utils.py3compat import cast_unicode
79 from IPython.utils.py3compat import cast_unicode
80
80
81 #-----------------------------------------------------------------------------
81 #-----------------------------------------------------------------------------
82 # Globals
82 # Globals
83 #-----------------------------------------------------------------------------
83 #-----------------------------------------------------------------------------
84
84
85 # The escape sequences that define the syntax transformations IPython will
85 # The escape sequences that define the syntax transformations IPython will
86 # apply to user input. These can NOT be just changed here: many regular
86 # apply to user input. These can NOT be just changed here: many regular
87 # expressions and other parts of the code may use their hardcoded values, and
87 # expressions and other parts of the code may use their hardcoded values, and
88 # for all intents and purposes they constitute the 'IPython syntax', so they
88 # for all intents and purposes they constitute the 'IPython syntax', so they
89 # should be considered fixed.
89 # should be considered fixed.
90
90
91 ESC_SHELL = '!' # Send line to underlying system shell
91 ESC_SHELL = '!' # Send line to underlying system shell
92 ESC_SH_CAP = '!!' # Send line to system shell and capture output
92 ESC_SH_CAP = '!!' # Send line to system shell and capture output
93 ESC_HELP = '?' # Find information about object
93 ESC_HELP = '?' # Find information about object
94 ESC_HELP2 = '??' # Find extra-detailed information about object
94 ESC_HELP2 = '??' # Find extra-detailed information about object
95 ESC_MAGIC = '%' # Call magic function
95 ESC_MAGIC = '%' # Call magic function
96 ESC_QUOTE = ',' # Split args on whitespace, quote each as string and call
96 ESC_QUOTE = ',' # Split args on whitespace, quote each as string and call
97 ESC_QUOTE2 = ';' # Quote all args as a single string, call
97 ESC_QUOTE2 = ';' # Quote all args as a single string, call
98 ESC_PAREN = '/' # Call first argument with rest of line as arguments
98 ESC_PAREN = '/' # Call first argument with rest of line as arguments
99
99
100 #-----------------------------------------------------------------------------
100 #-----------------------------------------------------------------------------
101 # Utilities
101 # Utilities
102 #-----------------------------------------------------------------------------
102 #-----------------------------------------------------------------------------
103
103
104 # FIXME: These are general-purpose utilities that later can be moved to the
104 # FIXME: These are general-purpose utilities that later can be moved to the
105 # general ward. Kept here for now because we're being very strict about test
105 # general ward. Kept here for now because we're being very strict about test
106 # coverage with this code, and this lets us ensure that we keep 100% coverage
106 # coverage with this code, and this lets us ensure that we keep 100% coverage
107 # while developing.
107 # while developing.
108
108
109 # compiled regexps for autoindent management
109 # compiled regexps for autoindent management
110 dedent_re = re.compile('|'.join([
110 dedent_re = re.compile('|'.join([
111 r'^\s+raise(\s.*)?$', # raise statement (+ space + other stuff, maybe)
111 r'^\s+raise(\s.*)?$', # raise statement (+ space + other stuff, maybe)
112 r'^\s+raise\([^\)]*\).*$', # wacky raise with immediate open paren
112 r'^\s+raise\([^\)]*\).*$', # wacky raise with immediate open paren
113 r'^\s+return(\s.*)?$', # normal return (+ space + other stuff, maybe)
113 r'^\s+return(\s.*)?$', # normal return (+ space + other stuff, maybe)
114 r'^\s+return\([^\)]*\).*$', # wacky return with immediate open paren
114 r'^\s+return\([^\)]*\).*$', # wacky return with immediate open paren
115 r'^\s+pass\s*$' # pass (optionally followed by trailing spaces)
115 r'^\s+pass\s*$' # pass (optionally followed by trailing spaces)
116 ]))
116 ]))
117 ini_spaces_re = re.compile(r'^([ \t\r\f\v]+)')
117 ini_spaces_re = re.compile(r'^([ \t\r\f\v]+)')
118
118
119 # regexp to match pure comment lines so we don't accidentally insert 'if 1:'
119 # regexp to match pure comment lines so we don't accidentally insert 'if 1:'
120 # before pure comments
120 # before pure comments
121 comment_line_re = re.compile('^\s*\#')
121 comment_line_re = re.compile('^\s*\#')
122
122
123
123
124 def num_ini_spaces(s):
124 def num_ini_spaces(s):
125 """Return the number of initial spaces in a string.
125 """Return the number of initial spaces in a string.
126
126
127 Note that tabs are counted as a single space. For now, we do *not* support
127 Note that tabs are counted as a single space. For now, we do *not* support
128 mixing of tabs and spaces in the user's input.
128 mixing of tabs and spaces in the user's input.
129
129
130 Parameters
130 Parameters
131 ----------
131 ----------
132 s : string
132 s : string
133
133
134 Returns
134 Returns
135 -------
135 -------
136 n : int
136 n : int
137 """
137 """
138
138
139 ini_spaces = ini_spaces_re.match(s)
139 ini_spaces = ini_spaces_re.match(s)
140 if ini_spaces:
140 if ini_spaces:
141 return ini_spaces.end()
141 return ini_spaces.end()
142 else:
142 else:
143 return 0
143 return 0
144
144
145
145
146 def remove_comments(src):
146 def remove_comments(src):
147 """Remove all comments from input source.
147 """Remove all comments from input source.
148
148
149 Note: comments are NOT recognized inside of strings!
149 Note: comments are NOT recognized inside of strings!
150
150
151 Parameters
151 Parameters
152 ----------
152 ----------
153 src : string
153 src : string
154 A single or multiline input string.
154 A single or multiline input string.
155
155
156 Returns
156 Returns
157 -------
157 -------
158 String with all Python comments removed.
158 String with all Python comments removed.
159 """
159 """
160
160
161 return re.sub('#.*', '', src)
161 return re.sub('#.*', '', src)
162
162
163 def has_comment(src):
163 def has_comment(src):
164 """Indicate whether an input line has (i.e. ends in, or is) a comment.
164 """Indicate whether an input line has (i.e. ends in, or is) a comment.
165
165
166 This uses tokenize, so it can distinguish comments from # inside strings.
166 This uses tokenize, so it can distinguish comments from # inside strings.
167
167
168 Parameters
168 Parameters
169 ----------
169 ----------
170 src : string
170 src : string
171 A single line input string.
171 A single line input string.
172
172
173 Returns
173 Returns
174 -------
174 -------
175 Boolean: True if source has a comment.
175 Boolean: True if source has a comment.
176 """
176 """
177 readline = StringIO(src).readline
177 readline = StringIO(src).readline
178 toktypes = set()
178 toktypes = set()
179 try:
179 try:
180 for t in tokenize.generate_tokens(readline):
180 for t in tokenize.generate_tokens(readline):
181 toktypes.add(t[0])
181 toktypes.add(t[0])
182 except tokenize.TokenError:
182 except tokenize.TokenError:
183 pass
183 pass
184 return(tokenize.COMMENT in toktypes)
184 return(tokenize.COMMENT in toktypes)
185
185
186
186
187 def get_input_encoding():
187 def get_input_encoding():
188 """Return the default standard input encoding.
188 """Return the default standard input encoding.
189
189
190 If sys.stdin has no encoding, 'ascii' is returned."""
190 If sys.stdin has no encoding, 'ascii' is returned."""
191 # There are strange environments for which sys.stdin.encoding is None. We
191 # There are strange environments for which sys.stdin.encoding is None. We
192 # ensure that a valid encoding is returned.
192 # ensure that a valid encoding is returned.
193 encoding = getattr(sys.stdin, 'encoding', None)
193 encoding = getattr(sys.stdin, 'encoding', None)
194 if encoding is None:
194 if encoding is None:
195 encoding = 'ascii'
195 encoding = 'ascii'
196 return encoding
196 return encoding
197
197
198 #-----------------------------------------------------------------------------
198 #-----------------------------------------------------------------------------
199 # Classes and functions for normal Python syntax handling
199 # Classes and functions for normal Python syntax handling
200 #-----------------------------------------------------------------------------
200 #-----------------------------------------------------------------------------
201
201
202 class InputSplitter(object):
202 class InputSplitter(object):
203 """An object that can accumulate lines of Python source before execution.
203 """An object that can accumulate lines of Python source before execution.
204
204
205 This object is designed to be fed python source line-by-line, using
205 This object is designed to be fed python source line-by-line, using
206 :meth:`push`. It will return on each push whether the currently pushed
206 :meth:`push`. It will return on each push whether the currently pushed
207 code could be executed already. In addition, it provides a method called
207 code could be executed already. In addition, it provides a method called
208 :meth:`push_accepts_more` that can be used to query whether more input
208 :meth:`push_accepts_more` that can be used to query whether more input
209 can be pushed into a single interactive block.
209 can be pushed into a single interactive block.
210
210
211 This is a simple example of how an interactive terminal-based client can use
211 This is a simple example of how an interactive terminal-based client can use
212 this tool::
212 this tool::
213
213
214 isp = InputSplitter()
214 isp = InputSplitter()
215 while isp.push_accepts_more():
215 while isp.push_accepts_more():
216 indent = ' '*isp.indent_spaces
216 indent = ' '*isp.indent_spaces
217 prompt = '>>> ' + indent
217 prompt = '>>> ' + indent
218 line = indent + raw_input(prompt)
218 line = indent + raw_input(prompt)
219 isp.push(line)
219 isp.push(line)
220 print 'Input source was:\n', isp.source_reset(),
220 print 'Input source was:\n', isp.source_reset(),
221 """
221 """
222 # Number of spaces of indentation computed from input that has been pushed
222 # Number of spaces of indentation computed from input that has been pushed
223 # so far. This is the attributes callers should query to get the current
223 # so far. This is the attributes callers should query to get the current
224 # indentation level, in order to provide auto-indent facilities.
224 # indentation level, in order to provide auto-indent facilities.
225 indent_spaces = 0
225 indent_spaces = 0
226 # String, indicating the default input encoding. It is computed by default
226 # String, indicating the default input encoding. It is computed by default
227 # at initialization time via get_input_encoding(), but it can be reset by a
227 # at initialization time via get_input_encoding(), but it can be reset by a
228 # client with specific knowledge of the encoding.
228 # client with specific knowledge of the encoding.
229 encoding = ''
229 encoding = ''
230 # String where the current full source input is stored, properly encoded.
230 # String where the current full source input is stored, properly encoded.
231 # Reading this attribute is the normal way of querying the currently pushed
231 # Reading this attribute is the normal way of querying the currently pushed
232 # source code, that has been properly encoded.
232 # source code, that has been properly encoded.
233 source = ''
233 source = ''
234 # Code object corresponding to the current source. It is automatically
234 # Code object corresponding to the current source. It is automatically
235 # synced to the source, so it can be queried at any time to obtain the code
235 # synced to the source, so it can be queried at any time to obtain the code
236 # object; it will be None if the source doesn't compile to valid Python.
236 # object; it will be None if the source doesn't compile to valid Python.
237 code = None
237 code = None
238 # Input mode
238 # Input mode
239 input_mode = 'line'
239 input_mode = 'line'
240
240
241 # Private attributes
241 # Private attributes
242
242
243 # List with lines of input accumulated so far
243 # List with lines of input accumulated so far
244 _buffer = None
244 _buffer = None
245 # Command compiler
245 # Command compiler
246 _compile = None
246 _compile = None
247 # Mark when input has changed indentation all the way back to flush-left
247 # Mark when input has changed indentation all the way back to flush-left
248 _full_dedent = False
248 _full_dedent = False
249 # Boolean indicating whether the current block is complete
249 # Boolean indicating whether the current block is complete
250 _is_complete = None
250 _is_complete = None
251
251
252 def __init__(self, input_mode=None):
252 def __init__(self, input_mode=None):
253 """Create a new InputSplitter instance.
253 """Create a new InputSplitter instance.
254
254
255 Parameters
255 Parameters
256 ----------
256 ----------
257 input_mode : str
257 input_mode : str
258
258
259 One of ['line', 'cell']; default is 'line'.
259 One of ['line', 'cell']; default is 'line'.
260
260
261 The input_mode parameter controls how new inputs are used when fed via
261 The input_mode parameter controls how new inputs are used when fed via
262 the :meth:`push` method:
262 the :meth:`push` method:
263
263
264 - 'line': meant for line-oriented clients, inputs are appended one at a
264 - 'line': meant for line-oriented clients, inputs are appended one at a
265 time to the internal buffer and the whole buffer is compiled.
265 time to the internal buffer and the whole buffer is compiled.
266
266
267 - 'cell': meant for clients that can edit multi-line 'cells' of text at
267 - 'cell': meant for clients that can edit multi-line 'cells' of text at
268 a time. A cell can contain one or more blocks that can be compile in
268 a time. A cell can contain one or more blocks that can be compile in
269 'single' mode by Python. In this mode, each new input new input
269 'single' mode by Python. In this mode, each new input new input
270 completely replaces all prior inputs. Cell mode is thus equivalent
270 completely replaces all prior inputs. Cell mode is thus equivalent
271 to prepending a full reset() to every push() call.
271 to prepending a full reset() to every push() call.
272 """
272 """
273 self._buffer = []
273 self._buffer = []
274 self._compile = codeop.CommandCompiler()
274 self._compile = codeop.CommandCompiler()
275 self.encoding = get_input_encoding()
275 self.encoding = get_input_encoding()
276 self.input_mode = InputSplitter.input_mode if input_mode is None \
276 self.input_mode = InputSplitter.input_mode if input_mode is None \
277 else input_mode
277 else input_mode
278
278
279 def reset(self):
279 def reset(self):
280 """Reset the input buffer and associated state."""
280 """Reset the input buffer and associated state."""
281 self.indent_spaces = 0
281 self.indent_spaces = 0
282 self._buffer[:] = []
282 self._buffer[:] = []
283 self.source = ''
283 self.source = ''
284 self.code = None
284 self.code = None
285 self._is_complete = False
285 self._is_complete = False
286 self._full_dedent = False
286 self._full_dedent = False
287
287
288 def source_reset(self):
288 def source_reset(self):
289 """Return the input source and perform a full reset.
289 """Return the input source and perform a full reset.
290 """
290 """
291 out = self.source
291 out = self.source
292 self.reset()
292 self.reset()
293 return out
293 return out
294
294
295 def push(self, lines):
295 def push(self, lines):
296 """Push one or more lines of input.
296 """Push one or more lines of input.
297
297
298 This stores the given lines and returns a status code indicating
298 This stores the given lines and returns a status code indicating
299 whether the code forms a complete Python block or not.
299 whether the code forms a complete Python block or not.
300
300
301 Any exceptions generated in compilation are swallowed, but if an
301 Any exceptions generated in compilation are swallowed, but if an
302 exception was produced, the method returns True.
302 exception was produced, the method returns True.
303
303
304 Parameters
304 Parameters
305 ----------
305 ----------
306 lines : string
306 lines : string
307 One or more lines of Python input.
307 One or more lines of Python input.
308
308
309 Returns
309 Returns
310 -------
310 -------
311 is_complete : boolean
311 is_complete : boolean
312 True if the current input source (the result of the current input
312 True if the current input source (the result of the current input
313 plus prior inputs) forms a complete Python execution block. Note that
313 plus prior inputs) forms a complete Python execution block. Note that
314 this value is also stored as a private attribute (_is_complete), so it
314 this value is also stored as a private attribute (_is_complete), so it
315 can be queried at any time.
315 can be queried at any time.
316 """
316 """
317 if self.input_mode == 'cell':
317 if self.input_mode == 'cell':
318 self.reset()
318 self.reset()
319
319
320 self._store(lines)
320 self._store(lines)
321 source = self.source
321 source = self.source
322
322
323 # Before calling _compile(), reset the code object to None so that if an
323 # Before calling _compile(), reset the code object to None so that if an
324 # exception is raised in compilation, we don't mislead by having
324 # exception is raised in compilation, we don't mislead by having
325 # inconsistent code/source attributes.
325 # inconsistent code/source attributes.
326 self.code, self._is_complete = None, None
326 self.code, self._is_complete = None, None
327
327
328 # Honor termination lines properly
328 # Honor termination lines properly
329 if source.rstrip().endswith('\\'):
329 if source.rstrip().endswith('\\'):
330 return False
330 return False
331
331
332 self._update_indent(lines)
332 self._update_indent(lines)
333 try:
333 try:
334 self.code = self._compile(source, symbol="exec")
334 self.code = self._compile(source, symbol="exec")
335 # Invalid syntax can produce any of a number of different errors from
335 # Invalid syntax can produce any of a number of different errors from
336 # inside the compiler, so we have to catch them all. Syntax errors
336 # inside the compiler, so we have to catch them all. Syntax errors
337 # immediately produce a 'ready' block, so the invalid Python can be
337 # immediately produce a 'ready' block, so the invalid Python can be
338 # sent to the kernel for evaluation with possible ipython
338 # sent to the kernel for evaluation with possible ipython
339 # special-syntax conversion.
339 # special-syntax conversion.
340 except (SyntaxError, OverflowError, ValueError, TypeError,
340 except (SyntaxError, OverflowError, ValueError, TypeError,
341 MemoryError):
341 MemoryError):
342 self._is_complete = True
342 self._is_complete = True
343 else:
343 else:
344 # Compilation didn't produce any exceptions (though it may not have
344 # Compilation didn't produce any exceptions (though it may not have
345 # given a complete code object)
345 # given a complete code object)
346 self._is_complete = self.code is not None
346 self._is_complete = self.code is not None
347
347
348 return self._is_complete
348 return self._is_complete
349
349
350 def push_accepts_more(self):
350 def push_accepts_more(self):
351 """Return whether a block of interactive input can accept more input.
351 """Return whether a block of interactive input can accept more input.
352
352
353 This method is meant to be used by line-oriented frontends, who need to
353 This method is meant to be used by line-oriented frontends, who need to
354 guess whether a block is complete or not based solely on prior and
354 guess whether a block is complete or not based solely on prior and
355 current input lines. The InputSplitter considers it has a complete
355 current input lines. The InputSplitter considers it has a complete
356 interactive block and will not accept more input only when either a
356 interactive block and will not accept more input only when either a
357 SyntaxError is raised, or *all* of the following are true:
357 SyntaxError is raised, or *all* of the following are true:
358
358
359 1. The input compiles to a complete statement.
359 1. The input compiles to a complete statement.
360
360
361 2. The indentation level is flush-left (because if we are indented,
361 2. The indentation level is flush-left (because if we are indented,
362 like inside a function definition or for loop, we need to keep
362 like inside a function definition or for loop, we need to keep
363 reading new input).
363 reading new input).
364
364
365 3. There is one extra line consisting only of whitespace.
365 3. There is one extra line consisting only of whitespace.
366
366
367 Because of condition #3, this method should be used only by
367 Because of condition #3, this method should be used only by
368 *line-oriented* frontends, since it means that intermediate blank lines
368 *line-oriented* frontends, since it means that intermediate blank lines
369 are not allowed in function definitions (or any other indented block).
369 are not allowed in function definitions (or any other indented block).
370
370
371 If the current input produces a syntax error, this method immediately
371 If the current input produces a syntax error, this method immediately
372 returns False but does *not* raise the syntax error exception, as
372 returns False but does *not* raise the syntax error exception, as
373 typically clients will want to send invalid syntax to an execution
373 typically clients will want to send invalid syntax to an execution
374 backend which might convert the invalid syntax into valid Python via
374 backend which might convert the invalid syntax into valid Python via
375 one of the dynamic IPython mechanisms.
375 one of the dynamic IPython mechanisms.
376 """
376 """
377
377
378 # With incomplete input, unconditionally accept more
378 # With incomplete input, unconditionally accept more
379 if not self._is_complete:
379 if not self._is_complete:
380 return True
380 return True
381
381
382 # If we already have complete input and we're flush left, the answer
382 # If we already have complete input and we're flush left, the answer
383 # depends. In line mode, if there hasn't been any indentation,
383 # depends. In line mode, if there hasn't been any indentation,
384 # that's it. If we've come back from some indentation, we need
384 # that's it. If we've come back from some indentation, we need
385 # the blank final line to finish.
385 # the blank final line to finish.
386 # In cell mode, we need to check how many blocks the input so far
386 # In cell mode, we need to check how many blocks the input so far
387 # compiles into, because if there's already more than one full
387 # compiles into, because if there's already more than one full
388 # independent block of input, then the client has entered full
388 # independent block of input, then the client has entered full
389 # 'cell' mode and is feeding lines that each is complete. In this
389 # 'cell' mode and is feeding lines that each is complete. In this
390 # case we should then keep accepting. The Qt terminal-like console
390 # case we should then keep accepting. The Qt terminal-like console
391 # does precisely this, to provide the convenience of terminal-like
391 # does precisely this, to provide the convenience of terminal-like
392 # input of single expressions, but allowing the user (with a
392 # input of single expressions, but allowing the user (with a
393 # separate keystroke) to switch to 'cell' mode and type multiple
393 # separate keystroke) to switch to 'cell' mode and type multiple
394 # expressions in one shot.
394 # expressions in one shot.
395 if self.indent_spaces==0:
395 if self.indent_spaces==0:
396 if self.input_mode=='line':
396 if self.input_mode=='line':
397 if not self._full_dedent:
397 if not self._full_dedent:
398 return False
398 return False
399 else:
399 else:
400 try:
400 try:
401 code_ast = ast.parse(u''.join(self._buffer))
401 code_ast = ast.parse(u''.join(self._buffer))
402 except Exception:
402 except Exception:
403 return False
403 return False
404 else:
404 else:
405 if len(code_ast.body) == 1:
405 if len(code_ast.body) == 1:
406 return False
406 return False
407
407
408 # When input is complete, then termination is marked by an extra blank
408 # When input is complete, then termination is marked by an extra blank
409 # line at the end.
409 # line at the end.
410 last_line = self.source.splitlines()[-1]
410 last_line = self.source.splitlines()[-1]
411 return bool(last_line and not last_line.isspace())
411 return bool(last_line and not last_line.isspace())
412
412
413 #------------------------------------------------------------------------
413 #------------------------------------------------------------------------
414 # Private interface
414 # Private interface
415 #------------------------------------------------------------------------
415 #------------------------------------------------------------------------
416
416
417 def _find_indent(self, line):
417 def _find_indent(self, line):
418 """Compute the new indentation level for a single line.
418 """Compute the new indentation level for a single line.
419
419
420 Parameters
420 Parameters
421 ----------
421 ----------
422 line : str
422 line : str
423 A single new line of non-whitespace, non-comment Python input.
423 A single new line of non-whitespace, non-comment Python input.
424
424
425 Returns
425 Returns
426 -------
426 -------
427 indent_spaces : int
427 indent_spaces : int
428 New value for the indent level (it may be equal to self.indent_spaces
428 New value for the indent level (it may be equal to self.indent_spaces
429 if indentation doesn't change.
429 if indentation doesn't change.
430
430
431 full_dedent : boolean
431 full_dedent : boolean
432 Whether the new line causes a full flush-left dedent.
432 Whether the new line causes a full flush-left dedent.
433 """
433 """
434 indent_spaces = self.indent_spaces
434 indent_spaces = self.indent_spaces
435 full_dedent = self._full_dedent
435 full_dedent = self._full_dedent
436
436
437 inisp = num_ini_spaces(line)
437 inisp = num_ini_spaces(line)
438 if inisp < indent_spaces:
438 if inisp < indent_spaces:
439 indent_spaces = inisp
439 indent_spaces = inisp
440 if indent_spaces <= 0:
440 if indent_spaces <= 0:
441 #print 'Full dedent in text',self.source # dbg
441 #print 'Full dedent in text',self.source # dbg
442 full_dedent = True
442 full_dedent = True
443
443
444 if line.rstrip()[-1] == ':':
444 if line.rstrip()[-1] == ':':
445 indent_spaces += 4
445 indent_spaces += 4
446 elif dedent_re.match(line):
446 elif dedent_re.match(line):
447 indent_spaces -= 4
447 indent_spaces -= 4
448 if indent_spaces <= 0:
448 if indent_spaces <= 0:
449 full_dedent = True
449 full_dedent = True
450
450
451 # Safety
451 # Safety
452 if indent_spaces < 0:
452 if indent_spaces < 0:
453 indent_spaces = 0
453 indent_spaces = 0
454 #print 'safety' # dbg
454 #print 'safety' # dbg
455
455
456 return indent_spaces, full_dedent
456 return indent_spaces, full_dedent
457
457
458 def _update_indent(self, lines):
458 def _update_indent(self, lines):
459 for line in remove_comments(lines).splitlines():
459 for line in remove_comments(lines).splitlines():
460 if line and not line.isspace():
460 if line and not line.isspace():
461 self.indent_spaces, self._full_dedent = self._find_indent(line)
461 self.indent_spaces, self._full_dedent = self._find_indent(line)
462
462
463 def _store(self, lines, buffer=None, store='source'):
463 def _store(self, lines, buffer=None, store='source'):
464 """Store one or more lines of input.
464 """Store one or more lines of input.
465
465
466 If input lines are not newline-terminated, a newline is automatically
466 If input lines are not newline-terminated, a newline is automatically
467 appended."""
467 appended."""
468
468
469 if buffer is None:
469 if buffer is None:
470 buffer = self._buffer
470 buffer = self._buffer
471
471
472 if lines.endswith('\n'):
472 if lines.endswith('\n'):
473 buffer.append(lines)
473 buffer.append(lines)
474 else:
474 else:
475 buffer.append(lines+'\n')
475 buffer.append(lines+'\n')
476 setattr(self, store, self._set_source(buffer))
476 setattr(self, store, self._set_source(buffer))
477
477
478 def _set_source(self, buffer):
478 def _set_source(self, buffer):
479 return u''.join(buffer)
479 return u''.join(buffer)
480
480
481
481
482 #-----------------------------------------------------------------------------
482 #-----------------------------------------------------------------------------
483 # Functions and classes for IPython-specific syntactic support
483 # Functions and classes for IPython-specific syntactic support
484 #-----------------------------------------------------------------------------
484 #-----------------------------------------------------------------------------
485
485
486 # The escaped translators ALL receive a line where their own escape has been
486 # The escaped translators ALL receive a line where their own escape has been
487 # stripped. Only '?' is valid at the end of the line, all others can only be
487 # stripped. Only '?' is valid at the end of the line, all others can only be
488 # placed at the start.
488 # placed at the start.
489
489
490 # Transformations of the special syntaxes that don't rely on an explicit escape
490 # Transformations of the special syntaxes that don't rely on an explicit escape
491 # character but instead on patterns on the input line
491 # character but instead on patterns on the input line
492
492
493 # The core transformations are implemented as standalone functions that can be
493 # The core transformations are implemented as standalone functions that can be
494 # tested and validated in isolation. Each of these uses a regexp, we
494 # tested and validated in isolation. Each of these uses a regexp, we
495 # pre-compile these and keep them close to each function definition for clarity
495 # pre-compile these and keep them close to each function definition for clarity
496
496
497 _assign_system_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
497 _assign_system_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
498 r'\s*=\s*!\s*(?P<cmd>.*)')
498 r'\s*=\s*!\s*(?P<cmd>.*)')
499
499
500 def transform_assign_system(line):
500 def transform_assign_system(line):
501 """Handle the `files = !ls` syntax."""
501 """Handle the `files = !ls` syntax."""
502 m = _assign_system_re.match(line)
502 m = _assign_system_re.match(line)
503 if m is not None:
503 if m is not None:
504 cmd = m.group('cmd')
504 cmd = m.group('cmd')
505 lhs = m.group('lhs')
505 lhs = m.group('lhs')
506 expr = make_quoted_expr(cmd)
506 expr = make_quoted_expr(cmd)
507 new_line = '%s = get_ipython().getoutput(%s)' % (lhs, expr)
507 new_line = '%s = get_ipython().getoutput(%s)' % (lhs, expr)
508 return new_line
508 return new_line
509 return line
509 return line
510
510
511
511
512 _assign_magic_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
512 _assign_magic_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
513 r'\s*=\s*%\s*(?P<cmd>.*)')
513 r'\s*=\s*%\s*(?P<cmd>.*)')
514
514
515 def transform_assign_magic(line):
515 def transform_assign_magic(line):
516 """Handle the `a = %who` syntax."""
516 """Handle the `a = %who` syntax."""
517 m = _assign_magic_re.match(line)
517 m = _assign_magic_re.match(line)
518 if m is not None:
518 if m is not None:
519 cmd = m.group('cmd')
519 cmd = m.group('cmd')
520 lhs = m.group('lhs')
520 lhs = m.group('lhs')
521 expr = make_quoted_expr(cmd)
521 expr = make_quoted_expr(cmd)
522 new_line = '%s = get_ipython().magic(%s)' % (lhs, expr)
522 new_line = '%s = get_ipython().magic(%s)' % (lhs, expr)
523 return new_line
523 return new_line
524 return line
524 return line
525
525
526
526
527 _classic_prompt_re = re.compile(r'^([ \t]*>>> |^[ \t]*\.\.\. )')
527 _classic_prompt_re = re.compile(r'^([ \t]*>>> |^[ \t]*\.\.\. )')
528
528
529 def transform_classic_prompt(line):
529 def transform_classic_prompt(line):
530 """Handle inputs that start with '>>> ' syntax."""
530 """Handle inputs that start with '>>> ' syntax."""
531
531
532 if not line or line.isspace():
532 if not line or line.isspace():
533 return line
533 return line
534 m = _classic_prompt_re.match(line)
534 m = _classic_prompt_re.match(line)
535 if m:
535 if m:
536 return line[len(m.group(0)):]
536 return line[len(m.group(0)):]
537 else:
537 else:
538 return line
538 return line
539
539
540
540
541 _ipy_prompt_re = re.compile(r'^([ \t]*In \[\d+\]: |^[ \t]*\ \ \ \.\.\.+: )')
541 _ipy_prompt_re = re.compile(r'^([ \t]*In \[\d+\]: |^[ \t]*\ \ \ \.\.\.+: )')
542
542
543 def transform_ipy_prompt(line):
543 def transform_ipy_prompt(line):
544 """Handle inputs that start classic IPython prompt syntax."""
544 """Handle inputs that start classic IPython prompt syntax."""
545
545
546 if not line or line.isspace():
546 if not line or line.isspace():
547 return line
547 return line
548 #print 'LINE: %r' % line # dbg
548 #print 'LINE: %r' % line # dbg
549 m = _ipy_prompt_re.match(line)
549 m = _ipy_prompt_re.match(line)
550 if m:
550 if m:
551 #print 'MATCH! %r -> %r' % (line, line[len(m.group(0)):]) # dbg
551 #print 'MATCH! %r -> %r' % (line, line[len(m.group(0)):]) # dbg
552 return line[len(m.group(0)):]
552 return line[len(m.group(0)):]
553 else:
553 else:
554 return line
554 return line
555
555
556
556
557 def _make_help_call(target, esc, lspace, next_input=None):
557 def _make_help_call(target, esc, lspace, next_input=None):
558 """Prepares a pinfo(2)/psearch call from a target name and the escape
558 """Prepares a pinfo(2)/psearch call from a target name and the escape
559 (i.e. ? or ??)"""
559 (i.e. ? or ??)"""
560 method = 'pinfo2' if esc == '??' \
560 method = 'pinfo2' if esc == '??' \
561 else 'psearch' if '*' in target \
561 else 'psearch' if '*' in target \
562 else 'pinfo'
562 else 'pinfo'
563 arg = make_quoted_expr(" ".join([method, target]))
563 arg = make_quoted_expr(" ".join([method, target]))
564
564
565 if next_input:
565 if next_input:
566 tpl = '%sget_ipython().magic(%s, next_input=%s)'
566 tpl = '%sget_ipython().magic(%s, next_input=%s)'
567 return tpl % (lspace, arg, make_quoted_expr(next_input))
567 return tpl % (lspace, arg, make_quoted_expr(next_input))
568 else:
568 else:
569 return '%sget_ipython().magic(%s)' % (lspace, arg)
569 return '%sget_ipython().magic(%s)' % (lspace, arg)
570
570
571 _initial_space_re = re.compile(r'\s*')
571 _initial_space_re = re.compile(r'\s*')
572 _help_end_re = re.compile(r"""(%?
572 _help_end_re = re.compile(r"""(%?
573 [a-zA-Z_*][\w*]* # Variable name
573 [a-zA-Z_*][\w*]* # Variable name
574 (\.[a-zA-Z_*][\w*]*)* # .etc.etc
574 (\.[a-zA-Z_*][\w*]*)* # .etc.etc
575 )
575 )
576 (\?\??)$ # ? or ??""",
576 (\?\??)$ # ? or ??""",
577 re.VERBOSE)
577 re.VERBOSE)
578 def transform_help_end(line):
578 def transform_help_end(line):
579 """Translate lines with ?/?? at the end"""
579 """Translate lines with ?/?? at the end"""
580 m = _help_end_re.search(line)
580 m = _help_end_re.search(line)
581 if m is None or has_comment(line):
581 if m is None or has_comment(line):
582 return line
582 return line
583 target = m.group(1)
583 target = m.group(1)
584 esc = m.group(3)
584 esc = m.group(3)
585 lspace = _initial_space_re.match(line).group(0)
585 lspace = _initial_space_re.match(line).group(0)
586
586
587 # If we're mid-command, put it back on the next prompt for the user.
587 # If we're mid-command, put it back on the next prompt for the user.
588 next_input = line.rstrip('?') if line.strip() != m.group(0) else None
588 next_input = line.rstrip('?') if line.strip() != m.group(0) else None
589
589
590 return _make_help_call(target, esc, lspace, next_input)
590 return _make_help_call(target, esc, lspace, next_input)
591
591
592
592
593 class EscapedTransformer(object):
593 class EscapedTransformer(object):
594 """Class to transform lines that are explicitly escaped out."""
594 """Class to transform lines that are explicitly escaped out."""
595
595
596 def __init__(self):
596 def __init__(self):
597 tr = { ESC_SHELL : self._tr_system,
597 tr = { ESC_SHELL : self._tr_system,
598 ESC_SH_CAP : self._tr_system2,
598 ESC_SH_CAP : self._tr_system2,
599 ESC_HELP : self._tr_help,
599 ESC_HELP : self._tr_help,
600 ESC_HELP2 : self._tr_help,
600 ESC_HELP2 : self._tr_help,
601 ESC_MAGIC : self._tr_magic,
601 ESC_MAGIC : self._tr_magic,
602 ESC_QUOTE : self._tr_quote,
602 ESC_QUOTE : self._tr_quote,
603 ESC_QUOTE2 : self._tr_quote2,
603 ESC_QUOTE2 : self._tr_quote2,
604 ESC_PAREN : self._tr_paren }
604 ESC_PAREN : self._tr_paren }
605 self.tr = tr
605 self.tr = tr
606
606
607 # Support for syntax transformations that use explicit escapes typed by the
607 # Support for syntax transformations that use explicit escapes typed by the
608 # user at the beginning of a line
608 # user at the beginning of a line
609 @staticmethod
609 @staticmethod
610 def _tr_system(line_info):
610 def _tr_system(line_info):
611 "Translate lines escaped with: !"
611 "Translate lines escaped with: !"
612 cmd = line_info.line.lstrip().lstrip(ESC_SHELL)
612 cmd = line_info.line.lstrip().lstrip(ESC_SHELL)
613 return '%sget_ipython().system(%s)' % (line_info.pre,
613 return '%sget_ipython().system(%s)' % (line_info.pre,
614 make_quoted_expr(cmd))
614 make_quoted_expr(cmd))
615
615
616 @staticmethod
616 @staticmethod
617 def _tr_system2(line_info):
617 def _tr_system2(line_info):
618 "Translate lines escaped with: !!"
618 "Translate lines escaped with: !!"
619 cmd = line_info.line.lstrip()[2:]
619 cmd = line_info.line.lstrip()[2:]
620 return '%sget_ipython().getoutput(%s)' % (line_info.pre,
620 return '%sget_ipython().getoutput(%s)' % (line_info.pre,
621 make_quoted_expr(cmd))
621 make_quoted_expr(cmd))
622
622
623 @staticmethod
623 @staticmethod
624 def _tr_help(line_info):
624 def _tr_help(line_info):
625 "Translate lines escaped with: ?/??"
625 "Translate lines escaped with: ?/??"
626 # A naked help line should just fire the intro help screen
626 # A naked help line should just fire the intro help screen
627 if not line_info.line[1:]:
627 if not line_info.line[1:]:
628 return 'get_ipython().show_usage()'
628 return 'get_ipython().show_usage()'
629
629
630 return _make_help_call(line_info.ifun, line_info.esc, line_info.pre)
630 return _make_help_call(line_info.ifun, line_info.esc, line_info.pre)
631
631
632 @staticmethod
632 @staticmethod
633 def _tr_magic(line_info):
633 def _tr_magic(line_info):
634 "Translate lines escaped with: %"
634 "Translate lines escaped with: %"
635 tpl = '%sget_ipython().magic(%s)'
635 tpl = '%sget_ipython().magic(%s)'
636 cmd = make_quoted_expr(' '.join([line_info.ifun,
636 cmd = make_quoted_expr(' '.join([line_info.ifun,
637 line_info.the_rest]).strip())
637 line_info.the_rest]).strip())
638 return tpl % (line_info.pre, cmd)
638 return tpl % (line_info.pre, cmd)
639
639
640 @staticmethod
640 @staticmethod
641 def _tr_quote(line_info):
641 def _tr_quote(line_info):
642 "Translate lines escaped with: ,"
642 "Translate lines escaped with: ,"
643 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
643 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
644 '", "'.join(line_info.the_rest.split()) )
644 '", "'.join(line_info.the_rest.split()) )
645
645
646 @staticmethod
646 @staticmethod
647 def _tr_quote2(line_info):
647 def _tr_quote2(line_info):
648 "Translate lines escaped with: ;"
648 "Translate lines escaped with: ;"
649 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
649 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
650 line_info.the_rest)
650 line_info.the_rest)
651
651
652 @staticmethod
652 @staticmethod
653 def _tr_paren(line_info):
653 def _tr_paren(line_info):
654 "Translate lines escaped with: /"
654 "Translate lines escaped with: /"
655 return '%s%s(%s)' % (line_info.pre, line_info.ifun,
655 return '%s%s(%s)' % (line_info.pre, line_info.ifun,
656 ", ".join(line_info.the_rest.split()))
656 ", ".join(line_info.the_rest.split()))
657
657
658 def __call__(self, line):
658 def __call__(self, line):
659 """Class to transform lines that are explicitly escaped out.
659 """Class to transform lines that are explicitly escaped out.
660
660
661 This calls the above _tr_* static methods for the actual line
661 This calls the above _tr_* static methods for the actual line
662 translations."""
662 translations."""
663
663
664 # Empty lines just get returned unmodified
664 # Empty lines just get returned unmodified
665 if not line or line.isspace():
665 if not line or line.isspace():
666 return line
666 return line
667
667
668 # Get line endpoints, where the escapes can be
668 # Get line endpoints, where the escapes can be
669 line_info = LineInfo(line)
669 line_info = LineInfo(line)
670
670
671 if not line_info.esc in self.tr:
671 if not line_info.esc in self.tr:
672 # If we don't recognize the escape, don't modify the line
672 # If we don't recognize the escape, don't modify the line
673 return line
673 return line
674
674
675 return self.tr[line_info.esc](line_info)
675 return self.tr[line_info.esc](line_info)
676
676
677
677
678 # A function-looking object to be used by the rest of the code. The purpose of
678 # A function-looking object to be used by the rest of the code. The purpose of
679 # the class in this case is to organize related functionality, more than to
679 # the class in this case is to organize related functionality, more than to
680 # manage state.
680 # manage state.
681 transform_escaped = EscapedTransformer()
681 transform_escaped = EscapedTransformer()
682
682
683
683
684 class IPythonInputSplitter(InputSplitter):
684 class IPythonInputSplitter(InputSplitter):
685 """An input splitter that recognizes all of IPython's special syntax."""
685 """An input splitter that recognizes all of IPython's special syntax."""
686
686
687 # String with raw, untransformed input.
687 # String with raw, untransformed input.
688 source_raw = ''
688 source_raw = ''
689
689
690 # Private attributes
690 # Private attributes
691
691
692 # List with lines of raw input accumulated so far.
692 # List with lines of raw input accumulated so far.
693 _buffer_raw = None
693 _buffer_raw = None
694
694
695 def __init__(self, input_mode=None):
695 def __init__(self, input_mode=None):
696 InputSplitter.__init__(self, input_mode)
696 InputSplitter.__init__(self, input_mode)
697 self._buffer_raw = []
697 self._buffer_raw = []
698
698
699 def reset(self):
699 def reset(self):
700 """Reset the input buffer and associated state."""
700 """Reset the input buffer and associated state."""
701 InputSplitter.reset(self)
701 InputSplitter.reset(self)
702 self._buffer_raw[:] = []
702 self._buffer_raw[:] = []
703 self.source_raw = ''
703 self.source_raw = ''
704
704
705 def source_raw_reset(self):
705 def source_raw_reset(self):
706 """Return input and raw source and perform a full reset.
706 """Return input and raw source and perform a full reset.
707 """
707 """
708 out = self.source
708 out = self.source
709 out_r = self.source_raw
709 out_r = self.source_raw
710 self.reset()
710 self.reset()
711 return out, out_r
711 return out, out_r
712
712
713 def push(self, lines):
713 def push(self, lines):
714 """Push one or more lines of IPython input.
714 """Push one or more lines of IPython input.
715 """
715 """
716 if not lines:
716 if not lines:
717 return super(IPythonInputSplitter, self).push(lines)
717 return super(IPythonInputSplitter, self).push(lines)
718
718
719 # We must ensure all input is pure unicode
719 # We must ensure all input is pure unicode
720 lines = cast_unicode(lines, self.encoding)
720 lines = cast_unicode(lines, self.encoding)
721
721
722 lines_list = lines.splitlines()
722 lines_list = lines.splitlines()
723
723
724 transforms = [transform_ipy_prompt, transform_classic_prompt,
724 transforms = [transform_ipy_prompt, transform_classic_prompt,
725 transform_help_end, transform_escaped,
725 transform_help_end, transform_escaped,
726 transform_assign_system, transform_assign_magic]
726 transform_assign_system, transform_assign_magic]
727
727
728 # Transform logic
728 # Transform logic
729 #
729 #
730 # We only apply the line transformers to the input if we have either no
730 # We only apply the line transformers to the input if we have either no
731 # input yet, or complete input, or if the last line of the buffer ends
731 # input yet, or complete input, or if the last line of the buffer ends
732 # with ':' (opening an indented block). This prevents the accidental
732 # with ':' (opening an indented block). This prevents the accidental
733 # transformation of escapes inside multiline expressions like
733 # transformation of escapes inside multiline expressions like
734 # triple-quoted strings or parenthesized expressions.
734 # triple-quoted strings or parenthesized expressions.
735 #
735 #
736 # The last heuristic, while ugly, ensures that the first line of an
736 # The last heuristic, while ugly, ensures that the first line of an
737 # indented block is correctly transformed.
737 # indented block is correctly transformed.
738 #
738 #
739 # FIXME: try to find a cleaner approach for this last bit.
739 # FIXME: try to find a cleaner approach for this last bit.
740
740
741 # If we were in 'block' mode, since we're going to pump the parent
741 # If we were in 'block' mode, since we're going to pump the parent
742 # class by hand line by line, we need to temporarily switch out to
742 # class by hand line by line, we need to temporarily switch out to
743 # 'line' mode, do a single manual reset and then feed the lines one
743 # 'line' mode, do a single manual reset and then feed the lines one
744 # by one. Note that this only matters if the input has more than one
744 # by one. Note that this only matters if the input has more than one
745 # line.
745 # line.
746 changed_input_mode = False
746 changed_input_mode = False
747
747
748 if self.input_mode == 'cell':
748 if self.input_mode == 'cell':
749 self.reset()
749 self.reset()
750 changed_input_mode = True
750 changed_input_mode = True
751 saved_input_mode = 'cell'
751 saved_input_mode = 'cell'
752 self.input_mode = 'line'
752 self.input_mode = 'line'
753
753
754 # Store raw source before applying any transformations to it. Note
754 # Store raw source before applying any transformations to it. Note
755 # that this must be done *after* the reset() call that would otherwise
755 # that this must be done *after* the reset() call that would otherwise
756 # flush the buffer.
756 # flush the buffer.
757 self._store(lines, self._buffer_raw, 'source_raw')
757 self._store(lines, self._buffer_raw, 'source_raw')
758
758
759 try:
759 try:
760 push = super(IPythonInputSplitter, self).push
760 push = super(IPythonInputSplitter, self).push
761 buf = self._buffer
761 for line in lines_list:
762 for line in lines_list:
762 if self._is_complete or not self._buffer or \
763 if self._is_complete or not buf or \
763 (self._buffer and self._buffer[-1].rstrip().endswith(':')):
764 (buf and (buf[-1].rstrip().endswith(':') or
765 buf[-1].rstrip().endswith(',')) ):
764 for f in transforms:
766 for f in transforms:
765 line = f(line)
767 line = f(line)
766
768
767 out = push(line)
769 out = push(line)
768 finally:
770 finally:
769 if changed_input_mode:
771 if changed_input_mode:
770 self.input_mode = saved_input_mode
772 self.input_mode = saved_input_mode
771 return out
773 return out
@@ -1,698 +1,704 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 The IPython Development Team
10 # Copyright (C) 2010 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 [('a =! ls', 'a = get_ipython().getoutput({u}"ls")'),
408 [('a =! ls', 'a = get_ipython().getoutput({u}"ls")'),
409 ('b = !ls', 'b = get_ipython().getoutput({u}"ls")'),
409 ('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 [('a =% who', 'a = get_ipython().magic({u}"who")'),
416 [('a =% who', 'a = get_ipython().magic({u}"who")'),
417 ('b = %who', 'b = get_ipython().magic({u}"who")'),
417 ('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 [ ('!ls', 'get_ipython().system({u}"ls")'),
445 [ ('!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 ('!!ls', 'get_ipython().getoutput({u}"ls")'),
448 ('!!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 [ ('?', 'get_ipython().show_usage()'),
454 [ ('?', 'get_ipython().show_usage()'),
455 ('?x1', 'get_ipython().magic({u}"pinfo x1")'),
455 ('?x1', 'get_ipython().magic({u}"pinfo x1")'),
456 ('??x2', 'get_ipython().magic({u}"pinfo2 x2")'),
456 ('??x2', 'get_ipython().magic({u}"pinfo2 x2")'),
457 ('?a.*s', 'get_ipython().magic({u}"psearch a.*s")'),
457 ('?a.*s', 'get_ipython().magic({u}"psearch a.*s")'),
458 ('?%hist', 'get_ipython().magic({u}"pinfo %hist")'),
458 ('?%hist', 'get_ipython().magic({u}"pinfo %hist")'),
459 ('?abc = qwe', 'get_ipython().magic({u}"pinfo abc")'),
459 ('?abc = qwe', 'get_ipython().magic({u}"pinfo abc")'),
460 ]],
460 ]],
461
461
462 end_help =
462 end_help =
463 [(i,py3compat.u_format(o)) for i,o in \
463 [(i,py3compat.u_format(o)) for i,o in \
464 [ ('x3?', 'get_ipython().magic({u}"pinfo x3")'),
464 [ ('x3?', 'get_ipython().magic({u}"pinfo x3")'),
465 ('x4??', 'get_ipython().magic({u}"pinfo2 x4")'),
465 ('x4??', 'get_ipython().magic({u}"pinfo2 x4")'),
466 ('%hist?', 'get_ipython().magic({u}"pinfo %hist")'),
466 ('%hist?', 'get_ipython().magic({u}"pinfo %hist")'),
467 ('f*?', 'get_ipython().magic({u}"psearch f*")'),
467 ('f*?', 'get_ipython().magic({u}"psearch f*")'),
468 ('ax.*aspe*?', 'get_ipython().magic({u}"psearch ax.*aspe*")'),
468 ('ax.*aspe*?', 'get_ipython().magic({u}"psearch ax.*aspe*")'),
469 ('a = abc?', 'get_ipython().magic({u}"pinfo abc", next_input={u}"a = abc")'),
469 ('a = abc?', 'get_ipython().magic({u}"pinfo abc", next_input={u}"a = abc")'),
470 ('a = abc.qe??', 'get_ipython().magic({u}"pinfo2 abc.qe", next_input={u}"a = abc.qe")'),
470 ('a = abc.qe??', 'get_ipython().magic({u}"pinfo2 abc.qe", next_input={u}"a = abc.qe")'),
471 ('a = *.items?', 'get_ipython().magic({u}"psearch *.items", next_input={u}"a = *.items")'),
471 ('a = *.items?', 'get_ipython().magic({u}"psearch *.items", next_input={u}"a = *.items")'),
472 ('plot(a?', 'get_ipython().magic({u}"pinfo a", next_input={u}"plot(a")'),
472 ('plot(a?', 'get_ipython().magic({u}"pinfo a", next_input={u}"plot(a")'),
473 ('a*2 #comment?', 'a*2 #comment?'),
473 ('a*2 #comment?', 'a*2 #comment?'),
474 ]],
474 ]],
475
475
476 # Explicit magic calls
476 # Explicit magic calls
477 escaped_magic =
477 escaped_magic =
478 [(i,py3compat.u_format(o)) for i,o in \
478 [(i,py3compat.u_format(o)) for i,o in \
479 [ ('%cd', 'get_ipython().magic({u}"cd")'),
479 [ ('%cd', 'get_ipython().magic({u}"cd")'),
480 ('%cd /home', 'get_ipython().magic({u}"cd /home")'),
480 ('%cd /home', 'get_ipython().magic({u}"cd /home")'),
481 (' %magic', ' get_ipython().magic({u}"magic")'),
481 (' %magic', ' get_ipython().magic({u}"magic")'),
482 ]],
482 ]],
483
483
484 # Quoting with separate arguments
484 # Quoting with separate arguments
485 escaped_quote =
485 escaped_quote =
486 [ (',f', 'f("")'),
486 [ (',f', 'f("")'),
487 (',f x', 'f("x")'),
487 (',f x', 'f("x")'),
488 (' ,f y', ' f("y")'),
488 (' ,f y', ' f("y")'),
489 (',f a b', 'f("a", "b")'),
489 (',f a b', 'f("a", "b")'),
490 ],
490 ],
491
491
492 # Quoting with single argument
492 # Quoting with single argument
493 escaped_quote2 =
493 escaped_quote2 =
494 [ (';f', 'f("")'),
494 [ (';f', 'f("")'),
495 (';f x', 'f("x")'),
495 (';f x', 'f("x")'),
496 (' ;f y', ' f("y")'),
496 (' ;f y', ' f("y")'),
497 (';f a b', 'f("a b")'),
497 (';f a b', 'f("a b")'),
498 ],
498 ],
499
499
500 # Simply apply parens
500 # Simply apply parens
501 escaped_paren =
501 escaped_paren =
502 [ ('/f', 'f()'),
502 [ ('/f', 'f()'),
503 ('/f x', 'f(x)'),
503 ('/f x', 'f(x)'),
504 (' /f y', ' f(y)'),
504 (' /f y', ' f(y)'),
505 ('/f a b', 'f(a, b)'),
505 ('/f a b', 'f(a, b)'),
506 ],
506 ],
507
507
508 # Check that we transform prompts before other transforms
508 # Check that we transform prompts before other transforms
509 mixed =
509 mixed =
510 [(i,py3compat.u_format(o)) for i,o in \
510 [(i,py3compat.u_format(o)) for i,o in \
511 [ ('In [1]: %lsmagic', 'get_ipython().magic({u}"lsmagic")'),
511 [ ('In [1]: %lsmagic', 'get_ipython().magic({u}"lsmagic")'),
512 ('>>> %lsmagic', 'get_ipython().magic({u}"lsmagic")'),
512 ('>>> %lsmagic', 'get_ipython().magic({u}"lsmagic")'),
513 ('In [2]: !ls', 'get_ipython().system({u}"ls")'),
513 ('In [2]: !ls', 'get_ipython().system({u}"ls")'),
514 ('In [3]: abs?', 'get_ipython().magic({u}"pinfo abs")'),
514 ('In [3]: abs?', 'get_ipython().magic({u}"pinfo abs")'),
515 ('In [4]: b = %who', 'b = get_ipython().magic({u}"who")'),
515 ('In [4]: b = %who', 'b = get_ipython().magic({u}"who")'),
516 ]],
516 ]],
517 )
517 )
518
518
519 # multiline syntax examples. Each of these should be a list of lists, with
519 # multiline syntax examples. Each of these should be a list of lists, with
520 # each entry itself having pairs of raw/transformed input. The union (with
520 # each entry itself having pairs of raw/transformed input. The union (with
521 # '\n'.join() of the transformed inputs is what the splitter should produce
521 # '\n'.join() of the transformed inputs is what the splitter should produce
522 # when fed the raw lines one at a time via push.
522 # when fed the raw lines one at a time via push.
523 syntax_ml = \
523 syntax_ml = \
524 dict(classic_prompt =
524 dict(classic_prompt =
525 [ [('>>> for i in range(10):','for i in range(10):'),
525 [ [('>>> for i in range(10):','for i in range(10):'),
526 ('... print i',' print i'),
526 ('... print i',' print i'),
527 ('... ', ''),
527 ('... ', ''),
528 ],
528 ],
529 ],
529 ],
530
530
531 ipy_prompt =
531 ipy_prompt =
532 [ [('In [24]: for i in range(10):','for i in range(10):'),
532 [ [('In [24]: for i in range(10):','for i in range(10):'),
533 (' ....: print i',' print i'),
533 (' ....: print i',' print i'),
534 (' ....: ', ''),
534 (' ....: ', ''),
535 ],
535 ],
536 ],
536 ],
537
538 multiline_datastructure =
539 [ [('>>> a = [1,','a = [1,'),
540 ('... 2]','2]'),
541 ],
542 ],
537 )
543 )
538
544
539
545
540 def test_assign_system():
546 def test_assign_system():
541 tt.check_pairs(isp.transform_assign_system, syntax['assign_system'])
547 tt.check_pairs(isp.transform_assign_system, syntax['assign_system'])
542
548
543
549
544 def test_assign_magic():
550 def test_assign_magic():
545 tt.check_pairs(isp.transform_assign_magic, syntax['assign_magic'])
551 tt.check_pairs(isp.transform_assign_magic, syntax['assign_magic'])
546
552
547
553
548 def test_classic_prompt():
554 def test_classic_prompt():
549 transform_checker(syntax['classic_prompt'], isp.transform_classic_prompt)
555 transform_checker(syntax['classic_prompt'], isp.transform_classic_prompt)
550 for example in syntax_ml['classic_prompt']:
556 for example in syntax_ml['classic_prompt']:
551 transform_checker(example, isp.transform_classic_prompt)
557 transform_checker(example, isp.transform_classic_prompt)
552
558
553
559
554 def test_ipy_prompt():
560 def test_ipy_prompt():
555 transform_checker(syntax['ipy_prompt'], isp.transform_ipy_prompt)
561 transform_checker(syntax['ipy_prompt'], isp.transform_ipy_prompt)
556 for example in syntax_ml['ipy_prompt']:
562 for example in syntax_ml['ipy_prompt']:
557 transform_checker(example, isp.transform_ipy_prompt)
563 transform_checker(example, isp.transform_ipy_prompt)
558
564
559 def test_end_help():
565 def test_end_help():
560 tt.check_pairs(isp.transform_help_end, syntax['end_help'])
566 tt.check_pairs(isp.transform_help_end, syntax['end_help'])
561
567
562 def test_escaped_noesc():
568 def test_escaped_noesc():
563 tt.check_pairs(isp.transform_escaped, syntax['escaped_noesc'])
569 tt.check_pairs(isp.transform_escaped, syntax['escaped_noesc'])
564
570
565
571
566 def test_escaped_shell():
572 def test_escaped_shell():
567 tt.check_pairs(isp.transform_escaped, syntax['escaped_shell'])
573 tt.check_pairs(isp.transform_escaped, syntax['escaped_shell'])
568
574
569
575
570 def test_escaped_help():
576 def test_escaped_help():
571 tt.check_pairs(isp.transform_escaped, syntax['escaped_help'])
577 tt.check_pairs(isp.transform_escaped, syntax['escaped_help'])
572
578
573
579
574 def test_escaped_magic():
580 def test_escaped_magic():
575 tt.check_pairs(isp.transform_escaped, syntax['escaped_magic'])
581 tt.check_pairs(isp.transform_escaped, syntax['escaped_magic'])
576
582
577
583
578 def test_escaped_quote():
584 def test_escaped_quote():
579 tt.check_pairs(isp.transform_escaped, syntax['escaped_quote'])
585 tt.check_pairs(isp.transform_escaped, syntax['escaped_quote'])
580
586
581
587
582 def test_escaped_quote2():
588 def test_escaped_quote2():
583 tt.check_pairs(isp.transform_escaped, syntax['escaped_quote2'])
589 tt.check_pairs(isp.transform_escaped, syntax['escaped_quote2'])
584
590
585
591
586 def test_escaped_paren():
592 def test_escaped_paren():
587 tt.check_pairs(isp.transform_escaped, syntax['escaped_paren'])
593 tt.check_pairs(isp.transform_escaped, syntax['escaped_paren'])
588
594
589
595
590 class IPythonInputTestCase(InputSplitterTestCase):
596 class IPythonInputTestCase(InputSplitterTestCase):
591 """By just creating a new class whose .isp is a different instance, we
597 """By just creating a new class whose .isp is a different instance, we
592 re-run the same test battery on the new input splitter.
598 re-run the same test battery on the new input splitter.
593
599
594 In addition, this runs the tests over the syntax and syntax_ml dicts that
600 In addition, this runs the tests over the syntax and syntax_ml dicts that
595 were tested by individual functions, as part of the OO interface.
601 were tested by individual functions, as part of the OO interface.
596
602
597 It also makes some checks on the raw buffer storage.
603 It also makes some checks on the raw buffer storage.
598 """
604 """
599
605
600 def setUp(self):
606 def setUp(self):
601 self.isp = isp.IPythonInputSplitter(input_mode='line')
607 self.isp = isp.IPythonInputSplitter(input_mode='line')
602
608
603 def test_syntax(self):
609 def test_syntax(self):
604 """Call all single-line syntax tests from the main object"""
610 """Call all single-line syntax tests from the main object"""
605 isp = self.isp
611 isp = self.isp
606 for example in syntax.itervalues():
612 for example in syntax.itervalues():
607 for raw, out_t in example:
613 for raw, out_t in example:
608 if raw.startswith(' '):
614 if raw.startswith(' '):
609 continue
615 continue
610
616
611 isp.push(raw)
617 isp.push(raw)
612 out, out_raw = isp.source_raw_reset()
618 out, out_raw = isp.source_raw_reset()
613 self.assertEqual(out.rstrip(), out_t,
619 self.assertEqual(out.rstrip(), out_t,
614 tt.pair_fail_msg.format("inputsplitter",raw, out_t, out))
620 tt.pair_fail_msg.format("inputsplitter",raw, out_t, out))
615 self.assertEqual(out_raw.rstrip(), raw.rstrip())
621 self.assertEqual(out_raw.rstrip(), raw.rstrip())
616
622
617 def test_syntax_multiline(self):
623 def test_syntax_multiline(self):
618 isp = self.isp
624 isp = self.isp
619 for example in syntax_ml.itervalues():
625 for example in syntax_ml.itervalues():
620 out_t_parts = []
626 out_t_parts = []
621 raw_parts = []
627 raw_parts = []
622 for line_pairs in example:
628 for line_pairs in example:
623 for lraw, out_t_part in line_pairs:
629 for lraw, out_t_part in line_pairs:
624 isp.push(lraw)
630 isp.push(lraw)
625 out_t_parts.append(out_t_part)
631 out_t_parts.append(out_t_part)
626 raw_parts.append(lraw)
632 raw_parts.append(lraw)
627
633
628 out, out_raw = isp.source_raw_reset()
634 out, out_raw = isp.source_raw_reset()
629 out_t = '\n'.join(out_t_parts).rstrip()
635 out_t = '\n'.join(out_t_parts).rstrip()
630 raw = '\n'.join(raw_parts).rstrip()
636 raw = '\n'.join(raw_parts).rstrip()
631 self.assertEqual(out.rstrip(), out_t)
637 self.assertEqual(out.rstrip(), out_t)
632 self.assertEqual(out_raw.rstrip(), raw)
638 self.assertEqual(out_raw.rstrip(), raw)
633
639
634
640
635 class BlockIPythonInputTestCase(IPythonInputTestCase):
641 class BlockIPythonInputTestCase(IPythonInputTestCase):
636
642
637 # Deactivate tests that don't make sense for the block mode
643 # Deactivate tests that don't make sense for the block mode
638 test_push3 = test_split = lambda s: None
644 test_push3 = test_split = lambda s: None
639
645
640 def setUp(self):
646 def setUp(self):
641 self.isp = isp.IPythonInputSplitter(input_mode='cell')
647 self.isp = isp.IPythonInputSplitter(input_mode='cell')
642
648
643 def test_syntax_multiline(self):
649 def test_syntax_multiline(self):
644 isp = self.isp
650 isp = self.isp
645 for example in syntax_ml.itervalues():
651 for example in syntax_ml.itervalues():
646 raw_parts = []
652 raw_parts = []
647 out_t_parts = []
653 out_t_parts = []
648 for line_pairs in example:
654 for line_pairs in example:
649 for raw, out_t_part in line_pairs:
655 for raw, out_t_part in line_pairs:
650 raw_parts.append(raw)
656 raw_parts.append(raw)
651 out_t_parts.append(out_t_part)
657 out_t_parts.append(out_t_part)
652
658
653 raw = '\n'.join(raw_parts)
659 raw = '\n'.join(raw_parts)
654 out_t = '\n'.join(out_t_parts)
660 out_t = '\n'.join(out_t_parts)
655
661
656 isp.push(raw)
662 isp.push(raw)
657 out, out_raw = isp.source_raw_reset()
663 out, out_raw = isp.source_raw_reset()
658 # Match ignoring trailing whitespace
664 # Match ignoring trailing whitespace
659 self.assertEqual(out.rstrip(), out_t.rstrip())
665 self.assertEqual(out.rstrip(), out_t.rstrip())
660 self.assertEqual(out_raw.rstrip(), raw.rstrip())
666 self.assertEqual(out_raw.rstrip(), raw.rstrip())
661
667
662
668
663 #-----------------------------------------------------------------------------
669 #-----------------------------------------------------------------------------
664 # Main - use as a script, mostly for developer experiments
670 # Main - use as a script, mostly for developer experiments
665 #-----------------------------------------------------------------------------
671 #-----------------------------------------------------------------------------
666
672
667 if __name__ == '__main__':
673 if __name__ == '__main__':
668 # A simple demo for interactive experimentation. This code will not get
674 # A simple demo for interactive experimentation. This code will not get
669 # picked up by any test suite.
675 # picked up by any test suite.
670 from IPython.core.inputsplitter import InputSplitter, IPythonInputSplitter
676 from IPython.core.inputsplitter import InputSplitter, IPythonInputSplitter
671
677
672 # configure here the syntax to use, prompt and whether to autoindent
678 # configure here the syntax to use, prompt and whether to autoindent
673 #isp, start_prompt = InputSplitter(), '>>> '
679 #isp, start_prompt = InputSplitter(), '>>> '
674 isp, start_prompt = IPythonInputSplitter(), 'In> '
680 isp, start_prompt = IPythonInputSplitter(), 'In> '
675
681
676 autoindent = True
682 autoindent = True
677 #autoindent = False
683 #autoindent = False
678
684
679 try:
685 try:
680 while True:
686 while True:
681 prompt = start_prompt
687 prompt = start_prompt
682 while isp.push_accepts_more():
688 while isp.push_accepts_more():
683 indent = ' '*isp.indent_spaces
689 indent = ' '*isp.indent_spaces
684 if autoindent:
690 if autoindent:
685 line = indent + raw_input(prompt+indent)
691 line = indent + raw_input(prompt+indent)
686 else:
692 else:
687 line = raw_input(prompt)
693 line = raw_input(prompt)
688 isp.push(line)
694 isp.push(line)
689 prompt = '... '
695 prompt = '... '
690
696
691 # Here we just return input so we can use it in a test suite, but a
697 # Here we just return input so we can use it in a test suite, but a
692 # real interpreter would instead send it for execution somewhere.
698 # real interpreter would instead send it for execution somewhere.
693 #src = isp.source; raise EOFError # dbg
699 #src = isp.source; raise EOFError # dbg
694 src, raw = isp.source_raw_reset()
700 src, raw = isp.source_raw_reset()
695 print 'Input source was:\n', src
701 print 'Input source was:\n', src
696 print 'Raw source was:\n', raw
702 print 'Raw source was:\n', raw
697 except EOFError:
703 except EOFError:
698 print 'Bye'
704 print 'Bye'
General Comments 0
You need to be logged in to leave comments. Login now