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