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