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