##// END OF EJS Templates
Further fixes and tweaks for inputsplitter.
Thomas Kluyver -
Show More
@@ -1,1007 +1,1005 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
73
74 # IPython modules
74 # IPython modules
75 from IPython.utils.text import make_quoted_expr
75 from IPython.utils.text import make_quoted_expr
76
76
77 #-----------------------------------------------------------------------------
77 #-----------------------------------------------------------------------------
78 # Globals
78 # Globals
79 #-----------------------------------------------------------------------------
79 #-----------------------------------------------------------------------------
80
80
81 # The escape sequences that define the syntax transformations IPython will
81 # The escape sequences that define the syntax transformations IPython will
82 # apply to user input. These can NOT be just changed here: many regular
82 # apply to user input. These can NOT be just changed here: many regular
83 # expressions and other parts of the code may use their hardcoded values, and
83 # expressions and other parts of the code may use their hardcoded values, and
84 # for all intents and purposes they constitute the 'IPython syntax', so they
84 # for all intents and purposes they constitute the 'IPython syntax', so they
85 # should be considered fixed.
85 # should be considered fixed.
86
86
87 ESC_SHELL = '!' # Send line to underlying system shell
87 ESC_SHELL = '!' # Send line to underlying system shell
88 ESC_SH_CAP = '!!' # Send line to system shell and capture output
88 ESC_SH_CAP = '!!' # Send line to system shell and capture output
89 ESC_HELP = '?' # Find information about object
89 ESC_HELP = '?' # Find information about object
90 ESC_HELP2 = '??' # Find extra-detailed information about object
90 ESC_HELP2 = '??' # Find extra-detailed information about object
91 ESC_MAGIC = '%' # Call magic function
91 ESC_MAGIC = '%' # Call magic function
92 ESC_QUOTE = ',' # Split args on whitespace, quote each as string and call
92 ESC_QUOTE = ',' # Split args on whitespace, quote each as string and call
93 ESC_QUOTE2 = ';' # Quote all args as a single string, call
93 ESC_QUOTE2 = ';' # Quote all args as a single string, call
94 ESC_PAREN = '/' # Call first argument with rest of line as arguments
94 ESC_PAREN = '/' # Call first argument with rest of line as arguments
95
95
96 #-----------------------------------------------------------------------------
96 #-----------------------------------------------------------------------------
97 # Utilities
97 # Utilities
98 #-----------------------------------------------------------------------------
98 #-----------------------------------------------------------------------------
99
99
100 # FIXME: These are general-purpose utilities that later can be moved to the
100 # FIXME: These are general-purpose utilities that later can be moved to the
101 # general ward. Kept here for now because we're being very strict about test
101 # general ward. Kept here for now because we're being very strict about test
102 # coverage with this code, and this lets us ensure that we keep 100% coverage
102 # coverage with this code, and this lets us ensure that we keep 100% coverage
103 # while developing.
103 # while developing.
104
104
105 # compiled regexps for autoindent management
105 # compiled regexps for autoindent management
106 dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass')
106 dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass')
107 ini_spaces_re = re.compile(r'^([ \t\r\f\v]+)')
107 ini_spaces_re = re.compile(r'^([ \t\r\f\v]+)')
108
108
109 # regexp to match pure comment lines so we don't accidentally insert 'if 1:'
109 # regexp to match pure comment lines so we don't accidentally insert 'if 1:'
110 # before pure comments
110 # before pure comments
111 comment_line_re = re.compile('^\s*\#')
111 comment_line_re = re.compile('^\s*\#')
112
112
113
113
114 def num_ini_spaces(s):
114 def num_ini_spaces(s):
115 """Return the number of initial spaces in a string.
115 """Return the number of initial spaces in a string.
116
116
117 Note that tabs are counted as a single space. For now, we do *not* support
117 Note that tabs are counted as a single space. For now, we do *not* support
118 mixing of tabs and spaces in the user's input.
118 mixing of tabs and spaces in the user's input.
119
119
120 Parameters
120 Parameters
121 ----------
121 ----------
122 s : string
122 s : string
123
123
124 Returns
124 Returns
125 -------
125 -------
126 n : int
126 n : int
127 """
127 """
128
128
129 ini_spaces = ini_spaces_re.match(s)
129 ini_spaces = ini_spaces_re.match(s)
130 if ini_spaces:
130 if ini_spaces:
131 return ini_spaces.end()
131 return ini_spaces.end()
132 else:
132 else:
133 return 0
133 return 0
134
134
135
135
136 def remove_comments(src):
136 def remove_comments(src):
137 """Remove all comments from input source.
137 """Remove all comments from input source.
138
138
139 Note: comments are NOT recognized inside of strings!
139 Note: comments are NOT recognized inside of strings!
140
140
141 Parameters
141 Parameters
142 ----------
142 ----------
143 src : string
143 src : string
144 A single or multiline input string.
144 A single or multiline input string.
145
145
146 Returns
146 Returns
147 -------
147 -------
148 String with all Python comments removed.
148 String with all Python comments removed.
149 """
149 """
150
150
151 return re.sub('#.*', '', src)
151 return re.sub('#.*', '', src)
152
152
153
153
154 def get_input_encoding():
154 def get_input_encoding():
155 """Return the default standard input encoding.
155 """Return the default standard input encoding.
156
156
157 If sys.stdin has no encoding, 'ascii' is returned."""
157 If sys.stdin has no encoding, 'ascii' is returned."""
158 # There are strange environments for which sys.stdin.encoding is None. We
158 # There are strange environments for which sys.stdin.encoding is None. We
159 # ensure that a valid encoding is returned.
159 # ensure that a valid encoding is returned.
160 encoding = getattr(sys.stdin, 'encoding', None)
160 encoding = getattr(sys.stdin, 'encoding', None)
161 if encoding is None:
161 if encoding is None:
162 encoding = 'ascii'
162 encoding = 'ascii'
163 return encoding
163 return encoding
164
164
165 #-----------------------------------------------------------------------------
165 #-----------------------------------------------------------------------------
166 # Classes and functions for normal Python syntax handling
166 # Classes and functions for normal Python syntax handling
167 #-----------------------------------------------------------------------------
167 #-----------------------------------------------------------------------------
168
168
169 # HACK! This implementation, written by Robert K a while ago using the
169 # HACK! This implementation, written by Robert K a while ago using the
170 # compiler module, is more robust than the other one below, but it expects its
170 # compiler module, is more robust than the other one below, but it expects its
171 # input to be pure python (no ipython syntax). For now we're using it as a
171 # input to be pure python (no ipython syntax). For now we're using it as a
172 # second-pass splitter after the first pass transforms the input to pure
172 # second-pass splitter after the first pass transforms the input to pure
173 # python.
173 # python.
174
174
175 def split_blocks(python):
175 def split_blocks(python):
176 """ Split multiple lines of code into discrete commands that can be
176 """ Split multiple lines of code into discrete commands that can be
177 executed singly.
177 executed singly.
178
178
179 Parameters
179 Parameters
180 ----------
180 ----------
181 python : str
181 python : str
182 Pure, exec'able Python code.
182 Pure, exec'able Python code.
183
183
184 Returns
184 Returns
185 -------
185 -------
186 commands : list of str
186 commands : list of str
187 Separate commands that can be exec'ed independently.
187 Separate commands that can be exec'ed independently.
188 """
188 """
189 # compiler.parse treats trailing spaces after a newline as a
189 # compiler.parse treats trailing spaces after a newline as a
190 # SyntaxError. This is different than codeop.CommandCompiler, which
190 # SyntaxError. This is different than codeop.CommandCompiler, which
191 # will compile the trailng spaces just fine. We simply strip any
191 # will compile the trailng spaces just fine. We simply strip any
192 # trailing whitespace off. Passing a string with trailing whitespace
192 # trailing whitespace off. Passing a string with trailing whitespace
193 # to exec will fail however. There seems to be some inconsistency in
193 # to exec will fail however. There seems to be some inconsistency in
194 # how trailing whitespace is handled, but this seems to work.
194 # how trailing whitespace is handled, but this seems to work.
195 python_ori = python # save original in case we bail on error
195 python_ori = python # save original in case we bail on error
196 python = python.strip()
196 python = python.strip()
197
197
198 # The compiler module will parse the code into an abstract syntax tree.
198 # The compiler module will parse the code into an abstract syntax tree.
199 # This has a bug with str("a\nb"), but not str("""a\nb""")!!!
199 # This has a bug with str("a\nb"), but not str("""a\nb""")!!!
200 try:
200 try:
201 code_ast = ast.parse(python)
201 code_ast = ast.parse(python)
202 except:
202 except:
203 return [python_ori]
203 return [python_ori]
204
204
205 # Uncomment to help debug the ast tree
205 # Uncomment to help debug the ast tree
206 # for n in code_ast.body:
206 # for n in code_ast.body:
207 # print n.lineno,'->',n
207 # print n.lineno,'->',n
208
208
209 # Each separate command is available by iterating over ast.node. The
209 # Each separate command is available by iterating over ast.node. The
210 # lineno attribute is the line number (1-indexed) beginning the commands
210 # lineno attribute is the line number (1-indexed) beginning the commands
211 # suite.
211 # suite.
212 # lines ending with ";" yield a Discard Node that doesn't have a lineno
212 # lines ending with ";" yield a Discard Node that doesn't have a lineno
213 # attribute. These nodes can and should be discarded. But there are
213 # attribute. These nodes can and should be discarded. But there are
214 # other situations that cause Discard nodes that shouldn't be discarded.
214 # other situations that cause Discard nodes that shouldn't be discarded.
215 # We might eventually discover other cases where lineno is None and have
215 # We might eventually discover other cases where lineno is None and have
216 # to put in a more sophisticated test.
216 # to put in a more sophisticated test.
217 linenos = [x.lineno-1 for x in code_ast.body if x.lineno is not None]
217 linenos = [x.lineno-1 for x in code_ast.body if x.lineno is not None]
218
218
219 # When we finally get the slices, we will need to slice all the way to
219 # When we finally get the slices, we will need to slice all the way to
220 # the end even though we don't have a line number for it. Fortunately,
220 # the end even though we don't have a line number for it. Fortunately,
221 # None does the job nicely.
221 # None does the job nicely.
222 linenos.append(None)
222 linenos.append(None)
223
223
224 # Same problem at the other end: sometimes the ast tree has its
224 # Same problem at the other end: sometimes the ast tree has its
225 # first complete statement not starting on line 0. In this case
225 # first complete statement not starting on line 0. In this case
226 # we might miss part of it. This fixes ticket 266993. Thanks Gael!
226 # we might miss part of it. This fixes ticket 266993. Thanks Gael!
227 linenos[0] = 0
227 linenos[0] = 0
228
228
229 lines = python.splitlines()
229 lines = python.splitlines()
230
230
231 # Create a list of atomic commands.
231 # Create a list of atomic commands.
232 cmds = []
232 cmds = []
233 for i, j in zip(linenos[:-1], linenos[1:]):
233 for i, j in zip(linenos[:-1], linenos[1:]):
234 cmd = lines[i:j]
234 cmd = lines[i:j]
235 if cmd:
235 if cmd:
236 cmds.append('\n'.join(cmd)+'\n')
236 cmds.append('\n'.join(cmd)+'\n')
237
237
238 return cmds
238 return cmds
239
239
240
240
241 class InputSplitter(object):
241 class InputSplitter(object):
242 """An object that can split Python source input in executable blocks.
242 """An object that can split Python source input in executable blocks.
243
243
244 This object is designed to be used in one of two basic modes:
244 This object is designed to be used in one of two basic modes:
245
245
246 1. By feeding it python source line-by-line, using :meth:`push`. In this
246 1. By feeding it python source line-by-line, using :meth:`push`. In this
247 mode, it will return on each push whether the currently pushed code
247 mode, it will return on each push whether the currently pushed code
248 could be executed already. In addition, it provides a method called
248 could be executed already. In addition, it provides a method called
249 :meth:`push_accepts_more` that can be used to query whether more input
249 :meth:`push_accepts_more` that can be used to query whether more input
250 can be pushed into a single interactive block.
250 can be pushed into a single interactive block.
251
251
252 2. By calling :meth:`split_blocks` with a single, multiline Python string,
252 2. By calling :meth:`split_blocks` with a single, multiline Python string,
253 that is then split into blocks each of which can be executed
253 that is then split into blocks each of which can be executed
254 interactively as a single statement.
254 interactively as a single statement.
255
255
256 This is a simple example of how an interactive terminal-based client can use
256 This is a simple example of how an interactive terminal-based client can use
257 this tool::
257 this tool::
258
258
259 isp = InputSplitter()
259 isp = InputSplitter()
260 while isp.push_accepts_more():
260 while isp.push_accepts_more():
261 indent = ' '*isp.indent_spaces
261 indent = ' '*isp.indent_spaces
262 prompt = '>>> ' + indent
262 prompt = '>>> ' + indent
263 line = indent + raw_input(prompt)
263 line = indent + raw_input(prompt)
264 isp.push(line)
264 isp.push(line)
265 print 'Input source was:\n', isp.source_reset(),
265 print 'Input source was:\n', isp.source_reset(),
266 """
266 """
267 # Number of spaces of indentation computed from input that has been pushed
267 # Number of spaces of indentation computed from input that has been pushed
268 # so far. This is the attributes callers should query to get the current
268 # so far. This is the attributes callers should query to get the current
269 # indentation level, in order to provide auto-indent facilities.
269 # indentation level, in order to provide auto-indent facilities.
270 indent_spaces = 0
270 indent_spaces = 0
271 # String, indicating the default input encoding. It is computed by default
271 # String, indicating the default input encoding. It is computed by default
272 # at initialization time via get_input_encoding(), but it can be reset by a
272 # at initialization time via get_input_encoding(), but it can be reset by a
273 # client with specific knowledge of the encoding.
273 # client with specific knowledge of the encoding.
274 encoding = ''
274 encoding = ''
275 # String where the current full source input is stored, properly encoded.
275 # String where the current full source input is stored, properly encoded.
276 # Reading this attribute is the normal way of querying the currently pushed
276 # Reading this attribute is the normal way of querying the currently pushed
277 # source code, that has been properly encoded.
277 # source code, that has been properly encoded.
278 source = ''
278 source = ''
279 # Code object corresponding to the current source. It is automatically
279 # Code object corresponding to the current source. It is automatically
280 # synced to the source, so it can be queried at any time to obtain the code
280 # synced to the source, so it can be queried at any time to obtain the code
281 # object; it will be None if the source doesn't compile to valid Python.
281 # object; it will be None if the source doesn't compile to valid Python.
282 code = None
282 code = None
283 # Input mode
283 # Input mode
284 input_mode = 'line'
284 input_mode = 'line'
285
285
286 # Private attributes
286 # Private attributes
287
287
288 # List with lines of input accumulated so far
288 # List with lines of input accumulated so far
289 _buffer = None
289 _buffer = None
290 # Command compiler
290 # Command compiler
291 _compile = None
291 _compile = None
292 # Mark when input has changed indentation all the way back to flush-left
292 # Mark when input has changed indentation all the way back to flush-left
293 _full_dedent = False
293 _full_dedent = False
294 # Boolean indicating whether the current block is complete
294 # Boolean indicating whether the current block is complete
295 _is_complete = None
295 _is_complete = None
296
296
297 def __init__(self, input_mode=None):
297 def __init__(self, input_mode=None):
298 """Create a new InputSplitter instance.
298 """Create a new InputSplitter instance.
299
299
300 Parameters
300 Parameters
301 ----------
301 ----------
302 input_mode : str
302 input_mode : str
303
303
304 One of ['line', 'cell']; default is 'line'.
304 One of ['line', 'cell']; default is 'line'.
305
305
306 The input_mode parameter controls how new inputs are used when fed via
306 The input_mode parameter controls how new inputs are used when fed via
307 the :meth:`push` method:
307 the :meth:`push` method:
308
308
309 - 'line': meant for line-oriented clients, inputs are appended one at a
309 - 'line': meant for line-oriented clients, inputs are appended one at a
310 time to the internal buffer and the whole buffer is compiled.
310 time to the internal buffer and the whole buffer is compiled.
311
311
312 - 'cell': meant for clients that can edit multi-line 'cells' of text at
312 - 'cell': meant for clients that can edit multi-line 'cells' of text at
313 a time. A cell can contain one or more blocks that can be compile in
313 a time. A cell can contain one or more blocks that can be compile in
314 'single' mode by Python. In this mode, each new input new input
314 'single' mode by Python. In this mode, each new input new input
315 completely replaces all prior inputs. Cell mode is thus equivalent
315 completely replaces all prior inputs. Cell mode is thus equivalent
316 to prepending a full reset() to every push() call.
316 to prepending a full reset() to every push() call.
317 """
317 """
318 self._buffer = []
318 self._buffer = []
319 self._compile = codeop.CommandCompiler()
319 self._compile = codeop.CommandCompiler()
320 self.encoding = get_input_encoding()
320 self.encoding = get_input_encoding()
321 self.input_mode = InputSplitter.input_mode if input_mode is None \
321 self.input_mode = InputSplitter.input_mode if input_mode is None \
322 else input_mode
322 else input_mode
323
323
324 def reset(self):
324 def reset(self):
325 """Reset the input buffer and associated state."""
325 """Reset the input buffer and associated state."""
326 self.indent_spaces = 0
326 self.indent_spaces = 0
327 self._buffer[:] = []
327 self._buffer[:] = []
328 self.source = ''
328 self.source = ''
329 self.code = None
329 self.code = None
330 self._is_complete = False
330 self._is_complete = False
331 self._full_dedent = False
331 self._full_dedent = False
332
332
333 def source_reset(self):
333 def source_reset(self):
334 """Return the input source and perform a full reset.
334 """Return the input source and perform a full reset.
335 """
335 """
336 out = self.source
336 out = self.source
337 self.reset()
337 self.reset()
338 return out
338 return out
339
339
340 def push(self, lines):
340 def push(self, lines):
341 """Push one or more lines of input.
341 """Push one or more lines of input.
342
342
343 This stores the given lines and returns a status code indicating
343 This stores the given lines and returns a status code indicating
344 whether the code forms a complete Python block or not.
344 whether the code forms a complete Python block or not.
345
345
346 Any exceptions generated in compilation are swallowed, but if an
346 Any exceptions generated in compilation are swallowed, but if an
347 exception was produced, the method returns True.
347 exception was produced, the method returns True.
348
348
349 Parameters
349 Parameters
350 ----------
350 ----------
351 lines : string
351 lines : string
352 One or more lines of Python input.
352 One or more lines of Python input.
353
353
354 Returns
354 Returns
355 -------
355 -------
356 is_complete : boolean
356 is_complete : boolean
357 True if the current input source (the result of the current input
357 True if the current input source (the result of the current input
358 plus prior inputs) forms a complete Python execution block. Note that
358 plus prior inputs) forms a complete Python execution block. Note that
359 this value is also stored as a private attribute (_is_complete), so it
359 this value is also stored as a private attribute (_is_complete), so it
360 can be queried at any time.
360 can be queried at any time.
361 """
361 """
362 if self.input_mode == 'cell':
362 if self.input_mode == 'cell':
363 self.reset()
363 self.reset()
364
364
365 self._store(lines)
365 self._store(lines)
366 source = self.source
366 source = self.source
367
367
368 # Before calling _compile(), reset the code object to None so that if an
368 # Before calling _compile(), reset the code object to None so that if an
369 # exception is raised in compilation, we don't mislead by having
369 # exception is raised in compilation, we don't mislead by having
370 # inconsistent code/source attributes.
370 # inconsistent code/source attributes.
371 self.code, self._is_complete = None, None
371 self.code, self._is_complete = None, None
372
372
373 # Honor termination lines properly
373 # Honor termination lines properly
374 if source.rstrip().endswith('\\'):
374 if source.rstrip().endswith('\\'):
375 return False
375 return False
376
376
377 self._update_indent(lines)
377 self._update_indent(lines)
378 try:
378 try:
379 self.code = self._compile(source)
379 self.code = self._compile(source)
380 # Invalid syntax can produce any of a number of different errors from
380 # Invalid syntax can produce any of a number of different errors from
381 # inside the compiler, so we have to catch them all. Syntax errors
381 # inside the compiler, so we have to catch them all. Syntax errors
382 # immediately produce a 'ready' block, so the invalid Python can be
382 # immediately produce a 'ready' block, so the invalid Python can be
383 # sent to the kernel for evaluation with possible ipython
383 # sent to the kernel for evaluation with possible ipython
384 # special-syntax conversion.
384 # special-syntax conversion.
385 except (SyntaxError, OverflowError, ValueError, TypeError,
385 except (SyntaxError, OverflowError, ValueError, TypeError,
386 MemoryError):
386 MemoryError):
387 self._is_complete = True
387 self._is_complete = True
388 else:
388 else:
389 # Compilation didn't produce any exceptions (though it may not have
389 # Compilation didn't produce any exceptions (though it may not have
390 # given a complete code object)
390 # given a complete code object)
391 self._is_complete = self.code is not None
391 self._is_complete = self.code is not None
392
392
393 return self._is_complete
393 return self._is_complete
394
394
395 def push_accepts_more(self):
395 def push_accepts_more(self):
396 """Return whether a block of interactive input can accept more input.
396 """Return whether a block of interactive input can accept more input.
397
397
398 This method is meant to be used by line-oriented frontends, who need to
398 This method is meant to be used by line-oriented frontends, who need to
399 guess whether a block is complete or not based solely on prior and
399 guess whether a block is complete or not based solely on prior and
400 current input lines. The InputSplitter considers it has a complete
400 current input lines. The InputSplitter considers it has a complete
401 interactive block and will not accept more input only when either a
401 interactive block and will not accept more input only when either a
402 SyntaxError is raised, or *all* of the following are true:
402 SyntaxError is raised, or *all* of the following are true:
403
403
404 1. The input compiles to a complete statement.
404 1. The input compiles to a complete statement.
405
405
406 2. The indentation level is flush-left (because if we are indented,
406 2. The indentation level is flush-left (because if we are indented,
407 like inside a function definition or for loop, we need to keep
407 like inside a function definition or for loop, we need to keep
408 reading new input).
408 reading new input).
409
409
410 3. There is one extra line consisting only of whitespace.
410 3. There is one extra line consisting only of whitespace.
411
411
412 Because of condition #3, this method should be used only by
412 Because of condition #3, this method should be used only by
413 *line-oriented* frontends, since it means that intermediate blank lines
413 *line-oriented* frontends, since it means that intermediate blank lines
414 are not allowed in function definitions (or any other indented block).
414 are not allowed in function definitions (or any other indented block).
415
415
416 Block-oriented frontends that have a separate keyboard event to
416 Block-oriented frontends that have a separate keyboard event to
417 indicate execution should use the :meth:`split_blocks` method instead.
417 indicate execution should use the :meth:`split_blocks` method instead.
418
418
419 If the current input produces a syntax error, this method immediately
419 If the current input produces a syntax error, this method immediately
420 returns False but does *not* raise the syntax error exception, as
420 returns False but does *not* raise the syntax error exception, as
421 typically clients will want to send invalid syntax to an execution
421 typically clients will want to send invalid syntax to an execution
422 backend which might convert the invalid syntax into valid Python via
422 backend which might convert the invalid syntax into valid Python via
423 one of the dynamic IPython mechanisms.
423 one of the dynamic IPython mechanisms.
424 """
424 """
425
425
426 # With incomplete input, unconditionally accept more
426 # With incomplete input, unconditionally accept more
427 if not self._is_complete:
427 if not self._is_complete:
428 return True
428 return True
429
429
430 # If we already have complete input and we're flush left, the answer
430 # If we already have complete input and we're flush left, the answer
431 # depends. In line mode, we're done. But in cell mode, we need to
431 # depends. In line mode, we're done. But in cell mode, we need to
432 # check how many blocks the input so far compiles into, because if
432 # check how many blocks the input so far compiles into, because if
433 # there's already more than one full independent block of input, then
433 # there's already more than one full independent block of input, then
434 # the client has entered full 'cell' mode and is feeding lines that
434 # the client has entered full 'cell' mode and is feeding lines that
435 # each is complete. In this case we should then keep accepting.
435 # each is complete. In this case we should then keep accepting.
436 # The Qt terminal-like console does precisely this, to provide the
436 # The Qt terminal-like console does precisely this, to provide the
437 # convenience of terminal-like input of single expressions, but
437 # convenience of terminal-like input of single expressions, but
438 # allowing the user (with a separate keystroke) to switch to 'cell'
438 # allowing the user (with a separate keystroke) to switch to 'cell'
439 # mode and type multiple expressions in one shot.
439 # mode and type multiple expressions in one shot.
440 if self.indent_spaces==0:
440 if self.indent_spaces==0:
441 if self.input_mode=='line':
441 if self.input_mode=='line':
442 return False
442 return False
443 else:
443 else:
444 nblocks = len(split_blocks(''.join(self._buffer)))
444 nblocks = len(split_blocks(''.join(self._buffer)))
445 if nblocks==1:
445 if nblocks==1:
446 return False
446 return False
447
447
448 # When input is complete, then termination is marked by an extra blank
448 # When input is complete, then termination is marked by an extra blank
449 # line at the end.
449 # line at the end.
450 last_line = self.source.splitlines()[-1]
450 last_line = self.source.splitlines()[-1]
451 return bool(last_line and not last_line.isspace())
451 return bool(last_line and not last_line.isspace())
452
452
453 def split_blocks(self, lines):
453 def split_blocks(self, lines):
454 """Split a multiline string into multiple input blocks.
454 """Split a multiline string into multiple input blocks.
455
455
456 Note: this method starts by performing a full reset().
456 Note: this method starts by performing a full reset().
457
457
458 Parameters
458 Parameters
459 ----------
459 ----------
460 lines : str
460 lines : str
461 A possibly multiline string.
461 A possibly multiline string.
462
462
463 Returns
463 Returns
464 -------
464 -------
465 blocks : list
465 blocks : list
466 A list of strings, each possibly multiline. Each string corresponds
466 A list of strings, each possibly multiline. Each string corresponds
467 to a single block that can be compiled in 'single' mode (unless it
467 to a single block that can be compiled in 'single' mode (unless it
468 has a syntax error)."""
468 has a syntax error)."""
469
469
470 # This code is fairly delicate. If you make any changes here, make
470 # This code is fairly delicate. If you make any changes here, make
471 # absolutely sure that you do run the full test suite and ALL tests
471 # absolutely sure that you do run the full test suite and ALL tests
472 # pass.
472 # pass.
473
473
474 self.reset()
474 self.reset()
475 blocks = []
475 blocks = []
476
476
477 # Reversed copy so we can use pop() efficiently and consume the input
477 # Reversed copy so we can use pop() efficiently and consume the input
478 # as a stack
478 # as a stack
479 lines = lines.splitlines()[::-1]
479 lines = lines.splitlines()[::-1]
480 # Outer loop over all input
480 # Outer loop over all input
481 while lines:
481 while lines:
482 #print 'Current lines:', lines # dbg
482 #print 'Current lines:', lines # dbg
483 # Inner loop to build each block
483 # Inner loop to build each block
484 while True:
484 while True:
485 # Safety exit from inner loop
485 # Safety exit from inner loop
486 if not lines:
486 if not lines:
487 break
487 break
488 # Grab next line but don't push it yet
488 # Grab next line but don't push it yet
489 next_line = lines.pop()
489 next_line = lines.pop()
490 # Blank/empty lines are pushed as-is
490 # Blank/empty lines are pushed as-is
491 if not next_line or next_line.isspace():
491 if not next_line or next_line.isspace():
492 self.push(next_line)
492 self.push(next_line)
493 continue
493 continue
494
494
495 # Check indentation changes caused by the *next* line
495 # Check indentation changes caused by the *next* line
496 indent_spaces, _full_dedent = self._find_indent(next_line)
496 indent_spaces, _full_dedent = self._find_indent(next_line)
497
497
498 # If the next line causes a dedent, it can be for two differnt
498 # If the next line causes a dedent, it can be for two differnt
499 # reasons: either an explicit de-dent by the user or a
499 # reasons: either an explicit de-dent by the user or a
500 # return/raise/pass statement. These MUST be handled
500 # return/raise/pass statement. These MUST be handled
501 # separately:
501 # separately:
502 #
502 #
503 # 1. the first case is only detected when the actual explicit
503 # 1. the first case is only detected when the actual explicit
504 # dedent happens, and that would be the *first* line of a *new*
504 # dedent happens, and that would be the *first* line of a *new*
505 # block. Thus, we must put the line back into the input buffer
505 # block. Thus, we must put the line back into the input buffer
506 # so that it starts a new block on the next pass.
506 # so that it starts a new block on the next pass.
507 #
507 #
508 # 2. the second case is detected in the line before the actual
508 # 2. the second case is detected in the line before the actual
509 # dedent happens, so , we consume the line and we can break out
509 # dedent happens, so , we consume the line and we can break out
510 # to start a new block.
510 # to start a new block.
511
511
512 # Case 1, explicit dedent causes a break.
512 # Case 1, explicit dedent causes a break.
513 # Note: check that we weren't on the very last line, else we'll
513 # Note: check that we weren't on the very last line, else we'll
514 # enter an infinite loop adding/removing the last line.
514 # enter an infinite loop adding/removing the last line.
515 if _full_dedent and lines and not next_line.startswith(' '):
515 if _full_dedent and lines and not next_line.startswith(' '):
516 lines.append(next_line)
516 lines.append(next_line)
517 break
517 break
518
518
519 # Otherwise any line is pushed
519 # Otherwise any line is pushed
520 self.push(next_line)
520 self.push(next_line)
521
521
522 # Case 2, full dedent with full block ready:
522 # Case 2, full dedent with full block ready:
523 if _full_dedent or \
523 if _full_dedent or \
524 self.indent_spaces==0 and not self.push_accepts_more():
524 self.indent_spaces==0 and not self.push_accepts_more():
525 break
525 break
526 # Form the new block with the current source input
526 # Form the new block with the current source input
527 blocks.append(self.source_reset())
527 blocks.append(self.source_reset())
528
528
529 #return blocks
529 #return blocks
530 # HACK!!! Now that our input is in blocks but guaranteed to be pure
530 # HACK!!! Now that our input is in blocks but guaranteed to be pure
531 # python syntax, feed it back a second time through the AST-based
531 # python syntax, feed it back a second time through the AST-based
532 # splitter, which is more accurate than ours.
532 # splitter, which is more accurate than ours.
533 return split_blocks(''.join(blocks))
533 return split_blocks(''.join(blocks))
534
534
535 #------------------------------------------------------------------------
535 #------------------------------------------------------------------------
536 # Private interface
536 # Private interface
537 #------------------------------------------------------------------------
537 #------------------------------------------------------------------------
538
538
539 def _find_indent(self, line):
539 def _find_indent(self, line):
540 """Compute the new indentation level for a single line.
540 """Compute the new indentation level for a single line.
541
541
542 Parameters
542 Parameters
543 ----------
543 ----------
544 line : str
544 line : str
545 A single new line of non-whitespace, non-comment Python input.
545 A single new line of non-whitespace, non-comment Python input.
546
546
547 Returns
547 Returns
548 -------
548 -------
549 indent_spaces : int
549 indent_spaces : int
550 New value for the indent level (it may be equal to self.indent_spaces
550 New value for the indent level (it may be equal to self.indent_spaces
551 if indentation doesn't change.
551 if indentation doesn't change.
552
552
553 full_dedent : boolean
553 full_dedent : boolean
554 Whether the new line causes a full flush-left dedent.
554 Whether the new line causes a full flush-left dedent.
555 """
555 """
556 indent_spaces = self.indent_spaces
556 indent_spaces = self.indent_spaces
557 full_dedent = self._full_dedent
557 full_dedent = self._full_dedent
558
558
559 inisp = num_ini_spaces(line)
559 inisp = num_ini_spaces(line)
560 if inisp < indent_spaces:
560 if inisp < indent_spaces:
561 indent_spaces = inisp
561 indent_spaces = inisp
562 if indent_spaces <= 0:
562 if indent_spaces <= 0:
563 #print 'Full dedent in text',self.source # dbg
563 #print 'Full dedent in text',self.source # dbg
564 full_dedent = True
564 full_dedent = True
565
565
566 if line[-1] == ':':
566 if line[-1] == ':':
567 indent_spaces += 4
567 indent_spaces += 4
568 elif dedent_re.match(line):
568 elif dedent_re.match(line):
569 indent_spaces -= 4
569 indent_spaces -= 4
570 if indent_spaces <= 0:
570 if indent_spaces <= 0:
571 full_dedent = True
571 full_dedent = True
572
572
573 # Safety
573 # Safety
574 if indent_spaces < 0:
574 if indent_spaces < 0:
575 indent_spaces = 0
575 indent_spaces = 0
576 #print 'safety' # dbg
576 #print 'safety' # dbg
577
577
578 return indent_spaces, full_dedent
578 return indent_spaces, full_dedent
579
579
580 def _update_indent(self, lines):
580 def _update_indent(self, lines):
581 for line in remove_comments(lines).splitlines():
581 for line in remove_comments(lines).splitlines():
582 if line and not line.isspace():
582 if line and not line.isspace():
583 self.indent_spaces, self._full_dedent = self._find_indent(line)
583 self.indent_spaces, self._full_dedent = self._find_indent(line)
584
584
585 def _store(self, lines, buffer=None, store='source'):
585 def _store(self, lines, buffer=None, store='source'):
586 """Store one or more lines of input.
586 """Store one or more lines of input.
587
587
588 If input lines are not newline-terminated, a newline is automatically
588 If input lines are not newline-terminated, a newline is automatically
589 appended."""
589 appended."""
590 if not isinstance(lines, unicode):
591 lines = lines.decode(self.encoding)
592
590
593 if buffer is None:
591 if buffer is None:
594 buffer = self._buffer
592 buffer = self._buffer
595
593
596 if lines.endswith('\n'):
594 if lines.endswith('\n'):
597 buffer.append(lines)
595 buffer.append(lines)
598 else:
596 else:
599 buffer.append(lines+'\n')
597 buffer.append(lines+'\n')
600 setattr(self, store, self._set_source(buffer))
598 setattr(self, store, self._set_source(buffer))
601
599
602 def _set_source(self, buffer):
600 def _set_source(self, buffer):
603 return ''.join(buffer)
601 return u''.join(buffer)
604
602
605
603
606 #-----------------------------------------------------------------------------
604 #-----------------------------------------------------------------------------
607 # Functions and classes for IPython-specific syntactic support
605 # Functions and classes for IPython-specific syntactic support
608 #-----------------------------------------------------------------------------
606 #-----------------------------------------------------------------------------
609
607
610 # RegExp for splitting line contents into pre-char//first word-method//rest.
608 # RegExp for splitting line contents into pre-char//first word-method//rest.
611 # For clarity, each group in on one line.
609 # For clarity, each group in on one line.
612
610
613 line_split = re.compile("""
611 line_split = re.compile("""
614 ^(\s*) # any leading space
612 ^(\s*) # any leading space
615 ([,;/%]|!!?|\?\??) # escape character or characters
613 ([,;/%]|!!?|\?\??) # escape character or characters
616 \s*(%?[\w\.\*]*) # function/method, possibly with leading %
614 \s*(%?[\w\.\*]*) # function/method, possibly with leading %
617 # to correctly treat things like '?%magic'
615 # to correctly treat things like '?%magic'
618 (\s+.*$|$) # rest of line
616 (\s+.*$|$) # rest of line
619 """, re.VERBOSE)
617 """, re.VERBOSE)
620
618
621
619
622 def split_user_input(line):
620 def split_user_input(line):
623 """Split user input into early whitespace, esc-char, function part and rest.
621 """Split user input into early whitespace, esc-char, function part and rest.
624
622
625 This is currently handles lines with '=' in them in a very inconsistent
623 This is currently handles lines with '=' in them in a very inconsistent
626 manner.
624 manner.
627
625
628 Examples
626 Examples
629 ========
627 ========
630 >>> split_user_input('x=1')
628 >>> split_user_input('x=1')
631 ('', '', 'x=1', '')
629 ('', '', 'x=1', '')
632 >>> split_user_input('?')
630 >>> split_user_input('?')
633 ('', '?', '', '')
631 ('', '?', '', '')
634 >>> split_user_input('??')
632 >>> split_user_input('??')
635 ('', '??', '', '')
633 ('', '??', '', '')
636 >>> split_user_input(' ?')
634 >>> split_user_input(' ?')
637 (' ', '?', '', '')
635 (' ', '?', '', '')
638 >>> split_user_input(' ??')
636 >>> split_user_input(' ??')
639 (' ', '??', '', '')
637 (' ', '??', '', '')
640 >>> split_user_input('??x')
638 >>> split_user_input('??x')
641 ('', '??', 'x', '')
639 ('', '??', 'x', '')
642 >>> split_user_input('?x=1')
640 >>> split_user_input('?x=1')
643 ('', '', '?x=1', '')
641 ('', '', '?x=1', '')
644 >>> split_user_input('!ls')
642 >>> split_user_input('!ls')
645 ('', '!', 'ls', '')
643 ('', '!', 'ls', '')
646 >>> split_user_input(' !ls')
644 >>> split_user_input(' !ls')
647 (' ', '!', 'ls', '')
645 (' ', '!', 'ls', '')
648 >>> split_user_input('!!ls')
646 >>> split_user_input('!!ls')
649 ('', '!!', 'ls', '')
647 ('', '!!', 'ls', '')
650 >>> split_user_input(' !!ls')
648 >>> split_user_input(' !!ls')
651 (' ', '!!', 'ls', '')
649 (' ', '!!', 'ls', '')
652 >>> split_user_input(',ls')
650 >>> split_user_input(',ls')
653 ('', ',', 'ls', '')
651 ('', ',', 'ls', '')
654 >>> split_user_input(';ls')
652 >>> split_user_input(';ls')
655 ('', ';', 'ls', '')
653 ('', ';', 'ls', '')
656 >>> split_user_input(' ;ls')
654 >>> split_user_input(' ;ls')
657 (' ', ';', 'ls', '')
655 (' ', ';', 'ls', '')
658 >>> split_user_input('f.g(x)')
656 >>> split_user_input('f.g(x)')
659 ('', '', 'f.g(x)', '')
657 ('', '', 'f.g(x)', '')
660 >>> split_user_input('f.g (x)')
658 >>> split_user_input('f.g (x)')
661 ('', '', 'f.g', '(x)')
659 ('', '', 'f.g', '(x)')
662 >>> split_user_input('?%hist')
660 >>> split_user_input('?%hist')
663 ('', '?', '%hist', '')
661 ('', '?', '%hist', '')
664 >>> split_user_input('?x*')
662 >>> split_user_input('?x*')
665 ('', '?', 'x*', '')
663 ('', '?', 'x*', '')
666 """
664 """
667 match = line_split.match(line)
665 match = line_split.match(line)
668 if match:
666 if match:
669 lspace, esc, fpart, rest = match.groups()
667 lspace, esc, fpart, rest = match.groups()
670 else:
668 else:
671 # print "match failed for line '%s'" % line
669 # print "match failed for line '%s'" % line
672 try:
670 try:
673 fpart, rest = line.split(None, 1)
671 fpart, rest = line.split(None, 1)
674 except ValueError:
672 except ValueError:
675 # print "split failed for line '%s'" % line
673 # print "split failed for line '%s'" % line
676 fpart, rest = line,''
674 fpart, rest = line,''
677 lspace = re.match('^(\s*)(.*)', line).groups()[0]
675 lspace = re.match('^(\s*)(.*)', line).groups()[0]
678 esc = ''
676 esc = ''
679
677
680 # fpart has to be a valid python identifier, so it better be only pure
678 # fpart has to be a valid python identifier, so it better be only pure
681 # ascii, no unicode:
679 # ascii, no unicode:
682 try:
680 try:
683 fpart = fpart.encode('ascii')
681 fpart = fpart.encode('ascii')
684 except UnicodeEncodeError:
682 except UnicodeEncodeError:
685 lspace = unicode(lspace)
683 lspace = unicode(lspace)
686 rest = fpart + u' ' + rest
684 rest = fpart + u' ' + rest
687 fpart = u''
685 fpart = u''
688
686
689 #print 'line:<%s>' % line # dbg
687 #print 'line:<%s>' % line # dbg
690 #print 'esc <%s> fpart <%s> rest <%s>' % (esc,fpart.strip(),rest) # dbg
688 #print 'esc <%s> fpart <%s> rest <%s>' % (esc,fpart.strip(),rest) # dbg
691 return lspace, esc, fpart.strip(), rest.lstrip()
689 return lspace, esc, fpart.strip(), rest.lstrip()
692
690
693
691
694 # The escaped translators ALL receive a line where their own escape has been
692 # The escaped translators ALL receive a line where their own escape has been
695 # stripped. Only '?' is valid at the end of the line, all others can only be
693 # stripped. Only '?' is valid at the end of the line, all others can only be
696 # placed at the start.
694 # placed at the start.
697
695
698 class LineInfo(object):
696 class LineInfo(object):
699 """A single line of input and associated info.
697 """A single line of input and associated info.
700
698
701 This is a utility class that mostly wraps the output of
699 This is a utility class that mostly wraps the output of
702 :func:`split_user_input` into a convenient object to be passed around
700 :func:`split_user_input` into a convenient object to be passed around
703 during input transformations.
701 during input transformations.
704
702
705 Includes the following as properties:
703 Includes the following as properties:
706
704
707 line
705 line
708 The original, raw line
706 The original, raw line
709
707
710 lspace
708 lspace
711 Any early whitespace before actual text starts.
709 Any early whitespace before actual text starts.
712
710
713 esc
711 esc
714 The initial esc character (or characters, for double-char escapes like
712 The initial esc character (or characters, for double-char escapes like
715 '??' or '!!').
713 '??' or '!!').
716
714
717 fpart
715 fpart
718 The 'function part', which is basically the maximal initial sequence
716 The 'function part', which is basically the maximal initial sequence
719 of valid python identifiers and the '.' character. This is what is
717 of valid python identifiers and the '.' character. This is what is
720 checked for alias and magic transformations, used for auto-calling,
718 checked for alias and magic transformations, used for auto-calling,
721 etc.
719 etc.
722
720
723 rest
721 rest
724 Everything else on the line.
722 Everything else on the line.
725 """
723 """
726 def __init__(self, line):
724 def __init__(self, line):
727 self.line = line
725 self.line = line
728 self.lspace, self.esc, self.fpart, self.rest = \
726 self.lspace, self.esc, self.fpart, self.rest = \
729 split_user_input(line)
727 split_user_input(line)
730
728
731 def __str__(self):
729 def __str__(self):
732 return "LineInfo [%s|%s|%s|%s]" % (self.lspace, self.esc,
730 return "LineInfo [%s|%s|%s|%s]" % (self.lspace, self.esc,
733 self.fpart, self.rest)
731 self.fpart, self.rest)
734
732
735
733
736 # Transformations of the special syntaxes that don't rely on an explicit escape
734 # Transformations of the special syntaxes that don't rely on an explicit escape
737 # character but instead on patterns on the input line
735 # character but instead on patterns on the input line
738
736
739 # The core transformations are implemented as standalone functions that can be
737 # The core transformations are implemented as standalone functions that can be
740 # tested and validated in isolation. Each of these uses a regexp, we
738 # tested and validated in isolation. Each of these uses a regexp, we
741 # pre-compile these and keep them close to each function definition for clarity
739 # pre-compile these and keep them close to each function definition for clarity
742
740
743 _assign_system_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
741 _assign_system_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
744 r'\s*=\s*!\s*(?P<cmd>.*)')
742 r'\s*=\s*!\s*(?P<cmd>.*)')
745
743
746 def transform_assign_system(line):
744 def transform_assign_system(line):
747 """Handle the `files = !ls` syntax."""
745 """Handle the `files = !ls` syntax."""
748 m = _assign_system_re.match(line)
746 m = _assign_system_re.match(line)
749 if m is not None:
747 if m is not None:
750 cmd = m.group('cmd')
748 cmd = m.group('cmd')
751 lhs = m.group('lhs')
749 lhs = m.group('lhs')
752 expr = make_quoted_expr(cmd)
750 expr = make_quoted_expr(cmd)
753 new_line = '%s = get_ipython().getoutput(%s)' % (lhs, expr)
751 new_line = '%s = get_ipython().getoutput(%s)' % (lhs, expr)
754 return new_line
752 return new_line
755 return line
753 return line
756
754
757
755
758 _assign_magic_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
756 _assign_magic_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
759 r'\s*=\s*%\s*(?P<cmd>.*)')
757 r'\s*=\s*%\s*(?P<cmd>.*)')
760
758
761 def transform_assign_magic(line):
759 def transform_assign_magic(line):
762 """Handle the `a = %who` syntax."""
760 """Handle the `a = %who` syntax."""
763 m = _assign_magic_re.match(line)
761 m = _assign_magic_re.match(line)
764 if m is not None:
762 if m is not None:
765 cmd = m.group('cmd')
763 cmd = m.group('cmd')
766 lhs = m.group('lhs')
764 lhs = m.group('lhs')
767 expr = make_quoted_expr(cmd)
765 expr = make_quoted_expr(cmd)
768 new_line = '%s = get_ipython().magic(%s)' % (lhs, expr)
766 new_line = '%s = get_ipython().magic(%s)' % (lhs, expr)
769 return new_line
767 return new_line
770 return line
768 return line
771
769
772
770
773 _classic_prompt_re = re.compile(r'^([ \t]*>>> |^[ \t]*\.\.\. )')
771 _classic_prompt_re = re.compile(r'^([ \t]*>>> |^[ \t]*\.\.\. )')
774
772
775 def transform_classic_prompt(line):
773 def transform_classic_prompt(line):
776 """Handle inputs that start with '>>> ' syntax."""
774 """Handle inputs that start with '>>> ' syntax."""
777
775
778 if not line or line.isspace():
776 if not line or line.isspace():
779 return line
777 return line
780 m = _classic_prompt_re.match(line)
778 m = _classic_prompt_re.match(line)
781 if m:
779 if m:
782 return line[len(m.group(0)):]
780 return line[len(m.group(0)):]
783 else:
781 else:
784 return line
782 return line
785
783
786
784
787 _ipy_prompt_re = re.compile(r'^([ \t]*In \[\d+\]: |^[ \t]*\ \ \ \.\.\.+: )')
785 _ipy_prompt_re = re.compile(r'^([ \t]*In \[\d+\]: |^[ \t]*\ \ \ \.\.\.+: )')
788
786
789 def transform_ipy_prompt(line):
787 def transform_ipy_prompt(line):
790 """Handle inputs that start classic IPython prompt syntax."""
788 """Handle inputs that start classic IPython prompt syntax."""
791
789
792 if not line or line.isspace():
790 if not line or line.isspace():
793 return line
791 return line
794 #print 'LINE: %r' % line # dbg
792 #print 'LINE: %r' % line # dbg
795 m = _ipy_prompt_re.match(line)
793 m = _ipy_prompt_re.match(line)
796 if m:
794 if m:
797 #print 'MATCH! %r -> %r' % (line, line[len(m.group(0)):]) # dbg
795 #print 'MATCH! %r -> %r' % (line, line[len(m.group(0)):]) # dbg
798 return line[len(m.group(0)):]
796 return line[len(m.group(0)):]
799 else:
797 else:
800 return line
798 return line
801
799
802
800
803 class EscapedTransformer(object):
801 class EscapedTransformer(object):
804 """Class to transform lines that are explicitly escaped out."""
802 """Class to transform lines that are explicitly escaped out."""
805
803
806 def __init__(self):
804 def __init__(self):
807 tr = { ESC_SHELL : self._tr_system,
805 tr = { ESC_SHELL : self._tr_system,
808 ESC_SH_CAP : self._tr_system2,
806 ESC_SH_CAP : self._tr_system2,
809 ESC_HELP : self._tr_help,
807 ESC_HELP : self._tr_help,
810 ESC_HELP2 : self._tr_help,
808 ESC_HELP2 : self._tr_help,
811 ESC_MAGIC : self._tr_magic,
809 ESC_MAGIC : self._tr_magic,
812 ESC_QUOTE : self._tr_quote,
810 ESC_QUOTE : self._tr_quote,
813 ESC_QUOTE2 : self._tr_quote2,
811 ESC_QUOTE2 : self._tr_quote2,
814 ESC_PAREN : self._tr_paren }
812 ESC_PAREN : self._tr_paren }
815 self.tr = tr
813 self.tr = tr
816
814
817 # Support for syntax transformations that use explicit escapes typed by the
815 # Support for syntax transformations that use explicit escapes typed by the
818 # user at the beginning of a line
816 # user at the beginning of a line
819 @staticmethod
817 @staticmethod
820 def _tr_system(line_info):
818 def _tr_system(line_info):
821 "Translate lines escaped with: !"
819 "Translate lines escaped with: !"
822 cmd = line_info.line.lstrip().lstrip(ESC_SHELL)
820 cmd = line_info.line.lstrip().lstrip(ESC_SHELL)
823 return '%sget_ipython().system(%s)' % (line_info.lspace,
821 return '%sget_ipython().system(%s)' % (line_info.lspace,
824 make_quoted_expr(cmd))
822 make_quoted_expr(cmd))
825
823
826 @staticmethod
824 @staticmethod
827 def _tr_system2(line_info):
825 def _tr_system2(line_info):
828 "Translate lines escaped with: !!"
826 "Translate lines escaped with: !!"
829 cmd = line_info.line.lstrip()[2:]
827 cmd = line_info.line.lstrip()[2:]
830 return '%sget_ipython().getoutput(%s)' % (line_info.lspace,
828 return '%sget_ipython().getoutput(%s)' % (line_info.lspace,
831 make_quoted_expr(cmd))
829 make_quoted_expr(cmd))
832
830
833 @staticmethod
831 @staticmethod
834 def _tr_help(line_info):
832 def _tr_help(line_info):
835 "Translate lines escaped with: ?/??"
833 "Translate lines escaped with: ?/??"
836 # A naked help line should just fire the intro help screen
834 # A naked help line should just fire the intro help screen
837 if not line_info.line[1:]:
835 if not line_info.line[1:]:
838 return 'get_ipython().show_usage()'
836 return 'get_ipython().show_usage()'
839
837
840 # There may be one or two '?' at the end, move them to the front so that
838 # There may be one or two '?' at the end, move them to the front so that
841 # the rest of the logic can assume escapes are at the start
839 # the rest of the logic can assume escapes are at the start
842 l_ori = line_info
840 l_ori = line_info
843 line = line_info.line
841 line = line_info.line
844 if line.endswith('?'):
842 if line.endswith('?'):
845 line = line[-1] + line[:-1]
843 line = line[-1] + line[:-1]
846 if line.endswith('?'):
844 if line.endswith('?'):
847 line = line[-1] + line[:-1]
845 line = line[-1] + line[:-1]
848 line_info = LineInfo(line)
846 line_info = LineInfo(line)
849
847
850 # From here on, simply choose which level of detail to get, and
848 # From here on, simply choose which level of detail to get, and
851 # special-case the psearch syntax
849 # special-case the psearch syntax
852 pinfo = 'pinfo' # default
850 pinfo = 'pinfo' # default
853 if '*' in line_info.line:
851 if '*' in line_info.line:
854 pinfo = 'psearch'
852 pinfo = 'psearch'
855 elif line_info.esc == '??':
853 elif line_info.esc == '??':
856 pinfo = 'pinfo2'
854 pinfo = 'pinfo2'
857
855
858 tpl = '%sget_ipython().magic("%s %s")'
856 tpl = '%sget_ipython().magic("%s %s")'
859 return tpl % (line_info.lspace, pinfo,
857 return tpl % (line_info.lspace, pinfo,
860 ' '.join([line_info.fpart, line_info.rest]).strip())
858 ' '.join([line_info.fpart, line_info.rest]).strip())
861
859
862 @staticmethod
860 @staticmethod
863 def _tr_magic(line_info):
861 def _tr_magic(line_info):
864 "Translate lines escaped with: %"
862 "Translate lines escaped with: %"
865 tpl = '%sget_ipython().magic(%s)'
863 tpl = '%sget_ipython().magic(%s)'
866 cmd = make_quoted_expr(' '.join([line_info.fpart,
864 cmd = make_quoted_expr(' '.join([line_info.fpart,
867 line_info.rest]).strip())
865 line_info.rest]).strip())
868 return tpl % (line_info.lspace, cmd)
866 return tpl % (line_info.lspace, cmd)
869
867
870 @staticmethod
868 @staticmethod
871 def _tr_quote(line_info):
869 def _tr_quote(line_info):
872 "Translate lines escaped with: ,"
870 "Translate lines escaped with: ,"
873 return '%s%s("%s")' % (line_info.lspace, line_info.fpart,
871 return '%s%s("%s")' % (line_info.lspace, line_info.fpart,
874 '", "'.join(line_info.rest.split()) )
872 '", "'.join(line_info.rest.split()) )
875
873
876 @staticmethod
874 @staticmethod
877 def _tr_quote2(line_info):
875 def _tr_quote2(line_info):
878 "Translate lines escaped with: ;"
876 "Translate lines escaped with: ;"
879 return '%s%s("%s")' % (line_info.lspace, line_info.fpart,
877 return '%s%s("%s")' % (line_info.lspace, line_info.fpart,
880 line_info.rest)
878 line_info.rest)
881
879
882 @staticmethod
880 @staticmethod
883 def _tr_paren(line_info):
881 def _tr_paren(line_info):
884 "Translate lines escaped with: /"
882 "Translate lines escaped with: /"
885 return '%s%s(%s)' % (line_info.lspace, line_info.fpart,
883 return '%s%s(%s)' % (line_info.lspace, line_info.fpart,
886 ", ".join(line_info.rest.split()))
884 ", ".join(line_info.rest.split()))
887
885
888 def __call__(self, line):
886 def __call__(self, line):
889 """Class to transform lines that are explicitly escaped out.
887 """Class to transform lines that are explicitly escaped out.
890
888
891 This calls the above _tr_* static methods for the actual line
889 This calls the above _tr_* static methods for the actual line
892 translations."""
890 translations."""
893
891
894 # Empty lines just get returned unmodified
892 # Empty lines just get returned unmodified
895 if not line or line.isspace():
893 if not line or line.isspace():
896 return line
894 return line
897
895
898 # Get line endpoints, where the escapes can be
896 # Get line endpoints, where the escapes can be
899 line_info = LineInfo(line)
897 line_info = LineInfo(line)
900
898
901 # If the escape is not at the start, only '?' needs to be special-cased.
899 # If the escape is not at the start, only '?' needs to be special-cased.
902 # All other escapes are only valid at the start
900 # All other escapes are only valid at the start
903 if not line_info.esc in self.tr:
901 if not line_info.esc in self.tr:
904 if line.endswith(ESC_HELP):
902 if line.endswith(ESC_HELP):
905 return self._tr_help(line_info)
903 return self._tr_help(line_info)
906 else:
904 else:
907 # If we don't recognize the escape, don't modify the line
905 # If we don't recognize the escape, don't modify the line
908 return line
906 return line
909
907
910 return self.tr[line_info.esc](line_info)
908 return self.tr[line_info.esc](line_info)
911
909
912
910
913 # A function-looking object to be used by the rest of the code. The purpose of
911 # A function-looking object to be used by the rest of the code. The purpose of
914 # the class in this case is to organize related functionality, more than to
912 # the class in this case is to organize related functionality, more than to
915 # manage state.
913 # manage state.
916 transform_escaped = EscapedTransformer()
914 transform_escaped = EscapedTransformer()
917
915
918
916
919 class IPythonInputSplitter(InputSplitter):
917 class IPythonInputSplitter(InputSplitter):
920 """An input splitter that recognizes all of IPython's special syntax."""
918 """An input splitter that recognizes all of IPython's special syntax."""
921
919
922 # String with raw, untransformed input.
920 # String with raw, untransformed input.
923 source_raw = ''
921 source_raw = ''
924
922
925 # Private attributes
923 # Private attributes
926
924
927 # List with lines of raw input accumulated so far.
925 # List with lines of raw input accumulated so far.
928 _buffer_raw = None
926 _buffer_raw = None
929
927
930 def __init__(self, input_mode=None):
928 def __init__(self, input_mode=None):
931 InputSplitter.__init__(self, input_mode)
929 InputSplitter.__init__(self, input_mode)
932 self._buffer_raw = []
930 self._buffer_raw = []
933
931
934 def reset(self):
932 def reset(self):
935 """Reset the input buffer and associated state."""
933 """Reset the input buffer and associated state."""
936 InputSplitter.reset(self)
934 InputSplitter.reset(self)
937 self._buffer_raw[:] = []
935 self._buffer_raw[:] = []
938 self.source_raw = ''
936 self.source_raw = ''
939
937
940 def source_raw_reset(self):
938 def source_raw_reset(self):
941 """Return input and raw source and perform a full reset.
939 """Return input and raw source and perform a full reset.
942 """
940 """
943 out = self.source
941 out = self.source
944 out_r = self.source_raw
942 out_r = self.source_raw
945 self.reset()
943 self.reset()
946 return out, out_r
944 return out, out_r
947
945
948 def push(self, lines):
946 def push(self, lines):
949 """Push one or more lines of IPython input.
947 """Push one or more lines of IPython input.
950 """
948 """
951 if not lines:
949 if not lines:
952 return super(IPythonInputSplitter, self).push(lines)
950 return super(IPythonInputSplitter, self).push(lines)
953
951
954 # We must ensure all input is pure unicode
952 # We must ensure all input is pure unicode
955 if type(lines)==str:
953 if type(lines)==str:
956 lines = lines.decode(self.encoding)
954 lines = lines.decode(self.encoding)
957
955
958 lines_list = lines.splitlines()
956 lines_list = lines.splitlines()
959
957
960 transforms = [transform_escaped, transform_assign_system,
958 transforms = [transform_escaped, transform_assign_system,
961 transform_assign_magic, transform_ipy_prompt,
959 transform_assign_magic, transform_ipy_prompt,
962 transform_classic_prompt]
960 transform_classic_prompt]
963
961
964 # Transform logic
962 # Transform logic
965 #
963 #
966 # We only apply the line transformers to the input if we have either no
964 # We only apply the line transformers to the input if we have either no
967 # input yet, or complete input, or if the last line of the buffer ends
965 # input yet, or complete input, or if the last line of the buffer ends
968 # with ':' (opening an indented block). This prevents the accidental
966 # with ':' (opening an indented block). This prevents the accidental
969 # transformation of escapes inside multiline expressions like
967 # transformation of escapes inside multiline expressions like
970 # triple-quoted strings or parenthesized expressions.
968 # triple-quoted strings or parenthesized expressions.
971 #
969 #
972 # The last heuristic, while ugly, ensures that the first line of an
970 # The last heuristic, while ugly, ensures that the first line of an
973 # indented block is correctly transformed.
971 # indented block is correctly transformed.
974 #
972 #
975 # FIXME: try to find a cleaner approach for this last bit.
973 # FIXME: try to find a cleaner approach for this last bit.
976
974
977 # If we were in 'block' mode, since we're going to pump the parent
975 # If we were in 'block' mode, since we're going to pump the parent
978 # class by hand line by line, we need to temporarily switch out to
976 # class by hand line by line, we need to temporarily switch out to
979 # 'line' mode, do a single manual reset and then feed the lines one
977 # 'line' mode, do a single manual reset and then feed the lines one
980 # by one. Note that this only matters if the input has more than one
978 # by one. Note that this only matters if the input has more than one
981 # line.
979 # line.
982 changed_input_mode = False
980 changed_input_mode = False
983
981
984 if self.input_mode == 'cell':
982 if self.input_mode == 'cell':
985 self.reset()
983 self.reset()
986 changed_input_mode = True
984 changed_input_mode = True
987 saved_input_mode = 'cell'
985 saved_input_mode = 'cell'
988 self.input_mode = 'line'
986 self.input_mode = 'line'
989
987
990 # Store raw source before applying any transformations to it. Note
988 # Store raw source before applying any transformations to it. Note
991 # that this must be done *after* the reset() call that would otherwise
989 # that this must be done *after* the reset() call that would otherwise
992 # flush the buffer.
990 # flush the buffer.
993 self._store(lines, self._buffer_raw, 'source_raw')
991 self._store(lines, self._buffer_raw, 'source_raw')
994
992
995 try:
993 try:
996 push = super(IPythonInputSplitter, self).push
994 push = super(IPythonInputSplitter, self).push
997 for line in lines_list:
995 for line in lines_list:
998 if self._is_complete or not self._buffer or \
996 if self._is_complete or not self._buffer or \
999 (self._buffer and self._buffer[-1].rstrip().endswith(':')):
997 (self._buffer and self._buffer[-1].rstrip().endswith(':')):
1000 for f in transforms:
998 for f in transforms:
1001 line = f(line)
999 line = f(line)
1002
1000
1003 out = push(line)
1001 out = push(line)
1004 finally:
1002 finally:
1005 if changed_input_mode:
1003 if changed_input_mode:
1006 self.input_mode = saved_input_mode
1004 self.input_mode = saved_input_mode
1007 return out
1005 return out
@@ -1,693 +1,693 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
28
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30 # Semi-complete examples (also used as tests)
30 # Semi-complete examples (also used as tests)
31 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
32
32
33 # Note: at the bottom, there's a slightly more complete version of this that
33 # Note: at the bottom, there's a slightly more complete version of this that
34 # can be useful during development of code here.
34 # can be useful during development of code here.
35
35
36 def mini_interactive_loop(input_func):
36 def mini_interactive_loop(input_func):
37 """Minimal example of the logic of an interactive interpreter loop.
37 """Minimal example of the logic of an interactive interpreter loop.
38
38
39 This serves as an example, and it is used by the test system with a fake
39 This serves as an example, and it is used by the test system with a fake
40 raw_input that simulates interactive input."""
40 raw_input that simulates interactive input."""
41
41
42 from IPython.core.inputsplitter import InputSplitter
42 from IPython.core.inputsplitter import InputSplitter
43
43
44 isp = InputSplitter()
44 isp = InputSplitter()
45 # In practice, this input loop would be wrapped in an outside loop to read
45 # In practice, this input loop would be wrapped in an outside loop to read
46 # input indefinitely, until some exit/quit command was issued. Here we
46 # input indefinitely, until some exit/quit command was issued. Here we
47 # only illustrate the basic inner loop.
47 # only illustrate the basic inner loop.
48 while isp.push_accepts_more():
48 while isp.push_accepts_more():
49 indent = ' '*isp.indent_spaces
49 indent = ' '*isp.indent_spaces
50 prompt = '>>> ' + indent
50 prompt = '>>> ' + indent
51 line = indent + input_func(prompt)
51 line = indent + input_func(prompt)
52 isp.push(line)
52 isp.push(line)
53
53
54 # Here we just return input so we can use it in a test suite, but a real
54 # Here we just return input so we can use it in a test suite, but a real
55 # interpreter would instead send it for execution somewhere.
55 # interpreter would instead send it for execution somewhere.
56 src = isp.source_reset()
56 src = isp.source_reset()
57 #print 'Input source was:\n', src # dbg
57 #print 'Input source was:\n', src # dbg
58 return src
58 return src
59
59
60 #-----------------------------------------------------------------------------
60 #-----------------------------------------------------------------------------
61 # Test utilities, just for local use
61 # Test utilities, just for local use
62 #-----------------------------------------------------------------------------
62 #-----------------------------------------------------------------------------
63
63
64 def assemble(block):
64 def assemble(block):
65 """Assemble a block into multi-line sub-blocks."""
65 """Assemble a block into multi-line sub-blocks."""
66 return ['\n'.join(sub_block)+'\n' for sub_block in block]
66 return ['\n'.join(sub_block)+'\n' for sub_block in block]
67
67
68
68
69 def pseudo_input(lines):
69 def pseudo_input(lines):
70 """Return a function that acts like raw_input but feeds the input list."""
70 """Return a function that acts like raw_input but feeds the input list."""
71 ilines = iter(lines)
71 ilines = iter(lines)
72 def raw_in(prompt):
72 def raw_in(prompt):
73 try:
73 try:
74 return next(ilines)
74 return next(ilines)
75 except StopIteration:
75 except StopIteration:
76 return ''
76 return ''
77 return raw_in
77 return raw_in
78
78
79 #-----------------------------------------------------------------------------
79 #-----------------------------------------------------------------------------
80 # Tests
80 # Tests
81 #-----------------------------------------------------------------------------
81 #-----------------------------------------------------------------------------
82 def test_spaces():
82 def test_spaces():
83 tests = [('', 0),
83 tests = [('', 0),
84 (' ', 1),
84 (' ', 1),
85 ('\n', 0),
85 ('\n', 0),
86 (' \n', 1),
86 (' \n', 1),
87 ('x', 0),
87 ('x', 0),
88 (' x', 1),
88 (' x', 1),
89 (' x',2),
89 (' x',2),
90 (' x',4),
90 (' x',4),
91 # Note: tabs are counted as a single whitespace!
91 # Note: tabs are counted as a single whitespace!
92 ('\tx', 1),
92 ('\tx', 1),
93 ('\t x', 2),
93 ('\t x', 2),
94 ]
94 ]
95
95
96 for s, nsp in tests:
96 for s, nsp in tests:
97 nt.assert_equal(isp.num_ini_spaces(s), nsp)
97 nt.assert_equal(isp.num_ini_spaces(s), nsp)
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
109
110 for inp, out in tests:
110 for inp, out in tests:
111 nt.assert_equal(isp.remove_comments(inp), out)
111 nt.assert_equal(isp.remove_comments(inp), out)
112
112
113
113
114 def test_get_input_encoding():
114 def test_get_input_encoding():
115 encoding = isp.get_input_encoding()
115 encoding = isp.get_input_encoding()
116 nt.assert_true(isinstance(encoding, basestring))
116 nt.assert_true(isinstance(encoding, basestring))
117 # simple-minded check that at least encoding a simple string works with the
117 # simple-minded check that at least encoding a simple string works with the
118 # encoding we got.
118 # encoding we got.
119 nt.assert_equal('test'.encode(encoding), 'test')
119 nt.assert_equal('test'.encode(encoding), 'test')
120
120
121
121
122 class NoInputEncodingTestCase(unittest.TestCase):
122 class NoInputEncodingTestCase(unittest.TestCase):
123 def setUp(self):
123 def setUp(self):
124 self.old_stdin = sys.stdin
124 self.old_stdin = sys.stdin
125 class X: pass
125 class X: pass
126 fake_stdin = X()
126 fake_stdin = X()
127 sys.stdin = fake_stdin
127 sys.stdin = fake_stdin
128
128
129 def test(self):
129 def test(self):
130 # Verify that if sys.stdin has no 'encoding' attribute we do the right
130 # Verify that if sys.stdin has no 'encoding' attribute we do the right
131 # thing
131 # thing
132 enc = isp.get_input_encoding()
132 enc = isp.get_input_encoding()
133 self.assertEqual(enc, 'ascii')
133 self.assertEqual(enc, 'ascii')
134
134
135 def tearDown(self):
135 def tearDown(self):
136 sys.stdin = self.old_stdin
136 sys.stdin = self.old_stdin
137
137
138
138
139 class InputSplitterTestCase(unittest.TestCase):
139 class InputSplitterTestCase(unittest.TestCase):
140 def setUp(self):
140 def setUp(self):
141 self.isp = isp.InputSplitter()
141 self.isp = isp.InputSplitter()
142
142
143 def test_reset(self):
143 def test_reset(self):
144 isp = self.isp
144 isp = self.isp
145 isp.push('x=1')
145 isp.push('x=1')
146 isp.reset()
146 isp.reset()
147 self.assertEqual(isp._buffer, [])
147 self.assertEqual(isp._buffer, [])
148 self.assertEqual(isp.indent_spaces, 0)
148 self.assertEqual(isp.indent_spaces, 0)
149 self.assertEqual(isp.source, '')
149 self.assertEqual(isp.source, '')
150 self.assertEqual(isp.code, None)
150 self.assertEqual(isp.code, None)
151 self.assertEqual(isp._is_complete, False)
151 self.assertEqual(isp._is_complete, False)
152
152
153 def test_source(self):
153 def test_source(self):
154 self.isp._store('1')
154 self.isp._store('1')
155 self.isp._store('2')
155 self.isp._store('2')
156 self.assertEqual(self.isp.source, '1\n2\n')
156 self.assertEqual(self.isp.source, '1\n2\n')
157 self.assertTrue(len(self.isp._buffer)>0)
157 self.assertTrue(len(self.isp._buffer)>0)
158 self.assertEqual(self.isp.source_reset(), '1\n2\n')
158 self.assertEqual(self.isp.source_reset(), '1\n2\n')
159 self.assertEqual(self.isp._buffer, [])
159 self.assertEqual(self.isp._buffer, [])
160 self.assertEqual(self.isp.source, '')
160 self.assertEqual(self.isp.source, '')
161
161
162 def test_indent(self):
162 def test_indent(self):
163 isp = self.isp # shorthand
163 isp = self.isp # shorthand
164 isp.push('x=1')
164 isp.push('x=1')
165 self.assertEqual(isp.indent_spaces, 0)
165 self.assertEqual(isp.indent_spaces, 0)
166 isp.push('if 1:\n x=1')
166 isp.push('if 1:\n x=1')
167 self.assertEqual(isp.indent_spaces, 4)
167 self.assertEqual(isp.indent_spaces, 4)
168 isp.push('y=2\n')
168 isp.push('y=2\n')
169 self.assertEqual(isp.indent_spaces, 0)
169 self.assertEqual(isp.indent_spaces, 0)
170
170
171 def test_indent2(self):
171 def test_indent2(self):
172 # In cell mode, inputs must be fed in whole blocks, so skip this test
172 # In cell mode, inputs must be fed in whole blocks, so skip this test
173 if self.isp.input_mode == 'cell': return
173 if self.isp.input_mode == 'cell': return
174
174
175 isp = self.isp
175 isp = self.isp
176 isp.push('if 1:')
176 isp.push('if 1:')
177 self.assertEqual(isp.indent_spaces, 4)
177 self.assertEqual(isp.indent_spaces, 4)
178 isp.push(' x=1')
178 isp.push(' x=1')
179 self.assertEqual(isp.indent_spaces, 4)
179 self.assertEqual(isp.indent_spaces, 4)
180 # Blank lines shouldn't change the indent level
180 # Blank lines shouldn't change the indent level
181 isp.push(' '*2)
181 isp.push(' '*2)
182 self.assertEqual(isp.indent_spaces, 4)
182 self.assertEqual(isp.indent_spaces, 4)
183
183
184 def test_indent3(self):
184 def test_indent3(self):
185 # In cell mode, inputs must be fed in whole blocks, so skip this test
185 # In cell mode, inputs must be fed in whole blocks, so skip this test
186 if self.isp.input_mode == 'cell': return
186 if self.isp.input_mode == 'cell': return
187
187
188 isp = self.isp
188 isp = self.isp
189 # When a multiline statement contains parens or multiline strings, we
189 # When a multiline statement contains parens or multiline strings, we
190 # shouldn't get confused.
190 # shouldn't get confused.
191 isp.push("if 1:")
191 isp.push("if 1:")
192 isp.push(" x = (1+\n 2)")
192 isp.push(" x = (1+\n 2)")
193 self.assertEqual(isp.indent_spaces, 4)
193 self.assertEqual(isp.indent_spaces, 4)
194
194
195 def test_dedent(self):
195 def test_dedent(self):
196 isp = self.isp # shorthand
196 isp = self.isp # shorthand
197 isp.push('if 1:')
197 isp.push('if 1:')
198 self.assertEqual(isp.indent_spaces, 4)
198 self.assertEqual(isp.indent_spaces, 4)
199 isp.push(' pass')
199 isp.push(' pass')
200 self.assertEqual(isp.indent_spaces, 0)
200 self.assertEqual(isp.indent_spaces, 0)
201
201
202 def test_push(self):
202 def test_push(self):
203 isp = self.isp
203 isp = self.isp
204 self.assertTrue(isp.push('x=1'))
204 self.assertTrue(isp.push('x=1'))
205
205
206 def test_push2(self):
206 def test_push2(self):
207 isp = self.isp
207 isp = self.isp
208 self.assertFalse(isp.push('if 1:'))
208 self.assertFalse(isp.push('if 1:'))
209 for line in [' x=1', '# a comment', ' y=2']:
209 for line in [' x=1', '# a comment', ' y=2']:
210 self.assertTrue(isp.push(line))
210 self.assertTrue(isp.push(line))
211
211
212 def test_replace_mode(self):
212 def test_replace_mode(self):
213 isp = self.isp
213 isp = self.isp
214 isp.input_mode = 'cell'
214 isp.input_mode = 'cell'
215 isp.push('x=1')
215 isp.push('x=1')
216 self.assertEqual(isp.source, 'x=1\n')
216 self.assertEqual(isp.source, 'x=1\n')
217 isp.push('x=2')
217 isp.push('x=2')
218 self.assertEqual(isp.source, 'x=2\n')
218 self.assertEqual(isp.source, 'x=2\n')
219
219
220 def test_push_accepts_more(self):
220 def test_push_accepts_more(self):
221 isp = self.isp
221 isp = self.isp
222 isp.push('x=1')
222 isp.push('x=1')
223 self.assertFalse(isp.push_accepts_more())
223 self.assertFalse(isp.push_accepts_more())
224
224
225 def test_push_accepts_more2(self):
225 def test_push_accepts_more2(self):
226 # In cell mode, inputs must be fed in whole blocks, so skip this test
226 # In cell mode, inputs must be fed in whole blocks, so skip this test
227 if self.isp.input_mode == 'cell': return
227 if self.isp.input_mode == 'cell': return
228
228
229 isp = self.isp
229 isp = self.isp
230 isp.push('if 1:')
230 isp.push('if 1:')
231 self.assertTrue(isp.push_accepts_more())
231 self.assertTrue(isp.push_accepts_more())
232 isp.push(' x=1')
232 isp.push(' x=1')
233 self.assertTrue(isp.push_accepts_more())
233 self.assertTrue(isp.push_accepts_more())
234 isp.push('')
234 isp.push('')
235 self.assertFalse(isp.push_accepts_more())
235 self.assertFalse(isp.push_accepts_more())
236
236
237 def test_push_accepts_more3(self):
237 def test_push_accepts_more3(self):
238 isp = self.isp
238 isp = self.isp
239 isp.push("x = (2+\n3)")
239 isp.push("x = (2+\n3)")
240 self.assertFalse(isp.push_accepts_more())
240 self.assertFalse(isp.push_accepts_more())
241
241
242 def test_push_accepts_more4(self):
242 def test_push_accepts_more4(self):
243 # In cell mode, inputs must be fed in whole blocks, so skip this test
243 # In cell mode, inputs must be fed in whole blocks, so skip this test
244 if self.isp.input_mode == 'cell': return
244 if self.isp.input_mode == 'cell': return
245
245
246 isp = self.isp
246 isp = self.isp
247 # When a multiline statement contains parens or multiline strings, we
247 # When a multiline statement contains parens or multiline strings, we
248 # shouldn't get confused.
248 # shouldn't get confused.
249 # FIXME: we should be able to better handle de-dents in statements like
249 # FIXME: we should be able to better handle de-dents in statements like
250 # multiline strings and multiline expressions (continued with \ or
250 # multiline strings and multiline expressions (continued with \ or
251 # parens). Right now we aren't handling the indentation tracking quite
251 # parens). Right now we aren't handling the indentation tracking quite
252 # correctly with this, though in practice it may not be too much of a
252 # correctly with this, though in practice it may not be too much of a
253 # problem. We'll need to see.
253 # problem. We'll need to see.
254 isp.push("if 1:")
254 isp.push("if 1:")
255 isp.push(" x = (2+")
255 isp.push(" x = (2+")
256 isp.push(" 3)")
256 isp.push(" 3)")
257 self.assertTrue(isp.push_accepts_more())
257 self.assertTrue(isp.push_accepts_more())
258 isp.push(" y = 3")
258 isp.push(" y = 3")
259 self.assertTrue(isp.push_accepts_more())
259 self.assertTrue(isp.push_accepts_more())
260 isp.push('')
260 isp.push('')
261 self.assertFalse(isp.push_accepts_more())
261 self.assertFalse(isp.push_accepts_more())
262
262
263 def test_continuation(self):
263 def test_continuation(self):
264 isp = self.isp
264 isp = self.isp
265 isp.push("import os, \\")
265 isp.push("import os, \\")
266 self.assertTrue(isp.push_accepts_more())
266 self.assertTrue(isp.push_accepts_more())
267 isp.push("sys")
267 isp.push("sys")
268 self.assertFalse(isp.push_accepts_more())
268 self.assertFalse(isp.push_accepts_more())
269
269
270 def test_syntax_error(self):
270 def test_syntax_error(self):
271 isp = self.isp
271 isp = self.isp
272 # Syntax errors immediately produce a 'ready' block, so the invalid
272 # Syntax errors immediately produce a 'ready' block, so the invalid
273 # Python can be sent to the kernel for evaluation with possible ipython
273 # Python can be sent to the kernel for evaluation with possible ipython
274 # special-syntax conversion.
274 # special-syntax conversion.
275 isp.push('run foo')
275 isp.push('run foo')
276 self.assertFalse(isp.push_accepts_more())
276 self.assertFalse(isp.push_accepts_more())
277
277
278 def check_split(self, block_lines, compile=True):
278 def check_split(self, block_lines, compile=True):
279 blocks = assemble(block_lines)
279 blocks = assemble(block_lines)
280 lines = ''.join(blocks)
280 lines = ''.join(blocks)
281 oblock = self.isp.split_blocks(lines)
281 oblock = self.isp.split_blocks(lines)
282 self.assertEqual(oblock, blocks)
282 self.assertEqual(oblock, blocks)
283 if compile:
283 if compile:
284 for block in blocks:
284 for block in blocks:
285 self.isp._compile(block)
285 self.isp._compile(block)
286
286
287 def test_split(self):
287 def test_split(self):
288 # All blocks of input we want to test in a list. The format for each
288 # All blocks of input we want to test in a list. The format for each
289 # block is a list of lists, with each inner lists consisting of all the
289 # block is a list of lists, with each inner lists consisting of all the
290 # lines (as single-lines) that should make up a sub-block.
290 # lines (as single-lines) that should make up a sub-block.
291
291
292 # Note: do NOT put here sub-blocks that don't compile, as the
292 # Note: do NOT put here sub-blocks that don't compile, as the
293 # check_split() routine makes a final verification pass to check that
293 # check_split() routine makes a final verification pass to check that
294 # each sub_block, as returned by split_blocks(), does compile
294 # each sub_block, as returned by split_blocks(), does compile
295 # correctly.
295 # correctly.
296 all_blocks = [ [['x=1']],
296 all_blocks = [ [['x=1']],
297
297
298 [['x=1'],
298 [['x=1'],
299 ['y=2']],
299 ['y=2']],
300
300
301 [['x=1',
301 [['x=1',
302 '# a comment'],
302 '# a comment'],
303 ['y=11']],
303 ['y=11']],
304
304
305 [['if 1:',
305 [['if 1:',
306 ' x=1'],
306 ' x=1'],
307 ['y=3']],
307 ['y=3']],
308
308
309 [['def f(x):',
309 [['def f(x):',
310 ' return x'],
310 ' return x'],
311 ['x=1']],
311 ['x=1']],
312
312
313 [['def f(x):',
313 [['def f(x):',
314 ' x+=1',
314 ' x+=1',
315 ' ',
315 ' ',
316 ' return x'],
316 ' return x'],
317 ['x=1']],
317 ['x=1']],
318
318
319 [['def f(x):',
319 [['def f(x):',
320 ' if x>0:',
320 ' if x>0:',
321 ' y=1',
321 ' y=1',
322 ' # a comment',
322 ' # a comment',
323 ' else:',
323 ' else:',
324 ' y=4',
324 ' y=4',
325 ' ',
325 ' ',
326 ' return y'],
326 ' return y'],
327 ['x=1'],
327 ['x=1'],
328 ['if 1:',
328 ['if 1:',
329 ' y=11'] ],
329 ' y=11'] ],
330
330
331 [['for i in range(10):'
331 [['for i in range(10):'
332 ' x=i**2']],
332 ' x=i**2']],
333
333
334 [['for i in range(10):'
334 [['for i in range(10):'
335 ' x=i**2'],
335 ' x=i**2'],
336 ['z = 1']],
336 ['z = 1']],
337
337
338 [['"asdf"']],
338 [['"asdf"']],
339
339
340 [['"asdf"'],
340 [['"asdf"'],
341 ['10'],
341 ['10'],
342 ],
342 ],
343
343
344 [['"""foo',
344 [['"""foo',
345 'bar"""']],
345 'bar"""']],
346 ]
346 ]
347 for block_lines in all_blocks:
347 for block_lines in all_blocks:
348 self.check_split(block_lines)
348 self.check_split(block_lines)
349
349
350 def test_split_syntax_errors(self):
350 def test_split_syntax_errors(self):
351 # Block splitting with invalid syntax
351 # Block splitting with invalid syntax
352 all_blocks = [ [['a syntax error']],
352 all_blocks = [ [['a syntax error']],
353
353
354 [['x=1',
354 [['x=1',
355 'another syntax error']],
355 'another syntax error']],
356
356
357 [['for i in range(10):'
357 [['for i in range(10):'
358 ' yet another error']],
358 ' yet another error']],
359
359
360 ]
360 ]
361 for block_lines in all_blocks:
361 for block_lines in all_blocks:
362 self.check_split(block_lines, compile=False)
362 self.check_split(block_lines, compile=False)
363
363
364 def test_unicode(self):
364 def test_unicode(self):
365 self.isp.push(u"PΓ©rez")
365 self.isp.push(u"PΓ©rez")
366 self.isp.push(u'\xc3\xa9')
366 self.isp.push(u'\xc3\xa9')
367 self.isp.push("u'\xc3\xa9'")
367 self.isp.push(u"u'\xc3\xa9'")
368
368
369 class InteractiveLoopTestCase(unittest.TestCase):
369 class InteractiveLoopTestCase(unittest.TestCase):
370 """Tests for an interactive loop like a python shell.
370 """Tests for an interactive loop like a python shell.
371 """
371 """
372 def check_ns(self, lines, ns):
372 def check_ns(self, lines, ns):
373 """Validate that the given input lines produce the resulting namespace.
373 """Validate that the given input lines produce the resulting namespace.
374
374
375 Note: the input lines are given exactly as they would be typed in an
375 Note: the input lines are given exactly as they would be typed in an
376 auto-indenting environment, as mini_interactive_loop above already does
376 auto-indenting environment, as mini_interactive_loop above already does
377 auto-indenting and prepends spaces to the input.
377 auto-indenting and prepends spaces to the input.
378 """
378 """
379 src = mini_interactive_loop(pseudo_input(lines))
379 src = mini_interactive_loop(pseudo_input(lines))
380 test_ns = {}
380 test_ns = {}
381 exec src in test_ns
381 exec src in test_ns
382 # We can't check that the provided ns is identical to the test_ns,
382 # We can't check that the provided ns is identical to the test_ns,
383 # because Python fills test_ns with extra keys (copyright, etc). But
383 # because Python fills test_ns with extra keys (copyright, etc). But
384 # we can check that the given dict is *contained* in test_ns
384 # we can check that the given dict is *contained* in test_ns
385 for k,v in ns.iteritems():
385 for k,v in ns.iteritems():
386 self.assertEqual(test_ns[k], v)
386 self.assertEqual(test_ns[k], v)
387
387
388 def test_simple(self):
388 def test_simple(self):
389 self.check_ns(['x=1'], dict(x=1))
389 self.check_ns(['x=1'], dict(x=1))
390
390
391 def test_simple2(self):
391 def test_simple2(self):
392 self.check_ns(['if 1:', 'x=2'], dict(x=2))
392 self.check_ns(['if 1:', 'x=2'], dict(x=2))
393
393
394 def test_xy(self):
394 def test_xy(self):
395 self.check_ns(['x=1; y=2'], dict(x=1, y=2))
395 self.check_ns(['x=1; y=2'], dict(x=1, y=2))
396
396
397 def test_abc(self):
397 def test_abc(self):
398 self.check_ns(['if 1:','a=1','b=2','c=3'], dict(a=1, b=2, c=3))
398 self.check_ns(['if 1:','a=1','b=2','c=3'], dict(a=1, b=2, c=3))
399
399
400 def test_multi(self):
400 def test_multi(self):
401 self.check_ns(['x =(1+','1+','2)'], dict(x=4))
401 self.check_ns(['x =(1+','1+','2)'], dict(x=4))
402
402
403
403
404 def test_LineInfo():
404 def test_LineInfo():
405 """Simple test for LineInfo construction and str()"""
405 """Simple test for LineInfo construction and str()"""
406 linfo = isp.LineInfo(' %cd /home')
406 linfo = isp.LineInfo(' %cd /home')
407 nt.assert_equals(str(linfo), 'LineInfo [ |%|cd|/home]')
407 nt.assert_equals(str(linfo), 'LineInfo [ |%|cd|/home]')
408
408
409
409
410 def test_split_user_input():
410 def test_split_user_input():
411 """Unicode test - split_user_input already has good doctests"""
411 """Unicode test - split_user_input already has good doctests"""
412 line = u"PΓ©rez Fernando"
412 line = u"PΓ©rez Fernando"
413 parts = isp.split_user_input(line)
413 parts = isp.split_user_input(line)
414 parts_expected = (u'', u'', u'', line)
414 parts_expected = (u'', u'', u'', line)
415 nt.assert_equal(parts, parts_expected)
415 nt.assert_equal(parts, parts_expected)
416
416
417
417
418 # Transformer tests
418 # Transformer tests
419 def transform_checker(tests, func):
419 def transform_checker(tests, func):
420 """Utility to loop over test inputs"""
420 """Utility to loop over test inputs"""
421 for inp, tr in tests:
421 for inp, tr in tests:
422 nt.assert_equals(func(inp), tr)
422 nt.assert_equals(func(inp), tr)
423
423
424 # Data for all the syntax tests in the form of lists of pairs of
424 # Data for all the syntax tests in the form of lists of pairs of
425 # raw/transformed input. We store it here as a global dict so that we can use
425 # raw/transformed input. We store it here as a global dict so that we can use
426 # it both within single-function tests and also to validate the behavior of the
426 # it both within single-function tests and also to validate the behavior of the
427 # larger objects
427 # larger objects
428
428
429 syntax = \
429 syntax = \
430 dict(assign_system =
430 dict(assign_system =
431 [('a =! ls', 'a = get_ipython().getoutput("ls")'),
431 [('a =! ls', 'a = get_ipython().getoutput("ls")'),
432 ('b = !ls', 'b = get_ipython().getoutput("ls")'),
432 ('b = !ls', 'b = get_ipython().getoutput("ls")'),
433 ('x=1', 'x=1'), # normal input is unmodified
433 ('x=1', 'x=1'), # normal input is unmodified
434 (' ',' '), # blank lines are kept intact
434 (' ',' '), # blank lines are kept intact
435 ],
435 ],
436
436
437 assign_magic =
437 assign_magic =
438 [('a =% who', 'a = get_ipython().magic("who")'),
438 [('a =% who', 'a = get_ipython().magic("who")'),
439 ('b = %who', 'b = get_ipython().magic("who")'),
439 ('b = %who', 'b = get_ipython().magic("who")'),
440 ('x=1', 'x=1'), # normal input is unmodified
440 ('x=1', 'x=1'), # normal input is unmodified
441 (' ',' '), # blank lines are kept intact
441 (' ',' '), # blank lines are kept intact
442 ],
442 ],
443
443
444 classic_prompt =
444 classic_prompt =
445 [('>>> x=1', 'x=1'),
445 [('>>> x=1', 'x=1'),
446 ('x=1', 'x=1'), # normal input is unmodified
446 ('x=1', 'x=1'), # normal input is unmodified
447 (' ', ' '), # blank lines are kept intact
447 (' ', ' '), # blank lines are kept intact
448 ('... ', ''), # continuation prompts
448 ('... ', ''), # continuation prompts
449 ],
449 ],
450
450
451 ipy_prompt =
451 ipy_prompt =
452 [('In [1]: x=1', 'x=1'),
452 [('In [1]: x=1', 'x=1'),
453 ('x=1', 'x=1'), # normal input is unmodified
453 ('x=1', 'x=1'), # normal input is unmodified
454 (' ',' '), # blank lines are kept intact
454 (' ',' '), # blank lines are kept intact
455 (' ....: ', ''), # continuation prompts
455 (' ....: ', ''), # continuation prompts
456 ],
456 ],
457
457
458 # Tests for the escape transformer to leave normal code alone
458 # Tests for the escape transformer to leave normal code alone
459 escaped_noesc =
459 escaped_noesc =
460 [ (' ', ' '),
460 [ (' ', ' '),
461 ('x=1', 'x=1'),
461 ('x=1', 'x=1'),
462 ],
462 ],
463
463
464 # System calls
464 # System calls
465 escaped_shell =
465 escaped_shell =
466 [ ('!ls', 'get_ipython().system("ls")'),
466 [ ('!ls', 'get_ipython().system("ls")'),
467 # Double-escape shell, this means to capture the output of the
467 # Double-escape shell, this means to capture the output of the
468 # subprocess and return it
468 # subprocess and return it
469 ('!!ls', 'get_ipython().getoutput("ls")'),
469 ('!!ls', 'get_ipython().getoutput("ls")'),
470 ],
470 ],
471
471
472 # Help/object info
472 # Help/object info
473 escaped_help =
473 escaped_help =
474 [ ('?', 'get_ipython().show_usage()'),
474 [ ('?', 'get_ipython().show_usage()'),
475 ('?x1', 'get_ipython().magic("pinfo x1")'),
475 ('?x1', 'get_ipython().magic("pinfo x1")'),
476 ('??x2', 'get_ipython().magic("pinfo2 x2")'),
476 ('??x2', 'get_ipython().magic("pinfo2 x2")'),
477 ('x3?', 'get_ipython().magic("pinfo x3")'),
477 ('x3?', 'get_ipython().magic("pinfo x3")'),
478 ('x4??', 'get_ipython().magic("pinfo2 x4")'),
478 ('x4??', 'get_ipython().magic("pinfo2 x4")'),
479 ('%hist?', 'get_ipython().magic("pinfo %hist")'),
479 ('%hist?', 'get_ipython().magic("pinfo %hist")'),
480 ('f*?', 'get_ipython().magic("psearch f*")'),
480 ('f*?', 'get_ipython().magic("psearch f*")'),
481 ('ax.*aspe*?', 'get_ipython().magic("psearch ax.*aspe*")'),
481 ('ax.*aspe*?', 'get_ipython().magic("psearch ax.*aspe*")'),
482 ],
482 ],
483
483
484 # Explicit magic calls
484 # Explicit magic calls
485 escaped_magic =
485 escaped_magic =
486 [ ('%cd', 'get_ipython().magic("cd")'),
486 [ ('%cd', 'get_ipython().magic("cd")'),
487 ('%cd /home', 'get_ipython().magic("cd /home")'),
487 ('%cd /home', 'get_ipython().magic("cd /home")'),
488 (' %magic', ' get_ipython().magic("magic")'),
488 (' %magic', ' get_ipython().magic("magic")'),
489 ],
489 ],
490
490
491 # Quoting with separate arguments
491 # Quoting with separate arguments
492 escaped_quote =
492 escaped_quote =
493 [ (',f', 'f("")'),
493 [ (',f', 'f("")'),
494 (',f x', 'f("x")'),
494 (',f x', 'f("x")'),
495 (' ,f y', ' f("y")'),
495 (' ,f y', ' f("y")'),
496 (',f a b', 'f("a", "b")'),
496 (',f a b', 'f("a", "b")'),
497 ],
497 ],
498
498
499 # Quoting with single argument
499 # Quoting with single argument
500 escaped_quote2 =
500 escaped_quote2 =
501 [ (';f', 'f("")'),
501 [ (';f', 'f("")'),
502 (';f x', 'f("x")'),
502 (';f x', 'f("x")'),
503 (' ;f y', ' f("y")'),
503 (' ;f y', ' f("y")'),
504 (';f a b', 'f("a b")'),
504 (';f a b', 'f("a b")'),
505 ],
505 ],
506
506
507 # Simply apply parens
507 # Simply apply parens
508 escaped_paren =
508 escaped_paren =
509 [ ('/f', 'f()'),
509 [ ('/f', 'f()'),
510 ('/f x', 'f(x)'),
510 ('/f x', 'f(x)'),
511 (' /f y', ' f(y)'),
511 (' /f y', ' f(y)'),
512 ('/f a b', 'f(a, b)'),
512 ('/f a b', 'f(a, b)'),
513 ],
513 ],
514
514
515 )
515 )
516
516
517 # multiline syntax examples. Each of these should be a list of lists, with
517 # multiline syntax examples. Each of these should be a list of lists, with
518 # each entry itself having pairs of raw/transformed input. The union (with
518 # each entry itself having pairs of raw/transformed input. The union (with
519 # '\n'.join() of the transformed inputs is what the splitter should produce
519 # '\n'.join() of the transformed inputs is what the splitter should produce
520 # when fed the raw lines one at a time via push.
520 # when fed the raw lines one at a time via push.
521 syntax_ml = \
521 syntax_ml = \
522 dict(classic_prompt =
522 dict(classic_prompt =
523 [ [('>>> for i in range(10):','for i in range(10):'),
523 [ [('>>> for i in range(10):','for i in range(10):'),
524 ('... print i',' print i'),
524 ('... print i',' print i'),
525 ('... ', ''),
525 ('... ', ''),
526 ],
526 ],
527 ],
527 ],
528
528
529 ipy_prompt =
529 ipy_prompt =
530 [ [('In [24]: for i in range(10):','for i in range(10):'),
530 [ [('In [24]: for i in range(10):','for i in range(10):'),
531 (' ....: print i',' print i'),
531 (' ....: print i',' print i'),
532 (' ....: ', ''),
532 (' ....: ', ''),
533 ],
533 ],
534 ],
534 ],
535 )
535 )
536
536
537
537
538 def test_assign_system():
538 def test_assign_system():
539 transform_checker(syntax['assign_system'], isp.transform_assign_system)
539 transform_checker(syntax['assign_system'], isp.transform_assign_system)
540
540
541
541
542 def test_assign_magic():
542 def test_assign_magic():
543 transform_checker(syntax['assign_magic'], isp.transform_assign_magic)
543 transform_checker(syntax['assign_magic'], isp.transform_assign_magic)
544
544
545
545
546 def test_classic_prompt():
546 def test_classic_prompt():
547 transform_checker(syntax['classic_prompt'], isp.transform_classic_prompt)
547 transform_checker(syntax['classic_prompt'], isp.transform_classic_prompt)
548 for example in syntax_ml['classic_prompt']:
548 for example in syntax_ml['classic_prompt']:
549 transform_checker(example, isp.transform_classic_prompt)
549 transform_checker(example, isp.transform_classic_prompt)
550
550
551
551
552 def test_ipy_prompt():
552 def test_ipy_prompt():
553 transform_checker(syntax['ipy_prompt'], isp.transform_ipy_prompt)
553 transform_checker(syntax['ipy_prompt'], isp.transform_ipy_prompt)
554 for example in syntax_ml['ipy_prompt']:
554 for example in syntax_ml['ipy_prompt']:
555 transform_checker(example, isp.transform_ipy_prompt)
555 transform_checker(example, isp.transform_ipy_prompt)
556
556
557
557
558 def test_escaped_noesc():
558 def test_escaped_noesc():
559 transform_checker(syntax['escaped_noesc'], isp.transform_escaped)
559 transform_checker(syntax['escaped_noesc'], isp.transform_escaped)
560
560
561
561
562 def test_escaped_shell():
562 def test_escaped_shell():
563 transform_checker(syntax['escaped_shell'], isp.transform_escaped)
563 transform_checker(syntax['escaped_shell'], isp.transform_escaped)
564
564
565
565
566 def test_escaped_help():
566 def test_escaped_help():
567 transform_checker(syntax['escaped_help'], isp.transform_escaped)
567 transform_checker(syntax['escaped_help'], isp.transform_escaped)
568
568
569
569
570 def test_escaped_magic():
570 def test_escaped_magic():
571 transform_checker(syntax['escaped_magic'], isp.transform_escaped)
571 transform_checker(syntax['escaped_magic'], isp.transform_escaped)
572
572
573
573
574 def test_escaped_quote():
574 def test_escaped_quote():
575 transform_checker(syntax['escaped_quote'], isp.transform_escaped)
575 transform_checker(syntax['escaped_quote'], isp.transform_escaped)
576
576
577
577
578 def test_escaped_quote2():
578 def test_escaped_quote2():
579 transform_checker(syntax['escaped_quote2'], isp.transform_escaped)
579 transform_checker(syntax['escaped_quote2'], isp.transform_escaped)
580
580
581
581
582 def test_escaped_paren():
582 def test_escaped_paren():
583 transform_checker(syntax['escaped_paren'], isp.transform_escaped)
583 transform_checker(syntax['escaped_paren'], isp.transform_escaped)
584
584
585
585
586 class IPythonInputTestCase(InputSplitterTestCase):
586 class IPythonInputTestCase(InputSplitterTestCase):
587 """By just creating a new class whose .isp is a different instance, we
587 """By just creating a new class whose .isp is a different instance, we
588 re-run the same test battery on the new input splitter.
588 re-run the same test battery on the new input splitter.
589
589
590 In addition, this runs the tests over the syntax and syntax_ml dicts that
590 In addition, this runs the tests over the syntax and syntax_ml dicts that
591 were tested by individual functions, as part of the OO interface.
591 were tested by individual functions, as part of the OO interface.
592
592
593 It also makes some checks on the raw buffer storage.
593 It also makes some checks on the raw buffer storage.
594 """
594 """
595
595
596 def setUp(self):
596 def setUp(self):
597 self.isp = isp.IPythonInputSplitter(input_mode='line')
597 self.isp = isp.IPythonInputSplitter(input_mode='line')
598
598
599 def test_syntax(self):
599 def test_syntax(self):
600 """Call all single-line syntax tests from the main object"""
600 """Call all single-line syntax tests from the main object"""
601 isp = self.isp
601 isp = self.isp
602 for example in syntax.itervalues():
602 for example in syntax.itervalues():
603 for raw, out_t in example:
603 for raw, out_t in example:
604 if raw.startswith(' '):
604 if raw.startswith(' '):
605 continue
605 continue
606
606
607 isp.push(raw)
607 isp.push(raw)
608 out, out_raw = isp.source_raw_reset()
608 out, out_raw = isp.source_raw_reset()
609 self.assertEqual(out.rstrip(), out_t)
609 self.assertEqual(out.rstrip(), out_t)
610 self.assertEqual(out_raw.rstrip(), raw.rstrip())
610 self.assertEqual(out_raw.rstrip(), raw.rstrip())
611
611
612 def test_syntax_multiline(self):
612 def test_syntax_multiline(self):
613 isp = self.isp
613 isp = self.isp
614 for example in syntax_ml.itervalues():
614 for example in syntax_ml.itervalues():
615 out_t_parts = []
615 out_t_parts = []
616 raw_parts = []
616 raw_parts = []
617 for line_pairs in example:
617 for line_pairs in example:
618 for lraw, out_t_part in line_pairs:
618 for lraw, out_t_part in line_pairs:
619 isp.push(lraw)
619 isp.push(lraw)
620 out_t_parts.append(out_t_part)
620 out_t_parts.append(out_t_part)
621 raw_parts.append(lraw)
621 raw_parts.append(lraw)
622
622
623 out, out_raw = isp.source_raw_reset()
623 out, out_raw = isp.source_raw_reset()
624 out_t = '\n'.join(out_t_parts).rstrip()
624 out_t = '\n'.join(out_t_parts).rstrip()
625 raw = '\n'.join(raw_parts).rstrip()
625 raw = '\n'.join(raw_parts).rstrip()
626 self.assertEqual(out.rstrip(), out_t)
626 self.assertEqual(out.rstrip(), out_t)
627 self.assertEqual(out_raw.rstrip(), raw)
627 self.assertEqual(out_raw.rstrip(), raw)
628
628
629
629
630 class BlockIPythonInputTestCase(IPythonInputTestCase):
630 class BlockIPythonInputTestCase(IPythonInputTestCase):
631
631
632 # Deactivate tests that don't make sense for the block mode
632 # Deactivate tests that don't make sense for the block mode
633 test_push3 = test_split = lambda s: None
633 test_push3 = test_split = lambda s: None
634
634
635 def setUp(self):
635 def setUp(self):
636 self.isp = isp.IPythonInputSplitter(input_mode='cell')
636 self.isp = isp.IPythonInputSplitter(input_mode='cell')
637
637
638 def test_syntax_multiline(self):
638 def test_syntax_multiline(self):
639 isp = self.isp
639 isp = self.isp
640 for example in syntax_ml.itervalues():
640 for example in syntax_ml.itervalues():
641 raw_parts = []
641 raw_parts = []
642 out_t_parts = []
642 out_t_parts = []
643 for line_pairs in example:
643 for line_pairs in example:
644 for raw, out_t_part in line_pairs:
644 for raw, out_t_part in line_pairs:
645 raw_parts.append(raw)
645 raw_parts.append(raw)
646 out_t_parts.append(out_t_part)
646 out_t_parts.append(out_t_part)
647
647
648 raw = '\n'.join(raw_parts)
648 raw = '\n'.join(raw_parts)
649 out_t = '\n'.join(out_t_parts)
649 out_t = '\n'.join(out_t_parts)
650
650
651 isp.push(raw)
651 isp.push(raw)
652 out, out_raw = isp.source_raw_reset()
652 out, out_raw = isp.source_raw_reset()
653 # Match ignoring trailing whitespace
653 # Match ignoring trailing whitespace
654 self.assertEqual(out.rstrip(), out_t.rstrip())
654 self.assertEqual(out.rstrip(), out_t.rstrip())
655 self.assertEqual(out_raw.rstrip(), raw.rstrip())
655 self.assertEqual(out_raw.rstrip(), raw.rstrip())
656
656
657
657
658 #-----------------------------------------------------------------------------
658 #-----------------------------------------------------------------------------
659 # Main - use as a script, mostly for developer experiments
659 # Main - use as a script, mostly for developer experiments
660 #-----------------------------------------------------------------------------
660 #-----------------------------------------------------------------------------
661
661
662 if __name__ == '__main__':
662 if __name__ == '__main__':
663 # A simple demo for interactive experimentation. This code will not get
663 # A simple demo for interactive experimentation. This code will not get
664 # picked up by any test suite.
664 # picked up by any test suite.
665 from IPython.core.inputsplitter import InputSplitter, IPythonInputSplitter
665 from IPython.core.inputsplitter import InputSplitter, IPythonInputSplitter
666
666
667 # configure here the syntax to use, prompt and whether to autoindent
667 # configure here the syntax to use, prompt and whether to autoindent
668 #isp, start_prompt = InputSplitter(), '>>> '
668 #isp, start_prompt = InputSplitter(), '>>> '
669 isp, start_prompt = IPythonInputSplitter(), 'In> '
669 isp, start_prompt = IPythonInputSplitter(), 'In> '
670
670
671 autoindent = True
671 autoindent = True
672 #autoindent = False
672 #autoindent = False
673
673
674 try:
674 try:
675 while True:
675 while True:
676 prompt = start_prompt
676 prompt = start_prompt
677 while isp.push_accepts_more():
677 while isp.push_accepts_more():
678 indent = ' '*isp.indent_spaces
678 indent = ' '*isp.indent_spaces
679 if autoindent:
679 if autoindent:
680 line = indent + raw_input(prompt+indent)
680 line = indent + raw_input(prompt+indent)
681 else:
681 else:
682 line = raw_input(prompt)
682 line = raw_input(prompt)
683 isp.push(line)
683 isp.push(line)
684 prompt = '... '
684 prompt = '... '
685
685
686 # Here we just return input so we can use it in a test suite, but a
686 # Here we just return input so we can use it in a test suite, but a
687 # real interpreter would instead send it for execution somewhere.
687 # real interpreter would instead send it for execution somewhere.
688 #src = isp.source; raise EOFError # dbg
688 #src = isp.source; raise EOFError # dbg
689 src, raw = isp.source_raw_reset()
689 src, raw = isp.source_raw_reset()
690 print 'Input source was:\n', src
690 print 'Input source was:\n', src
691 print 'Raw source was:\n', raw
691 print 'Raw source was:\n', raw
692 except EOFError:
692 except EOFError:
693 print 'Bye'
693 print 'Bye'
General Comments 0
You need to be logged in to leave comments. Login now