##// END OF EJS Templates
Fix tests in IPython.core
Thomas Kluyver -
Show More
@@ -1,649 +1,649 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
63
64 #-----------------------------------------------------------------------------
64 #-----------------------------------------------------------------------------
65 # Imports
65 # Imports
66 #-----------------------------------------------------------------------------
66 #-----------------------------------------------------------------------------
67 # stdlib
67 # stdlib
68 import ast
68 import ast
69 import codeop
69 import codeop
70 import re
70 import re
71 import sys
71 import sys
72
72
73 # IPython modules
73 # IPython modules
74 from IPython.core.splitinput import split_user_input, LineInfo
74 from IPython.core.splitinput import split_user_input, LineInfo
75 from IPython.utils.py3compat import cast_unicode
75 from IPython.utils.py3compat import cast_unicode
76 from IPython.core.inputtransformer import (leading_indent,
76 from IPython.core.inputtransformer import (leading_indent,
77 classic_prompt,
77 classic_prompt,
78 ipy_prompt,
78 ipy_prompt,
79 cellmagic,
79 cellmagic,
80 help_end,
80 help_end,
81 escaped_transformer,
81 escaped_transformer,
82 assign_from_magic,
82 assign_from_magic,
83 assign_from_system,
83 assign_from_system,
84 )
84 )
85
85
86 # Temporary!
86 # Temporary!
87 from IPython.core.inputtransformer import (ESC_SHELL, ESC_SH_CAP, ESC_HELP,
87 from IPython.core.inputtransformer import (ESC_SHELL, ESC_SH_CAP, ESC_HELP,
88 ESC_HELP2, ESC_MAGIC, ESC_MAGIC2,
88 ESC_HELP2, ESC_MAGIC, ESC_MAGIC2,
89 ESC_QUOTE, ESC_QUOTE2, ESC_PAREN, ESC_SEQUENCES)
89 ESC_QUOTE, ESC_QUOTE2, ESC_PAREN, ESC_SEQUENCES)
90
90
91 #-----------------------------------------------------------------------------
91 #-----------------------------------------------------------------------------
92 # Utilities
92 # Utilities
93 #-----------------------------------------------------------------------------
93 #-----------------------------------------------------------------------------
94
94
95 # FIXME: These are general-purpose utilities that later can be moved to the
95 # FIXME: These are general-purpose utilities that later can be moved to the
96 # general ward. Kept here for now because we're being very strict about test
96 # general ward. Kept here for now because we're being very strict about test
97 # coverage with this code, and this lets us ensure that we keep 100% coverage
97 # coverage with this code, and this lets us ensure that we keep 100% coverage
98 # while developing.
98 # while developing.
99
99
100 # compiled regexps for autoindent management
100 # compiled regexps for autoindent management
101 dedent_re = re.compile('|'.join([
101 dedent_re = re.compile('|'.join([
102 r'^\s+raise(\s.*)?$', # raise statement (+ space + other stuff, maybe)
102 r'^\s+raise(\s.*)?$', # raise statement (+ space + other stuff, maybe)
103 r'^\s+raise\([^\)]*\).*$', # wacky raise with immediate open paren
103 r'^\s+raise\([^\)]*\).*$', # wacky raise with immediate open paren
104 r'^\s+return(\s.*)?$', # normal return (+ space + other stuff, maybe)
104 r'^\s+return(\s.*)?$', # normal return (+ space + other stuff, maybe)
105 r'^\s+return\([^\)]*\).*$', # wacky return with immediate open paren
105 r'^\s+return\([^\)]*\).*$', # wacky return with immediate open paren
106 r'^\s+pass\s*$', # pass (optionally followed by trailing spaces)
106 r'^\s+pass\s*$', # pass (optionally followed by trailing spaces)
107 r'^\s+break\s*$', # break (optionally followed by trailing spaces)
107 r'^\s+break\s*$', # break (optionally followed by trailing spaces)
108 r'^\s+continue\s*$', # continue (optionally followed by trailing spaces)
108 r'^\s+continue\s*$', # continue (optionally followed by trailing spaces)
109 ]))
109 ]))
110 ini_spaces_re = re.compile(r'^([ \t\r\f\v]+)')
110 ini_spaces_re = re.compile(r'^([ \t\r\f\v]+)')
111
111
112 # regexp to match pure comment lines so we don't accidentally insert 'if 1:'
112 # regexp to match pure comment lines so we don't accidentally insert 'if 1:'
113 # before pure comments
113 # before pure comments
114 comment_line_re = re.compile('^\s*\#')
114 comment_line_re = re.compile('^\s*\#')
115
115
116
116
117 def num_ini_spaces(s):
117 def num_ini_spaces(s):
118 """Return the number of initial spaces in a string.
118 """Return the number of initial spaces in a string.
119
119
120 Note that tabs are counted as a single space. For now, we do *not* support
120 Note that tabs are counted as a single space. For now, we do *not* support
121 mixing of tabs and spaces in the user's input.
121 mixing of tabs and spaces in the user's input.
122
122
123 Parameters
123 Parameters
124 ----------
124 ----------
125 s : string
125 s : string
126
126
127 Returns
127 Returns
128 -------
128 -------
129 n : int
129 n : int
130 """
130 """
131
131
132 ini_spaces = ini_spaces_re.match(s)
132 ini_spaces = ini_spaces_re.match(s)
133 if ini_spaces:
133 if ini_spaces:
134 return ini_spaces.end()
134 return ini_spaces.end()
135 else:
135 else:
136 return 0
136 return 0
137
137
138 def last_blank(src):
138 def last_blank(src):
139 """Determine if the input source ends in a blank.
139 """Determine if the input source ends in a blank.
140
140
141 A blank is either a newline or a line consisting of whitespace.
141 A blank is either a newline or a line consisting of whitespace.
142
142
143 Parameters
143 Parameters
144 ----------
144 ----------
145 src : string
145 src : string
146 A single or multiline string.
146 A single or multiline string.
147 """
147 """
148 if not src: return False
148 if not src: return False
149 ll = src.splitlines()[-1]
149 ll = src.splitlines()[-1]
150 return (ll == '') or ll.isspace()
150 return (ll == '') or ll.isspace()
151
151
152
152
153 last_two_blanks_re = re.compile(r'\n\s*\n\s*$', re.MULTILINE)
153 last_two_blanks_re = re.compile(r'\n\s*\n\s*$', re.MULTILINE)
154 last_two_blanks_re2 = re.compile(r'.+\n\s*\n\s+$', re.MULTILINE)
154 last_two_blanks_re2 = re.compile(r'.+\n\s*\n\s+$', re.MULTILINE)
155
155
156 def last_two_blanks(src):
156 def last_two_blanks(src):
157 """Determine if the input source ends in two blanks.
157 """Determine if the input source ends in two blanks.
158
158
159 A blank is either a newline or a line consisting of whitespace.
159 A blank is either a newline or a line consisting of whitespace.
160
160
161 Parameters
161 Parameters
162 ----------
162 ----------
163 src : string
163 src : string
164 A single or multiline string.
164 A single or multiline string.
165 """
165 """
166 if not src: return False
166 if not src: return False
167 # The logic here is tricky: I couldn't get a regexp to work and pass all
167 # The logic here is tricky: I couldn't get a regexp to work and pass all
168 # the tests, so I took a different approach: split the source by lines,
168 # the tests, so I took a different approach: split the source by lines,
169 # grab the last two and prepend '###\n' as a stand-in for whatever was in
169 # grab the last two and prepend '###\n' as a stand-in for whatever was in
170 # the body before the last two lines. Then, with that structure, it's
170 # the body before the last two lines. Then, with that structure, it's
171 # possible to analyze with two regexps. Not the most elegant solution, but
171 # possible to analyze with two regexps. Not the most elegant solution, but
172 # it works. If anyone tries to change this logic, make sure to validate
172 # it works. If anyone tries to change this logic, make sure to validate
173 # the whole test suite first!
173 # the whole test suite first!
174 new_src = '\n'.join(['###\n'] + src.splitlines()[-2:])
174 new_src = '\n'.join(['###\n'] + src.splitlines()[-2:])
175 return (bool(last_two_blanks_re.match(new_src)) or
175 return (bool(last_two_blanks_re.match(new_src)) or
176 bool(last_two_blanks_re2.match(new_src)) )
176 bool(last_two_blanks_re2.match(new_src)) )
177
177
178
178
179 def remove_comments(src):
179 def remove_comments(src):
180 """Remove all comments from input source.
180 """Remove all comments from input source.
181
181
182 Note: comments are NOT recognized inside of strings!
182 Note: comments are NOT recognized inside of strings!
183
183
184 Parameters
184 Parameters
185 ----------
185 ----------
186 src : string
186 src : string
187 A single or multiline input string.
187 A single or multiline input string.
188
188
189 Returns
189 Returns
190 -------
190 -------
191 String with all Python comments removed.
191 String with all Python comments removed.
192 """
192 """
193
193
194 return re.sub('#.*', '', src)
194 return re.sub('#.*', '', src)
195
195
196
196
197 def get_input_encoding():
197 def get_input_encoding():
198 """Return the default standard input encoding.
198 """Return the default standard input encoding.
199
199
200 If sys.stdin has no encoding, 'ascii' is returned."""
200 If sys.stdin has no encoding, 'ascii' is returned."""
201 # There are strange environments for which sys.stdin.encoding is None. We
201 # There are strange environments for which sys.stdin.encoding is None. We
202 # ensure that a valid encoding is returned.
202 # ensure that a valid encoding is returned.
203 encoding = getattr(sys.stdin, 'encoding', None)
203 encoding = getattr(sys.stdin, 'encoding', None)
204 if encoding is None:
204 if encoding is None:
205 encoding = 'ascii'
205 encoding = 'ascii'
206 return encoding
206 return encoding
207
207
208 #-----------------------------------------------------------------------------
208 #-----------------------------------------------------------------------------
209 # Classes and functions for normal Python syntax handling
209 # Classes and functions for normal Python syntax handling
210 #-----------------------------------------------------------------------------
210 #-----------------------------------------------------------------------------
211
211
212 class InputSplitter(object):
212 class InputSplitter(object):
213 """An object that can accumulate lines of Python source before execution.
213 """An object that can accumulate lines of Python source before execution.
214
214
215 This object is designed to be fed python source line-by-line, using
215 This object is designed to be fed python source line-by-line, using
216 :meth:`push`. It will return on each push whether the currently pushed
216 :meth:`push`. It will return on each push whether the currently pushed
217 code could be executed already. In addition, it provides a method called
217 code could be executed already. In addition, it provides a method called
218 :meth:`push_accepts_more` that can be used to query whether more input
218 :meth:`push_accepts_more` that can be used to query whether more input
219 can be pushed into a single interactive block.
219 can be pushed into a single interactive block.
220
220
221 This is a simple example of how an interactive terminal-based client can use
221 This is a simple example of how an interactive terminal-based client can use
222 this tool::
222 this tool::
223
223
224 isp = InputSplitter()
224 isp = InputSplitter()
225 while isp.push_accepts_more():
225 while isp.push_accepts_more():
226 indent = ' '*isp.indent_spaces
226 indent = ' '*isp.indent_spaces
227 prompt = '>>> ' + indent
227 prompt = '>>> ' + indent
228 line = indent + raw_input(prompt)
228 line = indent + raw_input(prompt)
229 isp.push(line)
229 isp.push(line)
230 print 'Input source was:\n', isp.source_reset(),
230 print 'Input source was:\n', isp.source_reset(),
231 """
231 """
232 # Number of spaces of indentation computed from input that has been pushed
232 # Number of spaces of indentation computed from input that has been pushed
233 # so far. This is the attributes callers should query to get the current
233 # so far. This is the attributes callers should query to get the current
234 # indentation level, in order to provide auto-indent facilities.
234 # indentation level, in order to provide auto-indent facilities.
235 indent_spaces = 0
235 indent_spaces = 0
236 # String, indicating the default input encoding. It is computed by default
236 # String, indicating the default input encoding. It is computed by default
237 # at initialization time via get_input_encoding(), but it can be reset by a
237 # at initialization time via get_input_encoding(), but it can be reset by a
238 # client with specific knowledge of the encoding.
238 # client with specific knowledge of the encoding.
239 encoding = ''
239 encoding = ''
240 # String where the current full source input is stored, properly encoded.
240 # String where the current full source input is stored, properly encoded.
241 # Reading this attribute is the normal way of querying the currently pushed
241 # Reading this attribute is the normal way of querying the currently pushed
242 # source code, that has been properly encoded.
242 # source code, that has been properly encoded.
243 source = ''
243 source = ''
244 # Code object corresponding to the current source. It is automatically
244 # Code object corresponding to the current source. It is automatically
245 # synced to the source, so it can be queried at any time to obtain the code
245 # synced to the source, so it can be queried at any time to obtain the code
246 # object; it will be None if the source doesn't compile to valid Python.
246 # object; it will be None if the source doesn't compile to valid Python.
247 code = None
247 code = None
248 # Input mode
248 # Input mode
249 input_mode = 'line'
249 input_mode = 'line'
250
250
251 # Private attributes
251 # Private attributes
252
252
253 # List with lines of input accumulated so far
253 # List with lines of input accumulated so far
254 _buffer = None
254 _buffer = None
255 # Command compiler
255 # Command compiler
256 _compile = None
256 _compile = None
257 # Mark when input has changed indentation all the way back to flush-left
257 # Mark when input has changed indentation all the way back to flush-left
258 _full_dedent = False
258 _full_dedent = False
259 # Boolean indicating whether the current block is complete
259 # Boolean indicating whether the current block is complete
260 _is_complete = None
260 _is_complete = None
261
261
262 def __init__(self, input_mode=None):
262 def __init__(self, input_mode=None):
263 """Create a new InputSplitter instance.
263 """Create a new InputSplitter instance.
264
264
265 Parameters
265 Parameters
266 ----------
266 ----------
267 input_mode : str
267 input_mode : str
268
268
269 One of ['line', 'cell']; default is 'line'.
269 One of ['line', 'cell']; default is 'line'.
270
270
271 The input_mode parameter controls how new inputs are used when fed via
271 The input_mode parameter controls how new inputs are used when fed via
272 the :meth:`push` method:
272 the :meth:`push` method:
273
273
274 - 'line': meant for line-oriented clients, inputs are appended one at a
274 - 'line': meant for line-oriented clients, inputs are appended one at a
275 time to the internal buffer and the whole buffer is compiled.
275 time to the internal buffer and the whole buffer is compiled.
276
276
277 - 'cell': meant for clients that can edit multi-line 'cells' of text at
277 - 'cell': meant for clients that can edit multi-line 'cells' of text at
278 a time. A cell can contain one or more blocks that can be compile in
278 a time. A cell can contain one or more blocks that can be compile in
279 'single' mode by Python. In this mode, each new input new input
279 'single' mode by Python. In this mode, each new input new input
280 completely replaces all prior inputs. Cell mode is thus equivalent
280 completely replaces all prior inputs. Cell mode is thus equivalent
281 to prepending a full reset() to every push() call.
281 to prepending a full reset() to every push() call.
282 """
282 """
283 self._buffer = []
283 self._buffer = []
284 self._compile = codeop.CommandCompiler()
284 self._compile = codeop.CommandCompiler()
285 self.encoding = get_input_encoding()
285 self.encoding = get_input_encoding()
286 self.input_mode = InputSplitter.input_mode if input_mode is None \
286 self.input_mode = InputSplitter.input_mode if input_mode is None \
287 else input_mode
287 else input_mode
288
288
289 def reset(self):
289 def reset(self):
290 """Reset the input buffer and associated state."""
290 """Reset the input buffer and associated state."""
291 self.indent_spaces = 0
291 self.indent_spaces = 0
292 self._buffer[:] = []
292 self._buffer[:] = []
293 self.source = ''
293 self.source = ''
294 self.code = None
294 self.code = None
295 self._is_complete = False
295 self._is_complete = False
296 self._full_dedent = False
296 self._full_dedent = False
297
297
298 def source_reset(self):
298 def source_reset(self):
299 """Return the input source and perform a full reset.
299 """Return the input source and perform a full reset.
300 """
300 """
301 out = self.source
301 out = self.source
302 self.reset()
302 self.reset()
303 return out
303 return out
304
304
305 def push(self, lines):
305 def push(self, lines):
306 """Push one or more lines of input.
306 """Push one or more lines of input.
307
307
308 This stores the given lines and returns a status code indicating
308 This stores the given lines and returns a status code indicating
309 whether the code forms a complete Python block or not.
309 whether the code forms a complete Python block or not.
310
310
311 Any exceptions generated in compilation are swallowed, but if an
311 Any exceptions generated in compilation are swallowed, but if an
312 exception was produced, the method returns True.
312 exception was produced, the method returns True.
313
313
314 Parameters
314 Parameters
315 ----------
315 ----------
316 lines : string
316 lines : string
317 One or more lines of Python input.
317 One or more lines of Python input.
318
318
319 Returns
319 Returns
320 -------
320 -------
321 is_complete : boolean
321 is_complete : boolean
322 True if the current input source (the result of the current input
322 True if the current input source (the result of the current input
323 plus prior inputs) forms a complete Python execution block. Note that
323 plus prior inputs) forms a complete Python execution block. Note that
324 this value is also stored as a private attribute (``_is_complete``), so it
324 this value is also stored as a private attribute (``_is_complete``), so it
325 can be queried at any time.
325 can be queried at any time.
326 """
326 """
327 if self.input_mode == 'cell':
327 if self.input_mode == 'cell':
328 self.reset()
328 self.reset()
329
329
330 self._store(lines)
330 self._store(lines)
331 source = self.source
331 source = self.source
332
332
333 # Before calling _compile(), reset the code object to None so that if an
333 # Before calling _compile(), reset the code object to None so that if an
334 # exception is raised in compilation, we don't mislead by having
334 # exception is raised in compilation, we don't mislead by having
335 # inconsistent code/source attributes.
335 # inconsistent code/source attributes.
336 self.code, self._is_complete = None, None
336 self.code, self._is_complete = None, None
337
337
338 # Honor termination lines properly
338 # Honor termination lines properly
339 if source.endswith('\\\n'):
339 if source.endswith('\\\n'):
340 return False
340 return False
341
341
342 self._update_indent(lines)
342 self._update_indent(lines)
343 try:
343 try:
344 self.code = self._compile(source, symbol="exec")
344 self.code = self._compile(source, symbol="exec")
345 # Invalid syntax can produce any of a number of different errors from
345 # Invalid syntax can produce any of a number of different errors from
346 # inside the compiler, so we have to catch them all. Syntax errors
346 # inside the compiler, so we have to catch them all. Syntax errors
347 # immediately produce a 'ready' block, so the invalid Python can be
347 # immediately produce a 'ready' block, so the invalid Python can be
348 # sent to the kernel for evaluation with possible ipython
348 # sent to the kernel for evaluation with possible ipython
349 # special-syntax conversion.
349 # special-syntax conversion.
350 except (SyntaxError, OverflowError, ValueError, TypeError,
350 except (SyntaxError, OverflowError, ValueError, TypeError,
351 MemoryError):
351 MemoryError):
352 self._is_complete = True
352 self._is_complete = True
353 else:
353 else:
354 # Compilation didn't produce any exceptions (though it may not have
354 # Compilation didn't produce any exceptions (though it may not have
355 # given a complete code object)
355 # given a complete code object)
356 self._is_complete = self.code is not None
356 self._is_complete = self.code is not None
357
357
358 return self._is_complete
358 return self._is_complete
359
359
360 def push_accepts_more(self):
360 def push_accepts_more(self):
361 """Return whether a block of interactive input can accept more input.
361 """Return whether a block of interactive input can accept more input.
362
362
363 This method is meant to be used by line-oriented frontends, who need to
363 This method is meant to be used by line-oriented frontends, who need to
364 guess whether a block is complete or not based solely on prior and
364 guess whether a block is complete or not based solely on prior and
365 current input lines. The InputSplitter considers it has a complete
365 current input lines. The InputSplitter considers it has a complete
366 interactive block and will not accept more input only when either a
366 interactive block and will not accept more input only when either a
367 SyntaxError is raised, or *all* of the following are true:
367 SyntaxError is raised, or *all* of the following are true:
368
368
369 1. The input compiles to a complete statement.
369 1. The input compiles to a complete statement.
370
370
371 2. The indentation level is flush-left (because if we are indented,
371 2. The indentation level is flush-left (because if we are indented,
372 like inside a function definition or for loop, we need to keep
372 like inside a function definition or for loop, we need to keep
373 reading new input).
373 reading new input).
374
374
375 3. There is one extra line consisting only of whitespace.
375 3. There is one extra line consisting only of whitespace.
376
376
377 Because of condition #3, this method should be used only by
377 Because of condition #3, this method should be used only by
378 *line-oriented* frontends, since it means that intermediate blank lines
378 *line-oriented* frontends, since it means that intermediate blank lines
379 are not allowed in function definitions (or any other indented block).
379 are not allowed in function definitions (or any other indented block).
380
380
381 If the current input produces a syntax error, this method immediately
381 If the current input produces a syntax error, this method immediately
382 returns False but does *not* raise the syntax error exception, as
382 returns False but does *not* raise the syntax error exception, as
383 typically clients will want to send invalid syntax to an execution
383 typically clients will want to send invalid syntax to an execution
384 backend which might convert the invalid syntax into valid Python via
384 backend which might convert the invalid syntax into valid Python via
385 one of the dynamic IPython mechanisms.
385 one of the dynamic IPython mechanisms.
386 """
386 """
387
387
388 # With incomplete input, unconditionally accept more
388 # With incomplete input, unconditionally accept more
389 if not self._is_complete:
389 if not self._is_complete:
390 return True
390 return True
391
391
392 # If we already have complete input and we're flush left, the answer
392 # If we already have complete input and we're flush left, the answer
393 # depends. In line mode, if there hasn't been any indentation,
393 # depends. In line mode, if there hasn't been any indentation,
394 # that's it. If we've come back from some indentation, we need
394 # that's it. If we've come back from some indentation, we need
395 # the blank final line to finish.
395 # the blank final line to finish.
396 # In cell mode, we need to check how many blocks the input so far
396 # In cell mode, we need to check how many blocks the input so far
397 # compiles into, because if there's already more than one full
397 # compiles into, because if there's already more than one full
398 # independent block of input, then the client has entered full
398 # independent block of input, then the client has entered full
399 # 'cell' mode and is feeding lines that each is complete. In this
399 # 'cell' mode and is feeding lines that each is complete. In this
400 # case we should then keep accepting. The Qt terminal-like console
400 # case we should then keep accepting. The Qt terminal-like console
401 # does precisely this, to provide the convenience of terminal-like
401 # does precisely this, to provide the convenience of terminal-like
402 # input of single expressions, but allowing the user (with a
402 # input of single expressions, but allowing the user (with a
403 # separate keystroke) to switch to 'cell' mode and type multiple
403 # separate keystroke) to switch to 'cell' mode and type multiple
404 # expressions in one shot.
404 # expressions in one shot.
405 if self.indent_spaces==0:
405 if self.indent_spaces==0:
406 if self.input_mode=='line':
406 if self.input_mode=='line':
407 if not self._full_dedent:
407 if not self._full_dedent:
408 return False
408 return False
409 else:
409 else:
410 try:
410 try:
411 code_ast = ast.parse(u''.join(self._buffer))
411 code_ast = ast.parse(u''.join(self._buffer))
412 except Exception:
412 except Exception:
413 return False
413 return False
414 else:
414 else:
415 if len(code_ast.body) == 1:
415 if len(code_ast.body) == 1:
416 return False
416 return False
417
417
418 # When input is complete, then termination is marked by an extra blank
418 # When input is complete, then termination is marked by an extra blank
419 # line at the end.
419 # line at the end.
420 last_line = self.source.splitlines()[-1]
420 last_line = self.source.splitlines()[-1]
421 return bool(last_line and not last_line.isspace())
421 return bool(last_line and not last_line.isspace())
422
422
423 #------------------------------------------------------------------------
423 #------------------------------------------------------------------------
424 # Private interface
424 # Private interface
425 #------------------------------------------------------------------------
425 #------------------------------------------------------------------------
426
426
427 def _find_indent(self, line):
427 def _find_indent(self, line):
428 """Compute the new indentation level for a single line.
428 """Compute the new indentation level for a single line.
429
429
430 Parameters
430 Parameters
431 ----------
431 ----------
432 line : str
432 line : str
433 A single new line of non-whitespace, non-comment Python input.
433 A single new line of non-whitespace, non-comment Python input.
434
434
435 Returns
435 Returns
436 -------
436 -------
437 indent_spaces : int
437 indent_spaces : int
438 New value for the indent level (it may be equal to self.indent_spaces
438 New value for the indent level (it may be equal to self.indent_spaces
439 if indentation doesn't change.
439 if indentation doesn't change.
440
440
441 full_dedent : boolean
441 full_dedent : boolean
442 Whether the new line causes a full flush-left dedent.
442 Whether the new line causes a full flush-left dedent.
443 """
443 """
444 indent_spaces = self.indent_spaces
444 indent_spaces = self.indent_spaces
445 full_dedent = self._full_dedent
445 full_dedent = self._full_dedent
446
446
447 inisp = num_ini_spaces(line)
447 inisp = num_ini_spaces(line)
448 if inisp < indent_spaces:
448 if inisp < indent_spaces:
449 indent_spaces = inisp
449 indent_spaces = inisp
450 if indent_spaces <= 0:
450 if indent_spaces <= 0:
451 #print 'Full dedent in text',self.source # dbg
451 #print 'Full dedent in text',self.source # dbg
452 full_dedent = True
452 full_dedent = True
453
453
454 if line.rstrip()[-1] == ':':
454 if line.rstrip()[-1] == ':':
455 indent_spaces += 4
455 indent_spaces += 4
456 elif dedent_re.match(line):
456 elif dedent_re.match(line):
457 indent_spaces -= 4
457 indent_spaces -= 4
458 if indent_spaces <= 0:
458 if indent_spaces <= 0:
459 full_dedent = True
459 full_dedent = True
460
460
461 # Safety
461 # Safety
462 if indent_spaces < 0:
462 if indent_spaces < 0:
463 indent_spaces = 0
463 indent_spaces = 0
464 #print 'safety' # dbg
464 #print 'safety' # dbg
465
465
466 return indent_spaces, full_dedent
466 return indent_spaces, full_dedent
467
467
468 def _update_indent(self, lines):
468 def _update_indent(self, lines):
469 for line in remove_comments(lines).splitlines():
469 for line in remove_comments(lines).splitlines():
470 if line and not line.isspace():
470 if line and not line.isspace():
471 self.indent_spaces, self._full_dedent = self._find_indent(line)
471 self.indent_spaces, self._full_dedent = self._find_indent(line)
472
472
473 def _store(self, lines, buffer=None, store='source'):
473 def _store(self, lines, buffer=None, store='source'):
474 """Store one or more lines of input.
474 """Store one or more lines of input.
475
475
476 If input lines are not newline-terminated, a newline is automatically
476 If input lines are not newline-terminated, a newline is automatically
477 appended."""
477 appended."""
478
478
479 if buffer is None:
479 if buffer is None:
480 buffer = self._buffer
480 buffer = self._buffer
481
481
482 if lines.endswith('\n'):
482 if lines.endswith('\n'):
483 buffer.append(lines)
483 buffer.append(lines)
484 else:
484 else:
485 buffer.append(lines+'\n')
485 buffer.append(lines+'\n')
486 setattr(self, store, self._set_source(buffer))
486 setattr(self, store, self._set_source(buffer))
487
487
488 def _set_source(self, buffer):
488 def _set_source(self, buffer):
489 return u''.join(buffer)
489 return u''.join(buffer)
490
490
491
491
492 class IPythonInputSplitter(InputSplitter):
492 class IPythonInputSplitter(InputSplitter):
493 """An input splitter that recognizes all of IPython's special syntax."""
493 """An input splitter that recognizes all of IPython's special syntax."""
494
494
495 # String with raw, untransformed input.
495 # String with raw, untransformed input.
496 source_raw = ''
496 source_raw = ''
497
497
498 # Flag to track when a transformer has stored input that it hasn't given
498 # Flag to track when a transformer has stored input that it hasn't given
499 # back yet.
499 # back yet.
500 transformer_accumulating = False
500 transformer_accumulating = False
501
501
502 # Private attributes
502 # Private attributes
503
503
504 # List with lines of raw input accumulated so far.
504 # List with lines of raw input accumulated so far.
505 _buffer_raw = None
505 _buffer_raw = None
506
506
507 def __init__(self, input_mode=None):
507 def __init__(self, input_mode=None):
508 super(IPythonInputSplitter, self).__init__(input_mode)
508 super(IPythonInputSplitter, self).__init__(input_mode)
509 self._buffer_raw = []
509 self._buffer_raw = []
510 self._validate = True
510 self._validate = True
511 self.transforms = [leading_indent,
511 self.transforms = [leading_indent(),
512 classic_prompt,
512 classic_prompt(),
513 ipy_prompt,
513 ipy_prompt(),
514 cellmagic,
514 cellmagic(),
515 help_end,
515 help_end(),
516 escaped_transformer,
516 escaped_transformer(),
517 assign_from_magic,
517 assign_from_magic(),
518 assign_from_system,
518 assign_from_system(),
519 ]
519 ]
520
520
521 def reset(self):
521 def reset(self):
522 """Reset the input buffer and associated state."""
522 """Reset the input buffer and associated state."""
523 super(IPythonInputSplitter, self).reset()
523 super(IPythonInputSplitter, self).reset()
524 self._buffer_raw[:] = []
524 self._buffer_raw[:] = []
525 self.source_raw = ''
525 self.source_raw = ''
526 self.transformer_accumulating = False
526 self.transformer_accumulating = False
527 for t in self.transforms:
527 for t in self.transforms:
528 t.reset()
528 t.reset()
529
529
530 def flush_transformers(self):
530 def flush_transformers(self):
531 out = None
531 out = None
532 for t in self.transforms:
532 for t in self.transforms:
533 tmp = t.reset()
533 tmp = t.reset()
534 if tmp:
534 if tmp:
535 out = tmp
535 out = tmp
536 if out:
536 if out:
537 self._store(out)
537 self._store(out)
538
538
539 def source_raw_reset(self):
539 def source_raw_reset(self):
540 """Return input and raw source and perform a full reset.
540 """Return input and raw source and perform a full reset.
541 """
541 """
542 self.flush_transformers()
542 self.flush_transformers()
543 out = self.source
543 out = self.source
544 out_r = self.source_raw
544 out_r = self.source_raw
545 self.reset()
545 self.reset()
546 return out, out_r
546 return out, out_r
547
547
548 def source_reset(self):
548 def source_reset(self):
549 self.flush_transformers()
549 self.flush_transformers()
550 return super(IPythonInputSplitter, self).source_reset()
550 return super(IPythonInputSplitter, self).source_reset()
551
551
552 def push_accepts_more(self):
552 def push_accepts_more(self):
553 if self.transformer_accumulating:
553 if self.transformer_accumulating:
554 return True
554 return True
555 else:
555 else:
556 return super(IPythonInputSplitter, self).push_accepts_more()
556 return super(IPythonInputSplitter, self).push_accepts_more()
557
557
558 def transform_cell(self, cell):
558 def transform_cell(self, cell):
559 """Process and translate a cell of input.
559 """Process and translate a cell of input.
560 """
560 """
561 self.reset()
561 self.reset()
562 self.push(cell)
562 self.push(cell)
563 return self.source_reset()
563 return self.source_reset()
564
564
565 def push(self, lines):
565 def push(self, lines):
566 """Push one or more lines of IPython input.
566 """Push one or more lines of IPython input.
567
567
568 This stores the given lines and returns a status code indicating
568 This stores the given lines and returns a status code indicating
569 whether the code forms a complete Python block or not, after processing
569 whether the code forms a complete Python block or not, after processing
570 all input lines for special IPython syntax.
570 all input lines for special IPython syntax.
571
571
572 Any exceptions generated in compilation are swallowed, but if an
572 Any exceptions generated in compilation are swallowed, but if an
573 exception was produced, the method returns True.
573 exception was produced, the method returns True.
574
574
575 Parameters
575 Parameters
576 ----------
576 ----------
577 lines : string
577 lines : string
578 One or more lines of Python input.
578 One or more lines of Python input.
579
579
580 Returns
580 Returns
581 -------
581 -------
582 is_complete : boolean
582 is_complete : boolean
583 True if the current input source (the result of the current input
583 True if the current input source (the result of the current input
584 plus prior inputs) forms a complete Python execution block. Note that
584 plus prior inputs) forms a complete Python execution block. Note that
585 this value is also stored as a private attribute (_is_complete), so it
585 this value is also stored as a private attribute (_is_complete), so it
586 can be queried at any time.
586 can be queried at any time.
587 """
587 """
588
588
589 # We must ensure all input is pure unicode
589 # We must ensure all input is pure unicode
590 lines = cast_unicode(lines, self.encoding)
590 lines = cast_unicode(lines, self.encoding)
591
591
592 # ''.splitlines() --> [], but we need to push the empty line to transformers
592 # ''.splitlines() --> [], but we need to push the empty line to transformers
593 lines_list = lines.splitlines()
593 lines_list = lines.splitlines()
594 if not lines_list:
594 if not lines_list:
595 lines_list = ['']
595 lines_list = ['']
596
596
597 # Transform logic
597 # Transform logic
598 #
598 #
599 # We only apply the line transformers to the input if we have either no
599 # We only apply the line transformers to the input if we have either no
600 # input yet, or complete input, or if the last line of the buffer ends
600 # input yet, or complete input, or if the last line of the buffer ends
601 # with ':' (opening an indented block). This prevents the accidental
601 # with ':' (opening an indented block). This prevents the accidental
602 # transformation of escapes inside multiline expressions like
602 # transformation of escapes inside multiline expressions like
603 # triple-quoted strings or parenthesized expressions.
603 # triple-quoted strings or parenthesized expressions.
604 #
604 #
605 # The last heuristic, while ugly, ensures that the first line of an
605 # The last heuristic, while ugly, ensures that the first line of an
606 # indented block is correctly transformed.
606 # indented block is correctly transformed.
607 #
607 #
608 # FIXME: try to find a cleaner approach for this last bit.
608 # FIXME: try to find a cleaner approach for this last bit.
609
609
610 # If we were in 'block' mode, since we're going to pump the parent
610 # If we were in 'block' mode, since we're going to pump the parent
611 # class by hand line by line, we need to temporarily switch out to
611 # class by hand line by line, we need to temporarily switch out to
612 # 'line' mode, do a single manual reset and then feed the lines one
612 # 'line' mode, do a single manual reset and then feed the lines one
613 # by one. Note that this only matters if the input has more than one
613 # by one. Note that this only matters if the input has more than one
614 # line.
614 # line.
615 changed_input_mode = False
615 changed_input_mode = False
616
616
617 if self.input_mode == 'cell':
617 if self.input_mode == 'cell':
618 self.reset()
618 self.reset()
619 changed_input_mode = True
619 changed_input_mode = True
620 saved_input_mode = 'cell'
620 saved_input_mode = 'cell'
621 self.input_mode = 'line'
621 self.input_mode = 'line'
622
622
623 # Store raw source before applying any transformations to it. Note
623 # Store raw source before applying any transformations to it. Note
624 # that this must be done *after* the reset() call that would otherwise
624 # that this must be done *after* the reset() call that would otherwise
625 # flush the buffer.
625 # flush the buffer.
626 self._store(lines, self._buffer_raw, 'source_raw')
626 self._store(lines, self._buffer_raw, 'source_raw')
627
627
628 try:
628 try:
629 for line in lines_list:
629 for line in lines_list:
630 out = self.push_line(line)
630 out = self.push_line(line)
631 finally:
631 finally:
632 if changed_input_mode:
632 if changed_input_mode:
633 self.input_mode = saved_input_mode
633 self.input_mode = saved_input_mode
634
634
635 return out
635 return out
636
636
637 def push_line(self, line):
637 def push_line(self, line):
638 buf = self._buffer
638 buf = self._buffer
639 not_in_string = self._is_complete or not buf or \
639 not_in_string = self._is_complete or not buf or \
640 (buf and buf[-1].rstrip().endswith((':', ',')))
640 (buf and buf[-1].rstrip().endswith((':', ',')))
641 for transformer in self.transforms:
641 for transformer in self.transforms:
642 if not_in_string or transformer.look_in_string:
642 if not_in_string or transformer.look_in_string:
643 line = transformer.push(line)
643 line = transformer.push(line)
644 if line is None:
644 if line is None:
645 self.transformer_accumulating = True
645 self.transformer_accumulating = True
646 return False
646 return False
647
647
648 self.transformer_accumulating = False
648 self.transformer_accumulating = False
649 return super(IPythonInputSplitter, self).push(line)
649 return super(IPythonInputSplitter, self).push(line)
@@ -1,323 +1,333 b''
1 import abc
1 import abc
2 import re
2 import re
3 from StringIO import StringIO
3 from StringIO import StringIO
4 import tokenize
4 import tokenize
5
5
6 from IPython.core.splitinput import split_user_input, LineInfo
6 from IPython.core.splitinput import split_user_input, LineInfo
7
7
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Globals
9 # Globals
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11
11
12 # The escape sequences that define the syntax transformations IPython will
12 # The escape sequences that define the syntax transformations IPython will
13 # apply to user input. These can NOT be just changed here: many regular
13 # apply to user input. These can NOT be just changed here: many regular
14 # expressions and other parts of the code may use their hardcoded values, and
14 # expressions and other parts of the code may use their hardcoded values, and
15 # for all intents and purposes they constitute the 'IPython syntax', so they
15 # for all intents and purposes they constitute the 'IPython syntax', so they
16 # should be considered fixed.
16 # should be considered fixed.
17
17
18 ESC_SHELL = '!' # Send line to underlying system shell
18 ESC_SHELL = '!' # Send line to underlying system shell
19 ESC_SH_CAP = '!!' # Send line to system shell and capture output
19 ESC_SH_CAP = '!!' # Send line to system shell and capture output
20 ESC_HELP = '?' # Find information about object
20 ESC_HELP = '?' # Find information about object
21 ESC_HELP2 = '??' # Find extra-detailed information about object
21 ESC_HELP2 = '??' # Find extra-detailed information about object
22 ESC_MAGIC = '%' # Call magic function
22 ESC_MAGIC = '%' # Call magic function
23 ESC_MAGIC2 = '%%' # Call cell-magic function
23 ESC_MAGIC2 = '%%' # Call cell-magic function
24 ESC_QUOTE = ',' # Split args on whitespace, quote each as string and call
24 ESC_QUOTE = ',' # Split args on whitespace, quote each as string and call
25 ESC_QUOTE2 = ';' # Quote all args as a single string, call
25 ESC_QUOTE2 = ';' # Quote all args as a single string, call
26 ESC_PAREN = '/' # Call first argument with rest of line as arguments
26 ESC_PAREN = '/' # Call first argument with rest of line as arguments
27
27
28 ESC_SEQUENCES = [ESC_SHELL, ESC_SH_CAP, ESC_HELP ,\
28 ESC_SEQUENCES = [ESC_SHELL, ESC_SH_CAP, ESC_HELP ,\
29 ESC_HELP2, ESC_MAGIC, ESC_MAGIC2,\
29 ESC_HELP2, ESC_MAGIC, ESC_MAGIC2,\
30 ESC_QUOTE, ESC_QUOTE2, ESC_PAREN ]
30 ESC_QUOTE, ESC_QUOTE2, ESC_PAREN ]
31
31
32
32
33
33
34 class InputTransformer(object):
34 class InputTransformer(object):
35 __metaclass__ = abc.ABCMeta
35 __metaclass__ = abc.ABCMeta
36
36
37 @abc.abstractmethod
37 @abc.abstractmethod
38 def push(self, line):
38 def push(self, line):
39 pass
39 pass
40
40
41 @abc.abstractmethod
41 @abc.abstractmethod
42 def reset(self):
42 def reset(self):
43 pass
43 pass
44
44
45 look_in_string = False
45 look_in_string = False
46
46
47 class StatelessInputTransformer(InputTransformer):
47 def stateless_input_transformer(func):
48 """Decorator for a stateless input transformer implemented as a function."""
48 class StatelessInputTransformer(InputTransformer):
49 def __init__(self, func):
49 """Decorator for a stateless input transformer implemented as a function."""
50 self.func = func
50 def __init__(self):
51
51 self.func = func
52 def push(self, line):
52
53 return self.func(line)
53 def push(self, line):
54
54 return self.func(line)
55 def reset(self):
55
56 pass
56 def reset(self):
57
57 pass
58 class CoroutineInputTransformer(InputTransformer):
59 """Decorator for an input transformer implemented as a coroutine."""
60 def __init__(self, coro):
61 # Prime it
62 self.coro = coro()
63 next(self.coro)
64
58
65 def push(self, line):
59 return StatelessInputTransformer
66 return self.coro.send(line)
60
61 def coroutine_input_transformer(coro):
62 class CoroutineInputTransformer(InputTransformer):
63 def __init__(self):
64 # Prime it
65 self.coro = coro()
66 next(self.coro)
67
68 def push(self, line):
69 return self.coro.send(line)
70
71 def reset(self):
72 return self.coro.send(None)
67
73
68 def reset(self):
74 return CoroutineInputTransformer
69 return self.coro.send(None)
70
75
71
76
72 # Utilities
77 # Utilities
73 def _make_help_call(target, esc, lspace, next_input=None):
78 def _make_help_call(target, esc, lspace, next_input=None):
74 """Prepares a pinfo(2)/psearch call from a target name and the escape
79 """Prepares a pinfo(2)/psearch call from a target name and the escape
75 (i.e. ? or ??)"""
80 (i.e. ? or ??)"""
76 method = 'pinfo2' if esc == '??' \
81 method = 'pinfo2' if esc == '??' \
77 else 'psearch' if '*' in target \
82 else 'psearch' if '*' in target \
78 else 'pinfo'
83 else 'pinfo'
79 arg = " ".join([method, target])
84 arg = " ".join([method, target])
80 if next_input is None:
85 if next_input is None:
81 return '%sget_ipython().magic(%r)' % (lspace, arg)
86 return '%sget_ipython().magic(%r)' % (lspace, arg)
82 else:
87 else:
83 return '%sget_ipython().set_next_input(%r);get_ipython().magic(%r)' % \
88 return '%sget_ipython().set_next_input(%r);get_ipython().magic(%r)' % \
84 (lspace, next_input, arg)
89 (lspace, next_input, arg)
85
90
86 @CoroutineInputTransformer
91 @coroutine_input_transformer
87 def escaped_transformer():
92 def escaped_transformer():
88 """Translate lines beginning with one of IPython's escape characters."""
93 """Translate lines beginning with one of IPython's escape characters."""
89
94
90 # These define the transformations for the different escape characters.
95 # These define the transformations for the different escape characters.
91 def _tr_system(line_info):
96 def _tr_system(line_info):
92 "Translate lines escaped with: !"
97 "Translate lines escaped with: !"
93 cmd = line_info.line.lstrip().lstrip(ESC_SHELL)
98 cmd = line_info.line.lstrip().lstrip(ESC_SHELL)
94 return '%sget_ipython().system(%r)' % (line_info.pre, cmd)
99 return '%sget_ipython().system(%r)' % (line_info.pre, cmd)
95
100
96 def _tr_system2(line_info):
101 def _tr_system2(line_info):
97 "Translate lines escaped with: !!"
102 "Translate lines escaped with: !!"
98 cmd = line_info.line.lstrip()[2:]
103 cmd = line_info.line.lstrip()[2:]
99 return '%sget_ipython().getoutput(%r)' % (line_info.pre, cmd)
104 return '%sget_ipython().getoutput(%r)' % (line_info.pre, cmd)
100
105
101 def _tr_help(line_info):
106 def _tr_help(line_info):
102 "Translate lines escaped with: ?/??"
107 "Translate lines escaped with: ?/??"
103 # A naked help line should just fire the intro help screen
108 # A naked help line should just fire the intro help screen
104 if not line_info.line[1:]:
109 if not line_info.line[1:]:
105 return 'get_ipython().show_usage()'
110 return 'get_ipython().show_usage()'
106
111
107 return _make_help_call(line_info.ifun, line_info.esc, line_info.pre)
112 return _make_help_call(line_info.ifun, line_info.esc, line_info.pre)
108
113
109 def _tr_magic(line_info):
114 def _tr_magic(line_info):
110 "Translate lines escaped with: %"
115 "Translate lines escaped with: %"
111 tpl = '%sget_ipython().magic(%r)'
116 tpl = '%sget_ipython().magic(%r)'
112 cmd = ' '.join([line_info.ifun, line_info.the_rest]).strip()
117 cmd = ' '.join([line_info.ifun, line_info.the_rest]).strip()
113 return tpl % (line_info.pre, cmd)
118 return tpl % (line_info.pre, cmd)
114
119
115 def _tr_quote(line_info):
120 def _tr_quote(line_info):
116 "Translate lines escaped with: ,"
121 "Translate lines escaped with: ,"
117 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
122 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
118 '", "'.join(line_info.the_rest.split()) )
123 '", "'.join(line_info.the_rest.split()) )
119
124
120 def _tr_quote2(line_info):
125 def _tr_quote2(line_info):
121 "Translate lines escaped with: ;"
126 "Translate lines escaped with: ;"
122 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
127 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
123 line_info.the_rest)
128 line_info.the_rest)
124
129
125 def _tr_paren(line_info):
130 def _tr_paren(line_info):
126 "Translate lines escaped with: /"
131 "Translate lines escaped with: /"
127 return '%s%s(%s)' % (line_info.pre, line_info.ifun,
132 return '%s%s(%s)' % (line_info.pre, line_info.ifun,
128 ", ".join(line_info.the_rest.split()))
133 ", ".join(line_info.the_rest.split()))
129
134
130 tr = { ESC_SHELL : _tr_system,
135 tr = { ESC_SHELL : _tr_system,
131 ESC_SH_CAP : _tr_system2,
136 ESC_SH_CAP : _tr_system2,
132 ESC_HELP : _tr_help,
137 ESC_HELP : _tr_help,
133 ESC_HELP2 : _tr_help,
138 ESC_HELP2 : _tr_help,
134 ESC_MAGIC : _tr_magic,
139 ESC_MAGIC : _tr_magic,
135 ESC_QUOTE : _tr_quote,
140 ESC_QUOTE : _tr_quote,
136 ESC_QUOTE2 : _tr_quote2,
141 ESC_QUOTE2 : _tr_quote2,
137 ESC_PAREN : _tr_paren }
142 ESC_PAREN : _tr_paren }
138
143
139 line = ''
144 line = ''
140 while True:
145 while True:
141 line = (yield line)
146 line = (yield line)
142 if not line or line.isspace():
147 if not line or line.isspace():
143 continue
148 continue
144 lineinf = LineInfo(line)
149 lineinf = LineInfo(line)
145 if lineinf.esc not in tr:
150 if lineinf.esc not in tr:
146 continue
151 continue
147
152
148 parts = []
153 parts = []
149 while line is not None:
154 while line is not None:
150 parts.append(line.rstrip('\\'))
155 parts.append(line.rstrip('\\'))
151 if not line.endswith('\\'):
156 if not line.endswith('\\'):
152 break
157 break
153 line = (yield None)
158 line = (yield None)
154
159
155 # Output
160 # Output
156 lineinf = LineInfo(' '.join(parts))
161 lineinf = LineInfo(' '.join(parts))
157 line = tr[lineinf.esc](lineinf)
162 line = tr[lineinf.esc](lineinf)
158
163
159 _initial_space_re = re.compile(r'\s*')
164 _initial_space_re = re.compile(r'\s*')
160
165
161 _help_end_re = re.compile(r"""(%{0,2}
166 _help_end_re = re.compile(r"""(%{0,2}
162 [a-zA-Z_*][\w*]* # Variable name
167 [a-zA-Z_*][\w*]* # Variable name
163 (\.[a-zA-Z_*][\w*]*)* # .etc.etc
168 (\.[a-zA-Z_*][\w*]*)* # .etc.etc
164 )
169 )
165 (\?\??)$ # ? or ??""",
170 (\?\??)$ # ? or ??""",
166 re.VERBOSE)
171 re.VERBOSE)
167
172
168 def has_comment(src):
173 def has_comment(src):
169 """Indicate whether an input line has (i.e. ends in, or is) a comment.
174 """Indicate whether an input line has (i.e. ends in, or is) a comment.
170
175
171 This uses tokenize, so it can distinguish comments from # inside strings.
176 This uses tokenize, so it can distinguish comments from # inside strings.
172
177
173 Parameters
178 Parameters
174 ----------
179 ----------
175 src : string
180 src : string
176 A single line input string.
181 A single line input string.
177
182
178 Returns
183 Returns
179 -------
184 -------
180 Boolean: True if source has a comment.
185 Boolean: True if source has a comment.
181 """
186 """
182 readline = StringIO(src).readline
187 readline = StringIO(src).readline
183 toktypes = set()
188 toktypes = set()
184 try:
189 try:
185 for t in tokenize.generate_tokens(readline):
190 for t in tokenize.generate_tokens(readline):
186 toktypes.add(t[0])
191 toktypes.add(t[0])
187 except tokenize.TokenError:
192 except tokenize.TokenError:
188 pass
193 pass
189 return(tokenize.COMMENT in toktypes)
194 return(tokenize.COMMENT in toktypes)
190
195
191 @StatelessInputTransformer
196 @stateless_input_transformer
192 def help_end(line):
197 def help_end(line):
193 """Translate lines with ?/?? at the end"""
198 """Translate lines with ?/?? at the end"""
194 m = _help_end_re.search(line)
199 m = _help_end_re.search(line)
195 if m is None or has_comment(line):
200 if m is None or has_comment(line):
196 return line
201 return line
197 target = m.group(1)
202 target = m.group(1)
198 esc = m.group(3)
203 esc = m.group(3)
199 lspace = _initial_space_re.match(line).group(0)
204 lspace = _initial_space_re.match(line).group(0)
200
205
201 # If we're mid-command, put it back on the next prompt for the user.
206 # If we're mid-command, put it back on the next prompt for the user.
202 next_input = line.rstrip('?') if line.strip() != m.group(0) else None
207 next_input = line.rstrip('?') if line.strip() != m.group(0) else None
203
208
204 return _make_help_call(target, esc, lspace, next_input)
209 return _make_help_call(target, esc, lspace, next_input)
205
210
206
211
207 @CoroutineInputTransformer
212 @coroutine_input_transformer
208 def cellmagic():
213 def cellmagic():
209 tpl = 'get_ipython().run_cell_magic(%r, %r, %r)'
214 tpl = 'get_ipython().run_cell_magic(%r, %r, %r)'
215 cellmagic_help_re = re.compile('%%\w+\?')
210 line = ''
216 line = ''
211 while True:
217 while True:
212 line = (yield line)
218 line = (yield line)
213 if (not line) or (not line.startswith(ESC_MAGIC2)):
219 if (not line) or (not line.startswith(ESC_MAGIC2)):
214 continue
220 continue
215
221
222 if cellmagic_help_re.match(line):
223 # This case will be handled by help_end
224 continue
225
216 first = line
226 first = line
217 body = []
227 body = []
218 line = (yield None)
228 line = (yield None)
219 while (line is not None) and (line.strip() != ''):
229 while (line is not None) and (line.strip() != ''):
220 body.append(line)
230 body.append(line)
221 line = (yield None)
231 line = (yield None)
222
232
223 # Output
233 # Output
224 magic_name, _, first = first.partition(' ')
234 magic_name, _, first = first.partition(' ')
225 magic_name = magic_name.lstrip(ESC_MAGIC2)
235 magic_name = magic_name.lstrip(ESC_MAGIC2)
226 line = tpl % (magic_name, first, '\n'.join(body))
236 line = tpl % (magic_name, first, u'\n'.join(body))
227
237
228 def _strip_prompts(prompt1_re, prompt2_re):
238 def _strip_prompts(prompt1_re, prompt2_re):
229 """Remove matching input prompts from a block of input."""
239 """Remove matching input prompts from a block of input."""
230 line = ''
240 line = ''
231 while True:
241 while True:
232 line = (yield line)
242 line = (yield line)
233
243
234 if line is None:
244 if line is None:
235 continue
245 continue
236
246
237 m = prompt1_re.match(line)
247 m = prompt1_re.match(line)
238 if m:
248 if m:
239 while m:
249 while m:
240 line = (yield line[len(m.group(0)):])
250 line = (yield line[len(m.group(0)):])
241 if line is None:
251 if line is None:
242 break
252 break
243 m = prompt2_re.match(line)
253 m = prompt2_re.match(line)
244 else:
254 else:
245 # Prompts not in input - wait for reset
255 # Prompts not in input - wait for reset
246 while line is not None:
256 while line is not None:
247 line = (yield line)
257 line = (yield line)
248
258
249 @CoroutineInputTransformer
259 @coroutine_input_transformer
250 def classic_prompt():
260 def classic_prompt():
251 prompt1_re = re.compile(r'^(>>> )')
261 prompt1_re = re.compile(r'^(>>> )')
252 prompt2_re = re.compile(r'^(>>> |^\.\.\. )')
262 prompt2_re = re.compile(r'^(>>> |^\.\.\. )')
253 return _strip_prompts(prompt1_re, prompt2_re)
263 return _strip_prompts(prompt1_re, prompt2_re)
254
264
255 classic_prompt.look_in_string = True
265 classic_prompt.look_in_string = True
256
266
257 @CoroutineInputTransformer
267 @coroutine_input_transformer
258 def ipy_prompt():
268 def ipy_prompt():
259 prompt1_re = re.compile(r'^In \[\d+\]: ')
269 prompt1_re = re.compile(r'^In \[\d+\]: ')
260 prompt2_re = re.compile(r'^(In \[\d+\]: |^\ \ \ \.\.\.+: )')
270 prompt2_re = re.compile(r'^(In \[\d+\]: |^\ \ \ \.\.\.+: )')
261 return _strip_prompts(prompt1_re, prompt2_re)
271 return _strip_prompts(prompt1_re, prompt2_re)
262
272
263 ipy_prompt.look_in_string = True
273 ipy_prompt.look_in_string = True
264
274
265 @CoroutineInputTransformer
275 @coroutine_input_transformer
266 def leading_indent():
276 def leading_indent():
267 space_re = re.compile(r'^[ \t]+')
277 space_re = re.compile(r'^[ \t]+')
268 line = ''
278 line = ''
269 while True:
279 while True:
270 line = (yield line)
280 line = (yield line)
271
281
272 if line is None:
282 if line is None:
273 continue
283 continue
274
284
275 m = space_re.match(line)
285 m = space_re.match(line)
276 if m:
286 if m:
277 space = m.group(0)
287 space = m.group(0)
278 while line is not None:
288 while line is not None:
279 if line.startswith(space):
289 if line.startswith(space):
280 line = line[len(space):]
290 line = line[len(space):]
281 line = (yield line)
291 line = (yield line)
282 else:
292 else:
283 # No leading spaces - wait for reset
293 # No leading spaces - wait for reset
284 while line is not None:
294 while line is not None:
285 line = (yield line)
295 line = (yield line)
286
296
287 leading_indent.look_in_string = True
297 leading_indent.look_in_string = True
288
298
289 def _special_assignment(assignment_re, template):
299 def _special_assignment(assignment_re, template):
290 line = ''
300 line = ''
291 while True:
301 while True:
292 line = (yield line)
302 line = (yield line)
293 if not line or line.isspace():
303 if not line or line.isspace():
294 continue
304 continue
295
305
296 m = assignment_re.match(line)
306 m = assignment_re.match(line)
297 if not m:
307 if not m:
298 continue
308 continue
299
309
300 parts = []
310 parts = []
301 while line is not None:
311 while line is not None:
302 parts.append(line.rstrip('\\'))
312 parts.append(line.rstrip('\\'))
303 if not line.endswith('\\'):
313 if not line.endswith('\\'):
304 break
314 break
305 line = (yield None)
315 line = (yield None)
306
316
307 # Output
317 # Output
308 whole = assignment_re.match(' '.join(parts))
318 whole = assignment_re.match(' '.join(parts))
309 line = template % (whole.group('lhs'), whole.group('cmd'))
319 line = template % (whole.group('lhs'), whole.group('cmd'))
310
320
311 @CoroutineInputTransformer
321 @coroutine_input_transformer
312 def assign_from_system():
322 def assign_from_system():
313 assignment_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
323 assignment_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
314 r'\s*=\s*!\s*(?P<cmd>.*)')
324 r'\s*=\s*!\s*(?P<cmd>.*)')
315 template = '%s = get_ipython().getoutput(%r)'
325 template = '%s = get_ipython().getoutput(%r)'
316 return _special_assignment(assignment_re, template)
326 return _special_assignment(assignment_re, template)
317
327
318 @CoroutineInputTransformer
328 @coroutine_input_transformer
319 def assign_from_magic():
329 def assign_from_magic():
320 assignment_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
330 assignment_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
321 r'\s*=\s*%\s*(?P<cmd>.*)')
331 r'\s*=\s*%\s*(?P<cmd>.*)')
322 template = '%s = get_ipython().magic(%r)'
332 template = '%s = get_ipython().magic(%r)'
323 return _special_assignment(assignment_re, template)
333 return _special_assignment(assignment_re, template)
@@ -1,637 +1,625 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-2011 The IPython Development Team
10 # Copyright (C) 2010-2011 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.core.tests.test_inputtransformer import syntax, syntax_ml
28 from IPython.core.tests.test_inputtransformer import syntax, syntax_ml
29 from IPython.testing import tools as tt
29 from IPython.testing import tools as tt
30 from IPython.utils import py3compat
30 from IPython.utils import py3compat
31
31
32 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
33 # Semi-complete examples (also used as tests)
33 # Semi-complete examples (also used as tests)
34 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
35
35
36 # Note: at the bottom, there's a slightly more complete version of this that
36 # Note: at the bottom, there's a slightly more complete version of this that
37 # can be useful during development of code here.
37 # can be useful during development of code here.
38
38
39 def mini_interactive_loop(input_func):
39 def mini_interactive_loop(input_func):
40 """Minimal example of the logic of an interactive interpreter loop.
40 """Minimal example of the logic of an interactive interpreter loop.
41
41
42 This serves as an example, and it is used by the test system with a fake
42 This serves as an example, and it is used by the test system with a fake
43 raw_input that simulates interactive input."""
43 raw_input that simulates interactive input."""
44
44
45 from IPython.core.inputsplitter import InputSplitter
45 from IPython.core.inputsplitter import InputSplitter
46
46
47 isp = InputSplitter()
47 isp = InputSplitter()
48 # In practice, this input loop would be wrapped in an outside loop to read
48 # In practice, this input loop would be wrapped in an outside loop to read
49 # input indefinitely, until some exit/quit command was issued. Here we
49 # input indefinitely, until some exit/quit command was issued. Here we
50 # only illustrate the basic inner loop.
50 # only illustrate the basic inner loop.
51 while isp.push_accepts_more():
51 while isp.push_accepts_more():
52 indent = ' '*isp.indent_spaces
52 indent = ' '*isp.indent_spaces
53 prompt = '>>> ' + indent
53 prompt = '>>> ' + indent
54 line = indent + input_func(prompt)
54 line = indent + input_func(prompt)
55 isp.push(line)
55 isp.push(line)
56
56
57 # Here we just return input so we can use it in a test suite, but a real
57 # Here we just return input so we can use it in a test suite, but a real
58 # interpreter would instead send it for execution somewhere.
58 # interpreter would instead send it for execution somewhere.
59 src = isp.source_reset()
59 src = isp.source_reset()
60 #print 'Input source was:\n', src # dbg
60 #print 'Input source was:\n', src # dbg
61 return src
61 return src
62
62
63 #-----------------------------------------------------------------------------
63 #-----------------------------------------------------------------------------
64 # Test utilities, just for local use
64 # Test utilities, just for local use
65 #-----------------------------------------------------------------------------
65 #-----------------------------------------------------------------------------
66
66
67 def assemble(block):
67 def assemble(block):
68 """Assemble a block into multi-line sub-blocks."""
68 """Assemble a block into multi-line sub-blocks."""
69 return ['\n'.join(sub_block)+'\n' for sub_block in block]
69 return ['\n'.join(sub_block)+'\n' for sub_block in block]
70
70
71
71
72 def pseudo_input(lines):
72 def pseudo_input(lines):
73 """Return a function that acts like raw_input but feeds the input list."""
73 """Return a function that acts like raw_input but feeds the input list."""
74 ilines = iter(lines)
74 ilines = iter(lines)
75 def raw_in(prompt):
75 def raw_in(prompt):
76 try:
76 try:
77 return next(ilines)
77 return next(ilines)
78 except StopIteration:
78 except StopIteration:
79 return ''
79 return ''
80 return raw_in
80 return raw_in
81
81
82 #-----------------------------------------------------------------------------
82 #-----------------------------------------------------------------------------
83 # Tests
83 # Tests
84 #-----------------------------------------------------------------------------
84 #-----------------------------------------------------------------------------
85 def test_spaces():
85 def test_spaces():
86 tests = [('', 0),
86 tests = [('', 0),
87 (' ', 1),
87 (' ', 1),
88 ('\n', 0),
88 ('\n', 0),
89 (' \n', 1),
89 (' \n', 1),
90 ('x', 0),
90 ('x', 0),
91 (' x', 1),
91 (' x', 1),
92 (' x',2),
92 (' x',2),
93 (' x',4),
93 (' x',4),
94 # Note: tabs are counted as a single whitespace!
94 # Note: tabs are counted as a single whitespace!
95 ('\tx', 1),
95 ('\tx', 1),
96 ('\t x', 2),
96 ('\t x', 2),
97 ]
97 ]
98 tt.check_pairs(isp.num_ini_spaces, tests)
98 tt.check_pairs(isp.num_ini_spaces, tests)
99
99
100
100
101 def test_remove_comments():
101 def test_remove_comments():
102 tests = [('text', 'text'),
102 tests = [('text', 'text'),
103 ('text # comment', 'text '),
103 ('text # comment', 'text '),
104 ('text # comment\n', 'text \n'),
104 ('text # comment\n', 'text \n'),
105 ('text # comment \n', 'text \n'),
105 ('text # comment \n', 'text \n'),
106 ('line # c \nline\n','line \nline\n'),
106 ('line # c \nline\n','line \nline\n'),
107 ('line # c \nline#c2 \nline\nline #c\n\n',
107 ('line # c \nline#c2 \nline\nline #c\n\n',
108 'line \nline\nline\nline \n\n'),
108 'line \nline\nline\nline \n\n'),
109 ]
109 ]
110 tt.check_pairs(isp.remove_comments, tests)
110 tt.check_pairs(isp.remove_comments, tests)
111
111
112 def test_has_comment():
113 tests = [('text', False),
114 ('text #comment', True),
115 ('text #comment\n', True),
116 ('#comment', True),
117 ('#comment\n', True),
118 ('a = "#string"', False),
119 ('a = "#string" # comment', True),
120 ('a #comment not "string"', True),
121 ]
122 tt.check_pairs(isp.has_comment, tests)
123
124
112
125 def test_get_input_encoding():
113 def test_get_input_encoding():
126 encoding = isp.get_input_encoding()
114 encoding = isp.get_input_encoding()
127 nt.assert_true(isinstance(encoding, basestring))
115 nt.assert_true(isinstance(encoding, basestring))
128 # simple-minded check that at least encoding a simple string works with the
116 # simple-minded check that at least encoding a simple string works with the
129 # encoding we got.
117 # encoding we got.
130 nt.assert_equal(u'test'.encode(encoding), b'test')
118 nt.assert_equal(u'test'.encode(encoding), b'test')
131
119
132
120
133 class NoInputEncodingTestCase(unittest.TestCase):
121 class NoInputEncodingTestCase(unittest.TestCase):
134 def setUp(self):
122 def setUp(self):
135 self.old_stdin = sys.stdin
123 self.old_stdin = sys.stdin
136 class X: pass
124 class X: pass
137 fake_stdin = X()
125 fake_stdin = X()
138 sys.stdin = fake_stdin
126 sys.stdin = fake_stdin
139
127
140 def test(self):
128 def test(self):
141 # Verify that if sys.stdin has no 'encoding' attribute we do the right
129 # Verify that if sys.stdin has no 'encoding' attribute we do the right
142 # thing
130 # thing
143 enc = isp.get_input_encoding()
131 enc = isp.get_input_encoding()
144 self.assertEqual(enc, 'ascii')
132 self.assertEqual(enc, 'ascii')
145
133
146 def tearDown(self):
134 def tearDown(self):
147 sys.stdin = self.old_stdin
135 sys.stdin = self.old_stdin
148
136
149
137
150 class InputSplitterTestCase(unittest.TestCase):
138 class InputSplitterTestCase(unittest.TestCase):
151 def setUp(self):
139 def setUp(self):
152 self.isp = isp.InputSplitter()
140 self.isp = isp.InputSplitter()
153
141
154 def test_reset(self):
142 def test_reset(self):
155 isp = self.isp
143 isp = self.isp
156 isp.push('x=1')
144 isp.push('x=1')
157 isp.reset()
145 isp.reset()
158 self.assertEqual(isp._buffer, [])
146 self.assertEqual(isp._buffer, [])
159 self.assertEqual(isp.indent_spaces, 0)
147 self.assertEqual(isp.indent_spaces, 0)
160 self.assertEqual(isp.source, '')
148 self.assertEqual(isp.source, '')
161 self.assertEqual(isp.code, None)
149 self.assertEqual(isp.code, None)
162 self.assertEqual(isp._is_complete, False)
150 self.assertEqual(isp._is_complete, False)
163
151
164 def test_source(self):
152 def test_source(self):
165 self.isp._store('1')
153 self.isp._store('1')
166 self.isp._store('2')
154 self.isp._store('2')
167 self.assertEqual(self.isp.source, '1\n2\n')
155 self.assertEqual(self.isp.source, '1\n2\n')
168 self.assertTrue(len(self.isp._buffer)>0)
156 self.assertTrue(len(self.isp._buffer)>0)
169 self.assertEqual(self.isp.source_reset(), '1\n2\n')
157 self.assertEqual(self.isp.source_reset(), '1\n2\n')
170 self.assertEqual(self.isp._buffer, [])
158 self.assertEqual(self.isp._buffer, [])
171 self.assertEqual(self.isp.source, '')
159 self.assertEqual(self.isp.source, '')
172
160
173 def test_indent(self):
161 def test_indent(self):
174 isp = self.isp # shorthand
162 isp = self.isp # shorthand
175 isp.push('x=1')
163 isp.push('x=1')
176 self.assertEqual(isp.indent_spaces, 0)
164 self.assertEqual(isp.indent_spaces, 0)
177 isp.push('if 1:\n x=1')
165 isp.push('if 1:\n x=1')
178 self.assertEqual(isp.indent_spaces, 4)
166 self.assertEqual(isp.indent_spaces, 4)
179 isp.push('y=2\n')
167 isp.push('y=2\n')
180 self.assertEqual(isp.indent_spaces, 0)
168 self.assertEqual(isp.indent_spaces, 0)
181
169
182 def test_indent2(self):
170 def test_indent2(self):
183 # In cell mode, inputs must be fed in whole blocks, so skip this test
171 # In cell mode, inputs must be fed in whole blocks, so skip this test
184 if self.isp.input_mode == 'cell': return
172 if self.isp.input_mode == 'cell': return
185
173
186 isp = self.isp
174 isp = self.isp
187 isp.push('if 1:')
175 isp.push('if 1:')
188 self.assertEqual(isp.indent_spaces, 4)
176 self.assertEqual(isp.indent_spaces, 4)
189 isp.push(' x=1')
177 isp.push(' x=1')
190 self.assertEqual(isp.indent_spaces, 4)
178 self.assertEqual(isp.indent_spaces, 4)
191 # Blank lines shouldn't change the indent level
179 # Blank lines shouldn't change the indent level
192 isp.push(' '*2)
180 isp.push(' '*2)
193 self.assertEqual(isp.indent_spaces, 4)
181 self.assertEqual(isp.indent_spaces, 4)
194
182
195 def test_indent3(self):
183 def test_indent3(self):
196 # In cell mode, inputs must be fed in whole blocks, so skip this test
184 # In cell mode, inputs must be fed in whole blocks, so skip this test
197 if self.isp.input_mode == 'cell': return
185 if self.isp.input_mode == 'cell': return
198
186
199 isp = self.isp
187 isp = self.isp
200 # When a multiline statement contains parens or multiline strings, we
188 # When a multiline statement contains parens or multiline strings, we
201 # shouldn't get confused.
189 # shouldn't get confused.
202 isp.push("if 1:")
190 isp.push("if 1:")
203 isp.push(" x = (1+\n 2)")
191 isp.push(" x = (1+\n 2)")
204 self.assertEqual(isp.indent_spaces, 4)
192 self.assertEqual(isp.indent_spaces, 4)
205
193
206 def test_indent4(self):
194 def test_indent4(self):
207 # In cell mode, inputs must be fed in whole blocks, so skip this test
195 # In cell mode, inputs must be fed in whole blocks, so skip this test
208 if self.isp.input_mode == 'cell': return
196 if self.isp.input_mode == 'cell': return
209
197
210 isp = self.isp
198 isp = self.isp
211 # whitespace after ':' should not screw up indent level
199 # whitespace after ':' should not screw up indent level
212 isp.push('if 1: \n x=1')
200 isp.push('if 1: \n x=1')
213 self.assertEqual(isp.indent_spaces, 4)
201 self.assertEqual(isp.indent_spaces, 4)
214 isp.push('y=2\n')
202 isp.push('y=2\n')
215 self.assertEqual(isp.indent_spaces, 0)
203 self.assertEqual(isp.indent_spaces, 0)
216 isp.push('if 1:\t\n x=1')
204 isp.push('if 1:\t\n x=1')
217 self.assertEqual(isp.indent_spaces, 4)
205 self.assertEqual(isp.indent_spaces, 4)
218 isp.push('y=2\n')
206 isp.push('y=2\n')
219 self.assertEqual(isp.indent_spaces, 0)
207 self.assertEqual(isp.indent_spaces, 0)
220
208
221 def test_dedent_pass(self):
209 def test_dedent_pass(self):
222 isp = self.isp # shorthand
210 isp = self.isp # shorthand
223 # should NOT cause dedent
211 # should NOT cause dedent
224 isp.push('if 1:\n passes = 5')
212 isp.push('if 1:\n passes = 5')
225 self.assertEqual(isp.indent_spaces, 4)
213 self.assertEqual(isp.indent_spaces, 4)
226 isp.push('if 1:\n pass')
214 isp.push('if 1:\n pass')
227 self.assertEqual(isp.indent_spaces, 0)
215 self.assertEqual(isp.indent_spaces, 0)
228 isp.push('if 1:\n pass ')
216 isp.push('if 1:\n pass ')
229 self.assertEqual(isp.indent_spaces, 0)
217 self.assertEqual(isp.indent_spaces, 0)
230
218
231 def test_dedent_break(self):
219 def test_dedent_break(self):
232 isp = self.isp # shorthand
220 isp = self.isp # shorthand
233 # should NOT cause dedent
221 # should NOT cause dedent
234 isp.push('while 1:\n breaks = 5')
222 isp.push('while 1:\n breaks = 5')
235 self.assertEqual(isp.indent_spaces, 4)
223 self.assertEqual(isp.indent_spaces, 4)
236 isp.push('while 1:\n break')
224 isp.push('while 1:\n break')
237 self.assertEqual(isp.indent_spaces, 0)
225 self.assertEqual(isp.indent_spaces, 0)
238 isp.push('while 1:\n break ')
226 isp.push('while 1:\n break ')
239 self.assertEqual(isp.indent_spaces, 0)
227 self.assertEqual(isp.indent_spaces, 0)
240
228
241 def test_dedent_continue(self):
229 def test_dedent_continue(self):
242 isp = self.isp # shorthand
230 isp = self.isp # shorthand
243 # should NOT cause dedent
231 # should NOT cause dedent
244 isp.push('while 1:\n continues = 5')
232 isp.push('while 1:\n continues = 5')
245 self.assertEqual(isp.indent_spaces, 4)
233 self.assertEqual(isp.indent_spaces, 4)
246 isp.push('while 1:\n continue')
234 isp.push('while 1:\n continue')
247 self.assertEqual(isp.indent_spaces, 0)
235 self.assertEqual(isp.indent_spaces, 0)
248 isp.push('while 1:\n continue ')
236 isp.push('while 1:\n continue ')
249 self.assertEqual(isp.indent_spaces, 0)
237 self.assertEqual(isp.indent_spaces, 0)
250
238
251 def test_dedent_raise(self):
239 def test_dedent_raise(self):
252 isp = self.isp # shorthand
240 isp = self.isp # shorthand
253 # should NOT cause dedent
241 # should NOT cause dedent
254 isp.push('if 1:\n raised = 4')
242 isp.push('if 1:\n raised = 4')
255 self.assertEqual(isp.indent_spaces, 4)
243 self.assertEqual(isp.indent_spaces, 4)
256 isp.push('if 1:\n raise TypeError()')
244 isp.push('if 1:\n raise TypeError()')
257 self.assertEqual(isp.indent_spaces, 0)
245 self.assertEqual(isp.indent_spaces, 0)
258 isp.push('if 1:\n raise')
246 isp.push('if 1:\n raise')
259 self.assertEqual(isp.indent_spaces, 0)
247 self.assertEqual(isp.indent_spaces, 0)
260 isp.push('if 1:\n raise ')
248 isp.push('if 1:\n raise ')
261 self.assertEqual(isp.indent_spaces, 0)
249 self.assertEqual(isp.indent_spaces, 0)
262
250
263 def test_dedent_return(self):
251 def test_dedent_return(self):
264 isp = self.isp # shorthand
252 isp = self.isp # shorthand
265 # should NOT cause dedent
253 # should NOT cause dedent
266 isp.push('if 1:\n returning = 4')
254 isp.push('if 1:\n returning = 4')
267 self.assertEqual(isp.indent_spaces, 4)
255 self.assertEqual(isp.indent_spaces, 4)
268 isp.push('if 1:\n return 5 + 493')
256 isp.push('if 1:\n return 5 + 493')
269 self.assertEqual(isp.indent_spaces, 0)
257 self.assertEqual(isp.indent_spaces, 0)
270 isp.push('if 1:\n return')
258 isp.push('if 1:\n return')
271 self.assertEqual(isp.indent_spaces, 0)
259 self.assertEqual(isp.indent_spaces, 0)
272 isp.push('if 1:\n return ')
260 isp.push('if 1:\n return ')
273 self.assertEqual(isp.indent_spaces, 0)
261 self.assertEqual(isp.indent_spaces, 0)
274 isp.push('if 1:\n return(0)')
262 isp.push('if 1:\n return(0)')
275 self.assertEqual(isp.indent_spaces, 0)
263 self.assertEqual(isp.indent_spaces, 0)
276
264
277 def test_push(self):
265 def test_push(self):
278 isp = self.isp
266 isp = self.isp
279 self.assertTrue(isp.push('x=1'))
267 self.assertTrue(isp.push('x=1'))
280
268
281 def test_push2(self):
269 def test_push2(self):
282 isp = self.isp
270 isp = self.isp
283 self.assertFalse(isp.push('if 1:'))
271 self.assertFalse(isp.push('if 1:'))
284 for line in [' x=1', '# a comment', ' y=2']:
272 for line in [' x=1', '# a comment', ' y=2']:
285 self.assertTrue(isp.push(line))
273 self.assertTrue(isp.push(line))
286
274
287 def test_push3(self):
275 def test_push3(self):
288 isp = self.isp
276 isp = self.isp
289 isp.push('if True:')
277 isp.push('if True:')
290 isp.push(' a = 1')
278 isp.push(' a = 1')
291 self.assertFalse(isp.push('b = [1,'))
279 self.assertFalse(isp.push('b = [1,'))
292
280
293 def test_replace_mode(self):
281 def test_replace_mode(self):
294 isp = self.isp
282 isp = self.isp
295 isp.input_mode = 'cell'
283 isp.input_mode = 'cell'
296 isp.push('x=1')
284 isp.push('x=1')
297 self.assertEqual(isp.source, 'x=1\n')
285 self.assertEqual(isp.source, 'x=1\n')
298 isp.push('x=2')
286 isp.push('x=2')
299 self.assertEqual(isp.source, 'x=2\n')
287 self.assertEqual(isp.source, 'x=2\n')
300
288
301 def test_push_accepts_more(self):
289 def test_push_accepts_more(self):
302 isp = self.isp
290 isp = self.isp
303 isp.push('x=1')
291 isp.push('x=1')
304 self.assertFalse(isp.push_accepts_more())
292 self.assertFalse(isp.push_accepts_more())
305
293
306 def test_push_accepts_more2(self):
294 def test_push_accepts_more2(self):
307 # In cell mode, inputs must be fed in whole blocks, so skip this test
295 # In cell mode, inputs must be fed in whole blocks, so skip this test
308 if self.isp.input_mode == 'cell': return
296 if self.isp.input_mode == 'cell': return
309
297
310 isp = self.isp
298 isp = self.isp
311 isp.push('if 1:')
299 isp.push('if 1:')
312 self.assertTrue(isp.push_accepts_more())
300 self.assertTrue(isp.push_accepts_more())
313 isp.push(' x=1')
301 isp.push(' x=1')
314 self.assertTrue(isp.push_accepts_more())
302 self.assertTrue(isp.push_accepts_more())
315 isp.push('')
303 isp.push('')
316 self.assertFalse(isp.push_accepts_more())
304 self.assertFalse(isp.push_accepts_more())
317
305
318 def test_push_accepts_more3(self):
306 def test_push_accepts_more3(self):
319 isp = self.isp
307 isp = self.isp
320 isp.push("x = (2+\n3)")
308 isp.push("x = (2+\n3)")
321 self.assertFalse(isp.push_accepts_more())
309 self.assertFalse(isp.push_accepts_more())
322
310
323 def test_push_accepts_more4(self):
311 def test_push_accepts_more4(self):
324 # In cell mode, inputs must be fed in whole blocks, so skip this test
312 # In cell mode, inputs must be fed in whole blocks, so skip this test
325 if self.isp.input_mode == 'cell': return
313 if self.isp.input_mode == 'cell': return
326
314
327 isp = self.isp
315 isp = self.isp
328 # When a multiline statement contains parens or multiline strings, we
316 # When a multiline statement contains parens or multiline strings, we
329 # shouldn't get confused.
317 # shouldn't get confused.
330 # FIXME: we should be able to better handle de-dents in statements like
318 # FIXME: we should be able to better handle de-dents in statements like
331 # multiline strings and multiline expressions (continued with \ or
319 # multiline strings and multiline expressions (continued with \ or
332 # parens). Right now we aren't handling the indentation tracking quite
320 # parens). Right now we aren't handling the indentation tracking quite
333 # correctly with this, though in practice it may not be too much of a
321 # correctly with this, though in practice it may not be too much of a
334 # problem. We'll need to see.
322 # problem. We'll need to see.
335 isp.push("if 1:")
323 isp.push("if 1:")
336 isp.push(" x = (2+")
324 isp.push(" x = (2+")
337 isp.push(" 3)")
325 isp.push(" 3)")
338 self.assertTrue(isp.push_accepts_more())
326 self.assertTrue(isp.push_accepts_more())
339 isp.push(" y = 3")
327 isp.push(" y = 3")
340 self.assertTrue(isp.push_accepts_more())
328 self.assertTrue(isp.push_accepts_more())
341 isp.push('')
329 isp.push('')
342 self.assertFalse(isp.push_accepts_more())
330 self.assertFalse(isp.push_accepts_more())
343
331
344 def test_push_accepts_more5(self):
332 def test_push_accepts_more5(self):
345 # In cell mode, inputs must be fed in whole blocks, so skip this test
333 # In cell mode, inputs must be fed in whole blocks, so skip this test
346 if self.isp.input_mode == 'cell': return
334 if self.isp.input_mode == 'cell': return
347
335
348 isp = self.isp
336 isp = self.isp
349 isp.push('try:')
337 isp.push('try:')
350 isp.push(' a = 5')
338 isp.push(' a = 5')
351 isp.push('except:')
339 isp.push('except:')
352 isp.push(' raise')
340 isp.push(' raise')
353 self.assertTrue(isp.push_accepts_more())
341 self.assertTrue(isp.push_accepts_more())
354
342
355 def test_continuation(self):
343 def test_continuation(self):
356 isp = self.isp
344 isp = self.isp
357 isp.push("import os, \\")
345 isp.push("import os, \\")
358 self.assertTrue(isp.push_accepts_more())
346 self.assertTrue(isp.push_accepts_more())
359 isp.push("sys")
347 isp.push("sys")
360 self.assertFalse(isp.push_accepts_more())
348 self.assertFalse(isp.push_accepts_more())
361
349
362 def test_syntax_error(self):
350 def test_syntax_error(self):
363 isp = self.isp
351 isp = self.isp
364 # Syntax errors immediately produce a 'ready' block, so the invalid
352 # Syntax errors immediately produce a 'ready' block, so the invalid
365 # Python can be sent to the kernel for evaluation with possible ipython
353 # Python can be sent to the kernel for evaluation with possible ipython
366 # special-syntax conversion.
354 # special-syntax conversion.
367 isp.push('run foo')
355 isp.push('run foo')
368 self.assertFalse(isp.push_accepts_more())
356 self.assertFalse(isp.push_accepts_more())
369
357
370 def test_unicode(self):
358 def test_unicode(self):
371 self.isp.push(u"PΓ©rez")
359 self.isp.push(u"PΓ©rez")
372 self.isp.push(u'\xc3\xa9')
360 self.isp.push(u'\xc3\xa9')
373 self.isp.push(u"u'\xc3\xa9'")
361 self.isp.push(u"u'\xc3\xa9'")
374
362
375 def test_line_continuation(self):
363 def test_line_continuation(self):
376 """ Test issue #2108."""
364 """ Test issue #2108."""
377 isp = self.isp
365 isp = self.isp
378 # A blank line after a line continuation should not accept more
366 # A blank line after a line continuation should not accept more
379 isp.push("1 \\\n\n")
367 isp.push("1 \\\n\n")
380 self.assertFalse(isp.push_accepts_more())
368 self.assertFalse(isp.push_accepts_more())
381 # Whitespace after a \ is a SyntaxError. The only way to test that
369 # Whitespace after a \ is a SyntaxError. The only way to test that
382 # here is to test that push doesn't accept more (as with
370 # here is to test that push doesn't accept more (as with
383 # test_syntax_error() above).
371 # test_syntax_error() above).
384 isp.push(r"1 \ ")
372 isp.push(r"1 \ ")
385 self.assertFalse(isp.push_accepts_more())
373 self.assertFalse(isp.push_accepts_more())
386 # Even if the line is continuable (c.f. the regular Python
374 # Even if the line is continuable (c.f. the regular Python
387 # interpreter)
375 # interpreter)
388 isp.push(r"(1 \ ")
376 isp.push(r"(1 \ ")
389 self.assertFalse(isp.push_accepts_more())
377 self.assertFalse(isp.push_accepts_more())
390
378
391 class InteractiveLoopTestCase(unittest.TestCase):
379 class InteractiveLoopTestCase(unittest.TestCase):
392 """Tests for an interactive loop like a python shell.
380 """Tests for an interactive loop like a python shell.
393 """
381 """
394 def check_ns(self, lines, ns):
382 def check_ns(self, lines, ns):
395 """Validate that the given input lines produce the resulting namespace.
383 """Validate that the given input lines produce the resulting namespace.
396
384
397 Note: the input lines are given exactly as they would be typed in an
385 Note: the input lines are given exactly as they would be typed in an
398 auto-indenting environment, as mini_interactive_loop above already does
386 auto-indenting environment, as mini_interactive_loop above already does
399 auto-indenting and prepends spaces to the input.
387 auto-indenting and prepends spaces to the input.
400 """
388 """
401 src = mini_interactive_loop(pseudo_input(lines))
389 src = mini_interactive_loop(pseudo_input(lines))
402 test_ns = {}
390 test_ns = {}
403 exec src in test_ns
391 exec src in test_ns
404 # We can't check that the provided ns is identical to the test_ns,
392 # We can't check that the provided ns is identical to the test_ns,
405 # because Python fills test_ns with extra keys (copyright, etc). But
393 # because Python fills test_ns with extra keys (copyright, etc). But
406 # we can check that the given dict is *contained* in test_ns
394 # we can check that the given dict is *contained* in test_ns
407 for k,v in ns.iteritems():
395 for k,v in ns.iteritems():
408 self.assertEqual(test_ns[k], v)
396 self.assertEqual(test_ns[k], v)
409
397
410 def test_simple(self):
398 def test_simple(self):
411 self.check_ns(['x=1'], dict(x=1))
399 self.check_ns(['x=1'], dict(x=1))
412
400
413 def test_simple2(self):
401 def test_simple2(self):
414 self.check_ns(['if 1:', 'x=2'], dict(x=2))
402 self.check_ns(['if 1:', 'x=2'], dict(x=2))
415
403
416 def test_xy(self):
404 def test_xy(self):
417 self.check_ns(['x=1; y=2'], dict(x=1, y=2))
405 self.check_ns(['x=1; y=2'], dict(x=1, y=2))
418
406
419 def test_abc(self):
407 def test_abc(self):
420 self.check_ns(['if 1:','a=1','b=2','c=3'], dict(a=1, b=2, c=3))
408 self.check_ns(['if 1:','a=1','b=2','c=3'], dict(a=1, b=2, c=3))
421
409
422 def test_multi(self):
410 def test_multi(self):
423 self.check_ns(['x =(1+','1+','2)'], dict(x=4))
411 self.check_ns(['x =(1+','1+','2)'], dict(x=4))
424
412
425
413
426 def test_LineInfo():
414 def test_LineInfo():
427 """Simple test for LineInfo construction and str()"""
415 """Simple test for LineInfo construction and str()"""
428 linfo = isp.LineInfo(' %cd /home')
416 linfo = isp.LineInfo(' %cd /home')
429 nt.assert_equal(str(linfo), 'LineInfo [ |%|cd|/home]')
417 nt.assert_equal(str(linfo), 'LineInfo [ |%|cd|/home]')
430
418
431
419
432
420
433
421
434 class IPythonInputTestCase(InputSplitterTestCase):
422 class IPythonInputTestCase(InputSplitterTestCase):
435 """By just creating a new class whose .isp is a different instance, we
423 """By just creating a new class whose .isp is a different instance, we
436 re-run the same test battery on the new input splitter.
424 re-run the same test battery on the new input splitter.
437
425
438 In addition, this runs the tests over the syntax and syntax_ml dicts that
426 In addition, this runs the tests over the syntax and syntax_ml dicts that
439 were tested by individual functions, as part of the OO interface.
427 were tested by individual functions, as part of the OO interface.
440
428
441 It also makes some checks on the raw buffer storage.
429 It also makes some checks on the raw buffer storage.
442 """
430 """
443
431
444 def setUp(self):
432 def setUp(self):
445 self.isp = isp.IPythonInputSplitter(input_mode='line')
433 self.isp = isp.IPythonInputSplitter(input_mode='line')
446
434
447 def test_syntax(self):
435 def test_syntax(self):
448 """Call all single-line syntax tests from the main object"""
436 """Call all single-line syntax tests from the main object"""
449 isp = self.isp
437 isp = self.isp
450 for example in syntax.itervalues():
438 for example in syntax.itervalues():
451 for raw, out_t in example:
439 for raw, out_t in example:
452 if raw.startswith(' '):
440 if raw.startswith(' '):
453 continue
441 continue
454
442
455 isp.push(raw+'\n')
443 isp.push(raw+'\n')
456 out, out_raw = isp.source_raw_reset()
444 out, out_raw = isp.source_raw_reset()
457 self.assertEqual(out.rstrip(), out_t,
445 self.assertEqual(out.rstrip(), out_t,
458 tt.pair_fail_msg.format("inputsplitter",raw, out_t, out))
446 tt.pair_fail_msg.format("inputsplitter",raw, out_t, out))
459 self.assertEqual(out_raw.rstrip(), raw.rstrip())
447 self.assertEqual(out_raw.rstrip(), raw.rstrip())
460
448
461 def test_syntax_multiline(self):
449 def test_syntax_multiline(self):
462 isp = self.isp
450 isp = self.isp
463 for example in syntax_ml.itervalues():
451 for example in syntax_ml.itervalues():
464 out_t_parts = []
465 raw_parts = []
466 for line_pairs in example:
452 for line_pairs in example:
453 out_t_parts = []
454 raw_parts = []
467 for lraw, out_t_part in line_pairs:
455 for lraw, out_t_part in line_pairs:
468 isp.push(lraw)
456 if out_t_part is not None:
469 out_t_parts.append(out_t_part)
457 out_t_parts.append(out_t_part)
470 raw_parts.append(lraw)
458
459 if lraw is not None:
460 isp.push(lraw)
461 raw_parts.append(lraw)
471
462
472 out, out_raw = isp.source_raw_reset()
463 out, out_raw = isp.source_raw_reset()
473 out_t = '\n'.join(out_t_parts).rstrip()
464 out_t = '\n'.join(out_t_parts).rstrip()
474 raw = '\n'.join(raw_parts).rstrip()
465 raw = '\n'.join(raw_parts).rstrip()
475 self.assertEqual(out.rstrip(), out_t)
466 self.assertEqual(out.rstrip(), out_t)
476 self.assertEqual(out_raw.rstrip(), raw)
467 self.assertEqual(out_raw.rstrip(), raw)
477
468
478
469
479 class BlockIPythonInputTestCase(IPythonInputTestCase):
470 class BlockIPythonInputTestCase(IPythonInputTestCase):
480
471
481 # Deactivate tests that don't make sense for the block mode
472 # Deactivate tests that don't make sense for the block mode
482 test_push3 = test_split = lambda s: None
473 test_push3 = test_split = lambda s: None
483
474
484 def setUp(self):
475 def setUp(self):
485 self.isp = isp.IPythonInputSplitter(input_mode='cell')
476 self.isp = isp.IPythonInputSplitter(input_mode='cell')
486
477
487 def test_syntax_multiline(self):
478 def test_syntax_multiline(self):
488 isp = self.isp
479 isp = self.isp
489 for example in syntax_ml.itervalues():
480 for example in syntax_ml.itervalues():
490 raw_parts = []
481 raw_parts = []
491 out_t_parts = []
482 out_t_parts = []
492 for line_pairs in example:
483 for line_pairs in example:
493 for raw, out_t_part in line_pairs:
484 raw_parts, out_t_parts = zip(*line_pairs)
494 raw_parts.append(raw)
495 out_t_parts.append(out_t_part)
496
485
497 raw = '\n'.join(raw_parts)
486 raw = '\n'.join(r for r in raw_parts if r is not None)
498 out_t = '\n'.join(out_t_parts)
487 out_t = '\n'.join(o for o in out_t_parts if o is not None)
499
488
500 isp.push(raw)
489 isp.push(raw)
501 out, out_raw = isp.source_raw_reset()
490 out, out_raw = isp.source_raw_reset()
502 # Match ignoring trailing whitespace
491 # Match ignoring trailing whitespace
503 self.assertEqual(out.rstrip(), out_t.rstrip())
492 self.assertEqual(out.rstrip(), out_t.rstrip())
504 self.assertEqual(out_raw.rstrip(), raw.rstrip())
493 self.assertEqual(out_raw.rstrip(), raw.rstrip())
505
494
506 def test_syntax_multiline_cell(self):
495 def test_syntax_multiline_cell(self):
507 isp = self.isp
496 isp = self.isp
508 for example in syntax_ml.itervalues():
497 for example in syntax_ml.itervalues():
509
498
510 out_t_parts = []
499 out_t_parts = []
511 for line_pairs in example:
500 for line_pairs in example:
512 raw = '\n'.join(r for r, _ in line_pairs)
501 raw = '\n'.join(r for r, _ in line_pairs if r is not None)
513 out_t = '\n'.join(t for _,t in line_pairs)
502 out_t = '\n'.join(t for _,t in line_pairs if t is not None)
514 out = isp.transform_cell(raw)
503 out = isp.transform_cell(raw)
515 # Match ignoring trailing whitespace
504 # Match ignoring trailing whitespace
516 self.assertEqual(out.rstrip(), out_t.rstrip())
505 self.assertEqual(out.rstrip(), out_t.rstrip())
517
506
518 #-----------------------------------------------------------------------------
507 #-----------------------------------------------------------------------------
519 # Main - use as a script, mostly for developer experiments
508 # Main - use as a script, mostly for developer experiments
520 #-----------------------------------------------------------------------------
509 #-----------------------------------------------------------------------------
521
510
522 if __name__ == '__main__':
511 if __name__ == '__main__':
523 # A simple demo for interactive experimentation. This code will not get
512 # A simple demo for interactive experimentation. This code will not get
524 # picked up by any test suite.
513 # picked up by any test suite.
525 from IPython.core.inputsplitter import InputSplitter, IPythonInputSplitter
514 from IPython.core.inputsplitter import InputSplitter, IPythonInputSplitter
526
515
527 # configure here the syntax to use, prompt and whether to autoindent
516 # configure here the syntax to use, prompt and whether to autoindent
528 #isp, start_prompt = InputSplitter(), '>>> '
517 #isp, start_prompt = InputSplitter(), '>>> '
529 isp, start_prompt = IPythonInputSplitter(), 'In> '
518 isp, start_prompt = IPythonInputSplitter(), 'In> '
530
519
531 autoindent = True
520 autoindent = True
532 #autoindent = False
521 #autoindent = False
533
522
534 try:
523 try:
535 while True:
524 while True:
536 prompt = start_prompt
525 prompt = start_prompt
537 while isp.push_accepts_more():
526 while isp.push_accepts_more():
538 indent = ' '*isp.indent_spaces
527 indent = ' '*isp.indent_spaces
539 if autoindent:
528 if autoindent:
540 line = indent + raw_input(prompt+indent)
529 line = indent + raw_input(prompt+indent)
541 else:
530 else:
542 line = raw_input(prompt)
531 line = raw_input(prompt)
543 isp.push(line)
532 isp.push(line)
544 prompt = '... '
533 prompt = '... '
545
534
546 # Here we just return input so we can use it in a test suite, but a
535 # Here we just return input so we can use it in a test suite, but a
547 # real interpreter would instead send it for execution somewhere.
536 # real interpreter would instead send it for execution somewhere.
548 #src = isp.source; raise EOFError # dbg
537 #src = isp.source; raise EOFError # dbg
549 src, raw = isp.source_raw_reset()
538 src, raw = isp.source_raw_reset()
550 print 'Input source was:\n', src
539 print 'Input source was:\n', src
551 print 'Raw source was:\n', raw
540 print 'Raw source was:\n', raw
552 except EOFError:
541 except EOFError:
553 print 'Bye'
542 print 'Bye'
554
543
555 # Tests for cell magics support
544 # Tests for cell magics support
556
545
557 def test_last_blank():
546 def test_last_blank():
558 nt.assert_false(isp.last_blank(''))
547 nt.assert_false(isp.last_blank(''))
559 nt.assert_false(isp.last_blank('abc'))
548 nt.assert_false(isp.last_blank('abc'))
560 nt.assert_false(isp.last_blank('abc\n'))
549 nt.assert_false(isp.last_blank('abc\n'))
561 nt.assert_false(isp.last_blank('abc\na'))
550 nt.assert_false(isp.last_blank('abc\na'))
562
551
563 nt.assert_true(isp.last_blank('\n'))
552 nt.assert_true(isp.last_blank('\n'))
564 nt.assert_true(isp.last_blank('\n '))
553 nt.assert_true(isp.last_blank('\n '))
565 nt.assert_true(isp.last_blank('abc\n '))
554 nt.assert_true(isp.last_blank('abc\n '))
566 nt.assert_true(isp.last_blank('abc\n\n'))
555 nt.assert_true(isp.last_blank('abc\n\n'))
567 nt.assert_true(isp.last_blank('abc\nd\n\n'))
556 nt.assert_true(isp.last_blank('abc\nd\n\n'))
568 nt.assert_true(isp.last_blank('abc\nd\ne\n\n'))
557 nt.assert_true(isp.last_blank('abc\nd\ne\n\n'))
569 nt.assert_true(isp.last_blank('abc \n \n \n\n'))
558 nt.assert_true(isp.last_blank('abc \n \n \n\n'))
570
559
571
560
572 def test_last_two_blanks():
561 def test_last_two_blanks():
573 nt.assert_false(isp.last_two_blanks(''))
562 nt.assert_false(isp.last_two_blanks(''))
574 nt.assert_false(isp.last_two_blanks('abc'))
563 nt.assert_false(isp.last_two_blanks('abc'))
575 nt.assert_false(isp.last_two_blanks('abc\n'))
564 nt.assert_false(isp.last_two_blanks('abc\n'))
576 nt.assert_false(isp.last_two_blanks('abc\n\na'))
565 nt.assert_false(isp.last_two_blanks('abc\n\na'))
577 nt.assert_false(isp.last_two_blanks('abc\n \n'))
566 nt.assert_false(isp.last_two_blanks('abc\n \n'))
578 nt.assert_false(isp.last_two_blanks('abc\n\n'))
567 nt.assert_false(isp.last_two_blanks('abc\n\n'))
579
568
580 nt.assert_true(isp.last_two_blanks('\n\n'))
569 nt.assert_true(isp.last_two_blanks('\n\n'))
581 nt.assert_true(isp.last_two_blanks('\n\n '))
570 nt.assert_true(isp.last_two_blanks('\n\n '))
582 nt.assert_true(isp.last_two_blanks('\n \n'))
571 nt.assert_true(isp.last_two_blanks('\n \n'))
583 nt.assert_true(isp.last_two_blanks('abc\n\n '))
572 nt.assert_true(isp.last_two_blanks('abc\n\n '))
584 nt.assert_true(isp.last_two_blanks('abc\n\n\n'))
573 nt.assert_true(isp.last_two_blanks('abc\n\n\n'))
585 nt.assert_true(isp.last_two_blanks('abc\n\n \n'))
574 nt.assert_true(isp.last_two_blanks('abc\n\n \n'))
586 nt.assert_true(isp.last_two_blanks('abc\n\n \n '))
575 nt.assert_true(isp.last_two_blanks('abc\n\n \n '))
587 nt.assert_true(isp.last_two_blanks('abc\n\n \n \n'))
576 nt.assert_true(isp.last_two_blanks('abc\n\n \n \n'))
588 nt.assert_true(isp.last_two_blanks('abc\nd\n\n\n'))
577 nt.assert_true(isp.last_two_blanks('abc\nd\n\n\n'))
589 nt.assert_true(isp.last_two_blanks('abc\nd\ne\nf\n\n\n'))
578 nt.assert_true(isp.last_two_blanks('abc\nd\ne\nf\n\n\n'))
590
579
591
580
592 class CellMagicsCommon(object):
581 class CellMagicsCommon(object):
593
582
594 def test_whole_cell(self):
583 def test_whole_cell(self):
595 src = "%%cellm line\nbody\n"
584 src = "%%cellm line\nbody\n"
596 sp = self.sp
585 sp = self.sp
597 sp.push(src)
586 sp.push(src)
598 nt.assert_equal(sp.cell_magic_parts, ['body\n'])
587 out = sp.source_reset()
599 out = sp.source
588 ref = u"get_ipython().run_cell_magic({u}'cellm', {u}'line', {u}'body')\n"
600 ref = u"get_ipython()._run_cached_cell_magic({u}'cellm', {u}'line')\n"
601 nt.assert_equal(out, py3compat.u_format(ref))
589 nt.assert_equal(out, py3compat.u_format(ref))
602
590
603 def tearDown(self):
591 def tearDown(self):
604 self.sp.reset()
592 self.sp.reset()
605
593
606
594
607 class CellModeCellMagics(CellMagicsCommon, unittest.TestCase):
595 class CellModeCellMagics(CellMagicsCommon, unittest.TestCase):
608 sp = isp.IPythonInputSplitter(input_mode='cell')
596 sp = isp.IPythonInputSplitter(input_mode='cell')
609
597
610 def test_incremental(self):
598 def test_incremental(self):
611 sp = self.sp
599 sp = self.sp
612 src = '%%cellm line2\n'
600 src = '%%cellm line2\n'
613 sp.push(src)
601 sp.push(src)
614 nt.assert_true(sp.push_accepts_more()) #1
602 nt.assert_true(sp.push_accepts_more()) #1
615 src += '\n'
603 src += '\n'
616 sp.push(src)
604 sp.push(src)
617 # Note: if we ever change the logic to allow full blank lines (see
605 # Note: if we ever change the logic to allow full blank lines (see
618 # _handle_cell_magic), then the following test should change to true
606 # _handle_cell_magic), then the following test should change to true
619 nt.assert_false(sp.push_accepts_more()) #2
607 nt.assert_false(sp.push_accepts_more()) #2
620 # By now, even with full blanks allowed, a second blank should signal
608 # By now, even with full blanks allowed, a second blank should signal
621 # the end. For now this test is only a redundancy safety, but don't
609 # the end. For now this test is only a redundancy safety, but don't
622 # delete it in case we change our mind and the previous one goes to
610 # delete it in case we change our mind and the previous one goes to
623 # true.
611 # true.
624 src += '\n'
612 src += '\n'
625 sp.push(src)
613 sp.push(src)
626 nt.assert_false(sp.push_accepts_more()) #3
614 nt.assert_false(sp.push_accepts_more()) #3
627
615
628
616
629 class LineModeCellMagics(CellMagicsCommon, unittest.TestCase):
617 class LineModeCellMagics(CellMagicsCommon, unittest.TestCase):
630 sp = isp.IPythonInputSplitter(input_mode='line')
618 sp = isp.IPythonInputSplitter(input_mode='line')
631
619
632 def test_incremental(self):
620 def test_incremental(self):
633 sp = self.sp
621 sp = self.sp
634 sp.push('%%cellm line2\n')
622 sp.push('%%cellm line2\n')
635 nt.assert_true(sp.push_accepts_more()) #1
623 nt.assert_true(sp.push_accepts_more()) #1
636 sp.push('\n')
624 sp.push('\n')
637 nt.assert_false(sp.push_accepts_more()) #2
625 nt.assert_false(sp.push_accepts_more()) #2
@@ -1,305 +1,322 b''
1 import unittest
1 import unittest
2 import nose.tools as nt
2 import nose.tools as nt
3
3
4 from IPython.testing import tools as tt
4 from IPython.testing import tools as tt
5 from IPython.utils import py3compat
5 from IPython.utils import py3compat
6 u_fmt = py3compat.u_format
6 u_fmt = py3compat.u_format
7
7
8 from IPython.core import inputtransformer as ipt
8 from IPython.core import inputtransformer as ipt
9
9
10 def transform_and_reset(transformer):
10 def transform_and_reset(transformer):
11 transformer = transformer()
11 def transform(inp):
12 def transform(inp):
12 try:
13 try:
13 return transformer.push(inp)
14 return transformer.push(inp)
14 finally:
15 finally:
15 transformer.reset()
16 transformer.reset()
16
17
17 return transform
18 return transform
18
19
19 # Transformer tests
20 # Transformer tests
20 def transform_checker(tests, transformer):
21 def transform_checker(tests, transformer):
21 """Utility to loop over test inputs"""
22 """Utility to loop over test inputs"""
23 transformer = transformer()
22 try:
24 try:
23 for inp, tr in tests:
25 for inp, tr in tests:
24 nt.assert_equal(transformer.push(inp), tr)
26 nt.assert_equal(transformer.push(inp), tr)
25 finally:
27 finally:
26 transformer.reset()
28 transformer.reset()
27
29
28 # Data for all the syntax tests in the form of lists of pairs of
30 # Data for all the syntax tests in the form of lists of pairs of
29 # raw/transformed input. We store it here as a global dict so that we can use
31 # raw/transformed input. We store it here as a global dict so that we can use
30 # it both within single-function tests and also to validate the behavior of the
32 # it both within single-function tests and also to validate the behavior of the
31 # larger objects
33 # larger objects
32
34
33 syntax = \
35 syntax = \
34 dict(assign_system =
36 dict(assign_system =
35 [(i,py3compat.u_format(o)) for i,o in \
37 [(i,py3compat.u_format(o)) for i,o in \
36 [(u'a =! ls', "a = get_ipython().getoutput({u}'ls')"),
38 [(u'a =! ls', "a = get_ipython().getoutput({u}'ls')"),
37 (u'b = !ls', "b = get_ipython().getoutput({u}'ls')"),
39 (u'b = !ls', "b = get_ipython().getoutput({u}'ls')"),
38 ('x=1', 'x=1'), # normal input is unmodified
40 ('x=1', 'x=1'), # normal input is unmodified
39 (' ',' '), # blank lines are kept intact
41 (' ',' '), # blank lines are kept intact
40 ]],
42 ]],
41
43
42 assign_magic =
44 assign_magic =
43 [(i,py3compat.u_format(o)) for i,o in \
45 [(i,py3compat.u_format(o)) for i,o in \
44 [(u'a =% who', "a = get_ipython().magic({u}'who')"),
46 [(u'a =% who', "a = get_ipython().magic({u}'who')"),
45 (u'b = %who', "b = get_ipython().magic({u}'who')"),
47 (u'b = %who', "b = get_ipython().magic({u}'who')"),
46 ('x=1', 'x=1'), # normal input is unmodified
48 ('x=1', 'x=1'), # normal input is unmodified
47 (' ',' '), # blank lines are kept intact
49 (' ',' '), # blank lines are kept intact
48 ]],
50 ]],
49
51
50 classic_prompt =
52 classic_prompt =
51 [('>>> x=1', 'x=1'),
53 [('>>> x=1', 'x=1'),
52 ('x=1', 'x=1'), # normal input is unmodified
54 ('x=1', 'x=1'), # normal input is unmodified
53 (' ', ' '), # blank lines are kept intact
55 (' ', ' '), # blank lines are kept intact
54 ],
56 ],
55
57
56 ipy_prompt =
58 ipy_prompt =
57 [('In [1]: x=1', 'x=1'),
59 [('In [1]: x=1', 'x=1'),
58 ('x=1', 'x=1'), # normal input is unmodified
60 ('x=1', 'x=1'), # normal input is unmodified
59 (' ',' '), # blank lines are kept intact
61 (' ',' '), # blank lines are kept intact
60 ],
62 ],
61
63
62 # Tests for the escape transformer to leave normal code alone
64 # Tests for the escape transformer to leave normal code alone
63 escaped_noesc =
65 escaped_noesc =
64 [ (' ', ' '),
66 [ (' ', ' '),
65 ('x=1', 'x=1'),
67 ('x=1', 'x=1'),
66 ],
68 ],
67
69
68 # System calls
70 # System calls
69 escaped_shell =
71 escaped_shell =
70 [(i,py3compat.u_format(o)) for i,o in \
72 [(i,py3compat.u_format(o)) for i,o in \
71 [ (u'!ls', "get_ipython().system({u}'ls')"),
73 [ (u'!ls', "get_ipython().system({u}'ls')"),
72 # Double-escape shell, this means to capture the output of the
74 # Double-escape shell, this means to capture the output of the
73 # subprocess and return it
75 # subprocess and return it
74 (u'!!ls', "get_ipython().getoutput({u}'ls')"),
76 (u'!!ls', "get_ipython().getoutput({u}'ls')"),
75 ]],
77 ]],
76
78
77 # Help/object info
79 # Help/object info
78 escaped_help =
80 escaped_help =
79 [(i,py3compat.u_format(o)) for i,o in \
81 [(i,py3compat.u_format(o)) for i,o in \
80 [ (u'?', 'get_ipython().show_usage()'),
82 [ (u'?', 'get_ipython().show_usage()'),
81 (u'?x1', "get_ipython().magic({u}'pinfo x1')"),
83 (u'?x1', "get_ipython().magic({u}'pinfo x1')"),
82 (u'??x2', "get_ipython().magic({u}'pinfo2 x2')"),
84 (u'??x2', "get_ipython().magic({u}'pinfo2 x2')"),
83 (u'?a.*s', "get_ipython().magic({u}'psearch a.*s')"),
85 (u'?a.*s', "get_ipython().magic({u}'psearch a.*s')"),
84 (u'?%hist1', "get_ipython().magic({u}'pinfo %hist1')"),
86 (u'?%hist1', "get_ipython().magic({u}'pinfo %hist1')"),
85 (u'?%%hist2', "get_ipython().magic({u}'pinfo %%hist2')"),
87 (u'?%%hist2', "get_ipython().magic({u}'pinfo %%hist2')"),
86 (u'?abc = qwe', "get_ipython().magic({u}'pinfo abc')"),
88 (u'?abc = qwe', "get_ipython().magic({u}'pinfo abc')"),
87 ]],
89 ]],
88
90
89 end_help =
91 end_help =
90 [(i,py3compat.u_format(o)) for i,o in \
92 [(i,py3compat.u_format(o)) for i,o in \
91 [ (u'x3?', "get_ipython().magic({u}'pinfo x3')"),
93 [ (u'x3?', "get_ipython().magic({u}'pinfo x3')"),
92 (u'x4??', "get_ipython().magic({u}'pinfo2 x4')"),
94 (u'x4??', "get_ipython().magic({u}'pinfo2 x4')"),
93 (u'%hist1?', "get_ipython().magic({u}'pinfo %hist1')"),
95 (u'%hist1?', "get_ipython().magic({u}'pinfo %hist1')"),
94 (u'%hist2??', "get_ipython().magic({u}'pinfo2 %hist2')"),
96 (u'%hist2??', "get_ipython().magic({u}'pinfo2 %hist2')"),
95 (u'%%hist3?', "get_ipython().magic({u}'pinfo %%hist3')"),
97 (u'%%hist3?', "get_ipython().magic({u}'pinfo %%hist3')"),
96 (u'%%hist4??', "get_ipython().magic({u}'pinfo2 %%hist4')"),
98 (u'%%hist4??', "get_ipython().magic({u}'pinfo2 %%hist4')"),
97 (u'f*?', "get_ipython().magic({u}'psearch f*')"),
99 (u'f*?', "get_ipython().magic({u}'psearch f*')"),
98 (u'ax.*aspe*?', "get_ipython().magic({u}'psearch ax.*aspe*')"),
100 (u'ax.*aspe*?', "get_ipython().magic({u}'psearch ax.*aspe*')"),
99 (u'a = abc?', "get_ipython().set_next_input({u}'a = abc');"
101 (u'a = abc?', "get_ipython().set_next_input({u}'a = abc');"
100 "get_ipython().magic({u}'pinfo abc')"),
102 "get_ipython().magic({u}'pinfo abc')"),
101 (u'a = abc.qe??', "get_ipython().set_next_input({u}'a = abc.qe');"
103 (u'a = abc.qe??', "get_ipython().set_next_input({u}'a = abc.qe');"
102 "get_ipython().magic({u}'pinfo2 abc.qe')"),
104 "get_ipython().magic({u}'pinfo2 abc.qe')"),
103 (u'a = *.items?', "get_ipython().set_next_input({u}'a = *.items');"
105 (u'a = *.items?', "get_ipython().set_next_input({u}'a = *.items');"
104 "get_ipython().magic({u}'psearch *.items')"),
106 "get_ipython().magic({u}'psearch *.items')"),
105 (u'plot(a?', "get_ipython().set_next_input({u}'plot(a');"
107 (u'plot(a?', "get_ipython().set_next_input({u}'plot(a');"
106 "get_ipython().magic({u}'pinfo a')"),
108 "get_ipython().magic({u}'pinfo a')"),
107 (u'a*2 #comment?', 'a*2 #comment?'),
109 (u'a*2 #comment?', 'a*2 #comment?'),
108 ]],
110 ]],
109
111
110 # Explicit magic calls
112 # Explicit magic calls
111 escaped_magic =
113 escaped_magic =
112 [(i,py3compat.u_format(o)) for i,o in \
114 [(i,py3compat.u_format(o)) for i,o in \
113 [ (u'%cd', "get_ipython().magic({u}'cd')"),
115 [ (u'%cd', "get_ipython().magic({u}'cd')"),
114 (u'%cd /home', "get_ipython().magic({u}'cd /home')"),
116 (u'%cd /home', "get_ipython().magic({u}'cd /home')"),
115 # Backslashes need to be escaped.
117 # Backslashes need to be escaped.
116 (u'%cd C:\\User', "get_ipython().magic({u}'cd C:\\\\User')"),
118 (u'%cd C:\\User', "get_ipython().magic({u}'cd C:\\\\User')"),
117 (u' %magic', " get_ipython().magic({u}'magic')"),
119 (u' %magic', " get_ipython().magic({u}'magic')"),
118 ]],
120 ]],
119
121
120 # Quoting with separate arguments
122 # Quoting with separate arguments
121 escaped_quote =
123 escaped_quote =
122 [ (',f', 'f("")'),
124 [ (',f', 'f("")'),
123 (',f x', 'f("x")'),
125 (',f x', 'f("x")'),
124 (' ,f y', ' f("y")'),
126 (' ,f y', ' f("y")'),
125 (',f a b', 'f("a", "b")'),
127 (',f a b', 'f("a", "b")'),
126 ],
128 ],
127
129
128 # Quoting with single argument
130 # Quoting with single argument
129 escaped_quote2 =
131 escaped_quote2 =
130 [ (';f', 'f("")'),
132 [ (';f', 'f("")'),
131 (';f x', 'f("x")'),
133 (';f x', 'f("x")'),
132 (' ;f y', ' f("y")'),
134 (' ;f y', ' f("y")'),
133 (';f a b', 'f("a b")'),
135 (';f a b', 'f("a b")'),
134 ],
136 ],
135
137
136 # Simply apply parens
138 # Simply apply parens
137 escaped_paren =
139 escaped_paren =
138 [ ('/f', 'f()'),
140 [ ('/f', 'f()'),
139 ('/f x', 'f(x)'),
141 ('/f x', 'f(x)'),
140 (' /f y', ' f(y)'),
142 (' /f y', ' f(y)'),
141 ('/f a b', 'f(a, b)'),
143 ('/f a b', 'f(a, b)'),
142 ],
144 ],
143
145
144 # Check that we transform prompts before other transforms
146 # Check that we transform prompts before other transforms
145 mixed =
147 mixed =
146 [(i,py3compat.u_format(o)) for i,o in \
148 [(i,py3compat.u_format(o)) for i,o in \
147 [ (u'In [1]: %lsmagic', "get_ipython().magic({u}'lsmagic')"),
149 [ (u'In [1]: %lsmagic', "get_ipython().magic({u}'lsmagic')"),
148 (u'>>> %lsmagic', "get_ipython().magic({u}'lsmagic')"),
150 (u'>>> %lsmagic', "get_ipython().magic({u}'lsmagic')"),
149 (u'In [2]: !ls', "get_ipython().system({u}'ls')"),
151 (u'In [2]: !ls', "get_ipython().system({u}'ls')"),
150 (u'In [3]: abs?', "get_ipython().magic({u}'pinfo abs')"),
152 (u'In [3]: abs?', "get_ipython().magic({u}'pinfo abs')"),
151 (u'In [4]: b = %who', "b = get_ipython().magic({u}'who')"),
153 (u'In [4]: b = %who', "b = get_ipython().magic({u}'who')"),
152 ]],
154 ]],
153 )
155 )
154
156
155 # multiline syntax examples. Each of these should be a list of lists, with
157 # multiline syntax examples. Each of these should be a list of lists, with
156 # each entry itself having pairs of raw/transformed input. The union (with
158 # each entry itself having pairs of raw/transformed input. The union (with
157 # '\n'.join() of the transformed inputs is what the splitter should produce
159 # '\n'.join() of the transformed inputs is what the splitter should produce
158 # when fed the raw lines one at a time via push.
160 # when fed the raw lines one at a time via push.
159 syntax_ml = \
161 syntax_ml = \
160 dict(classic_prompt =
162 dict(classic_prompt =
161 [ [('>>> for i in range(10):','for i in range(10):'),
163 [ [('>>> for i in range(10):','for i in range(10):'),
162 ('... print i',' print i'),
164 ('... print i',' print i'),
163 ('... ', ''),
165 ('... ', ''),
164 ],
166 ],
165 [('>>> a="""','a="""'),
167 [('>>> a="""','a="""'),
166 ('... 123"""','123"""'),
168 ('... 123"""','123"""'),
167 ],
169 ],
168 [('a="""','a="""'),
170 [('a="""','a="""'),
169 ('... 123"""','... 123"""'),
171 ('... 123"""','... 123"""'),
170 ],
172 ],
171 ],
173 ],
172
174
173 ipy_prompt =
175 ipy_prompt =
174 [ [('In [24]: for i in range(10):','for i in range(10):'),
176 [ [('In [24]: for i in range(10):','for i in range(10):'),
175 (' ....: print i',' print i'),
177 (' ....: print i',' print i'),
176 (' ....: ', ''),
178 (' ....: ', ''),
177 ],
179 ],
178 [('In [2]: a="""','a="""'),
180 [('In [2]: a="""','a="""'),
179 (' ...: 123"""','123"""'),
181 (' ...: 123"""','123"""'),
180 ],
182 ],
181 [('a="""','a="""'),
183 [('a="""','a="""'),
182 (' ...: 123"""',' ...: 123"""'),
184 (' ...: 123"""',' ...: 123"""'),
183 ],
185 ],
184 ],
186 ],
185
187
186 multiline_datastructure =
188 multiline_datastructure =
187 [ [('>>> a = [1,','a = [1,'),
189 [ [('>>> a = [1,','a = [1,'),
188 ('... 2]','2]'),
190 ('... 2]','2]'),
189 ],
191 ],
190 ],
192 ],
191
193
192 leading_indent =
194 leading_indent =
193 [ [(' print "hi"','print "hi"'),
195 [ [(' print "hi"','print "hi"'),
194 (' for a in range(5):','for a in range(5):'),
196 ],
197 [(' for a in range(5):','for a in range(5):'),
195 (' a*2',' a*2'),
198 (' a*2',' a*2'),
196 ],
199 ],
197 [(' a="""','a="""'),
200 [(' a="""','a="""'),
198 (' 123"""','123"""'),
201 (' 123"""','123"""'),
199 ],
202 ],
200 [('a="""','a="""'),
203 [('a="""','a="""'),
201 (' 123"""',' 123"""'),
204 (' 123"""',' 123"""'),
202 ],
205 ],
203 ],
206 ],
204
207
205 cellmagic =
208 cellmagic =
206 [ [('%%foo a', None),
209 [ [(u'%%foo a', None),
207 (None, "get_ipython().run_cell_magic('foo', 'a', '')"),
210 (None, u_fmt("get_ipython().run_cell_magic({u}'foo', {u}'a', {u}'')")),
208 ],
211 ],
209 [('%%bar 123', None),
212 [(u'%%bar 123', None),
210 ('hello', None),
213 (u'hello', None),
211 ('', "get_ipython().run_cell_magic('bar', '123', 'hello')"),
214 (u'', u_fmt("get_ipython().run_cell_magic({u}'bar', {u}'123', {u}'hello')")),
212 ],
215 ],
213 ],
216 ],
214
217
215 escaped =
218 escaped =
216 [ [('%abc def \\', None),
219 [ [('%abc def \\', None),
217 ('ghi', u_fmt("get_ipython().magic({u}'abc def ghi')")),
220 ('ghi', u_fmt("get_ipython().magic({u}'abc def ghi')")),
218 ],
221 ],
219 [('%abc def \\', None),
222 [('%abc def \\', None),
220 ('ghi\\', None),
223 ('ghi\\', None),
221 (None, u_fmt("get_ipython().magic({u}'abc def ghi')")),
224 (None, u_fmt("get_ipython().magic({u}'abc def ghi')")),
222 ],
225 ],
223 ],
226 ],
224
227
225 assign_magic =
228 assign_magic =
226 [ [('a = %bc de \\', None),
229 [ [(u'a = %bc de \\', None),
227 ('fg', "a = get_ipython().magic('bc de fg')"),
230 (u'fg', u_fmt("a = get_ipython().magic({u}'bc de fg')")),
228 ],
231 ],
229 [('a = %bc de \\', None),
232 [(u'a = %bc de \\', None),
230 ('fg\\', None),
233 (u'fg\\', None),
231 (None, "a = get_ipython().magic('bc de fg')"),
234 (None, u_fmt("a = get_ipython().magic({u}'bc de fg')")),
232 ],
235 ],
233 ],
236 ],
234
237
235 assign_system =
238 assign_system =
236 [ [('a = !bc de \\', None),
239 [ [(u'a = !bc de \\', None),
237 ('fg', "a = get_ipython().getoutput('bc de fg')"),
240 (u'fg', u_fmt("a = get_ipython().getoutput({u}'bc de fg')")),
238 ],
241 ],
239 [('a = !bc de \\', None),
242 [(u'a = !bc de \\', None),
240 ('fg\\', None),
243 (u'fg\\', None),
241 (None, "a = get_ipython().getoutput('bc de fg')"),
244 (None, u_fmt("a = get_ipython().getoutput({u}'bc de fg')")),
242 ],
245 ],
243 ],
246 ],
244 )
247 )
245
248
246
249
247 def test_assign_system():
250 def test_assign_system():
248 tt.check_pairs(transform_and_reset(ipt.assign_from_system), syntax['assign_system'])
251 tt.check_pairs(transform_and_reset(ipt.assign_from_system), syntax['assign_system'])
249 for example in syntax_ml['assign_system']:
252 for example in syntax_ml['assign_system']:
250 transform_checker(example, ipt.assign_from_system)
253 transform_checker(example, ipt.assign_from_system)
251
254
252 def test_assign_magic():
255 def test_assign_magic():
253 tt.check_pairs(transform_and_reset(ipt.assign_from_magic), syntax['assign_magic'])
256 tt.check_pairs(transform_and_reset(ipt.assign_from_magic), syntax['assign_magic'])
254 for example in syntax_ml['assign_magic']:
257 for example in syntax_ml['assign_magic']:
255 transform_checker(example, ipt.assign_from_magic)
258 transform_checker(example, ipt.assign_from_magic)
256
259
257
260
258 def test_classic_prompt():
261 def test_classic_prompt():
259 tt.check_pairs(transform_and_reset(ipt.classic_prompt), syntax['classic_prompt'])
262 tt.check_pairs(transform_and_reset(ipt.classic_prompt), syntax['classic_prompt'])
260 for example in syntax_ml['classic_prompt']:
263 for example in syntax_ml['classic_prompt']:
261 transform_checker(example, ipt.classic_prompt)
264 transform_checker(example, ipt.classic_prompt)
265 for example in syntax_ml['multiline_datastructure']:
266 transform_checker(example, ipt.classic_prompt)
262
267
263
268
264 def test_ipy_prompt():
269 def test_ipy_prompt():
265 tt.check_pairs(transform_and_reset(ipt.ipy_prompt), syntax['ipy_prompt'])
270 tt.check_pairs(transform_and_reset(ipt.ipy_prompt), syntax['ipy_prompt'])
266 for example in syntax_ml['ipy_prompt']:
271 for example in syntax_ml['ipy_prompt']:
267 transform_checker(example, ipt.ipy_prompt)
272 transform_checker(example, ipt.ipy_prompt)
268
273
269 def test_help_end():
274 def test_help_end():
270 tt.check_pairs(transform_and_reset(ipt.help_end), syntax['end_help'])
275 tt.check_pairs(transform_and_reset(ipt.help_end), syntax['end_help'])
271
276
272 def test_escaped_noesc():
277 def test_escaped_noesc():
273 tt.check_pairs(transform_and_reset(ipt.escaped_transformer), syntax['escaped_noesc'])
278 tt.check_pairs(transform_and_reset(ipt.escaped_transformer), syntax['escaped_noesc'])
274
279
275
280
276 def test_escaped_shell():
281 def test_escaped_shell():
277 tt.check_pairs(transform_and_reset(ipt.escaped_transformer), syntax['escaped_shell'])
282 tt.check_pairs(transform_and_reset(ipt.escaped_transformer), syntax['escaped_shell'])
278
283
279
284
280 def test_escaped_help():
285 def test_escaped_help():
281 tt.check_pairs(transform_and_reset(ipt.escaped_transformer), syntax['escaped_help'])
286 tt.check_pairs(transform_and_reset(ipt.escaped_transformer), syntax['escaped_help'])
282
287
283
288
284 def test_escaped_magic():
289 def test_escaped_magic():
285 tt.check_pairs(transform_and_reset(ipt.escaped_transformer), syntax['escaped_magic'])
290 tt.check_pairs(transform_and_reset(ipt.escaped_transformer), syntax['escaped_magic'])
286
291
287
292
288 def test_escaped_quote():
293 def test_escaped_quote():
289 tt.check_pairs(transform_and_reset(ipt.escaped_transformer), syntax['escaped_quote'])
294 tt.check_pairs(transform_and_reset(ipt.escaped_transformer), syntax['escaped_quote'])
290
295
291
296
292 def test_escaped_quote2():
297 def test_escaped_quote2():
293 tt.check_pairs(transform_and_reset(ipt.escaped_transformer), syntax['escaped_quote2'])
298 tt.check_pairs(transform_and_reset(ipt.escaped_transformer), syntax['escaped_quote2'])
294
299
295
300
296 def test_escaped_paren():
301 def test_escaped_paren():
297 tt.check_pairs(transform_and_reset(ipt.escaped_transformer), syntax['escaped_paren'])
302 tt.check_pairs(transform_and_reset(ipt.escaped_transformer), syntax['escaped_paren'])
298
303
299 def test_escaped_multiline():
304 def test_escaped_multiline():
300 for example in syntax_ml['escaped']:
305 for example in syntax_ml['escaped']:
301 transform_checker(example, ipt.escaped_transformer)
306 transform_checker(example, ipt.escaped_transformer)
302
307
303 def test_cellmagic():
308 def test_cellmagic():
304 for example in syntax_ml['cellmagic']:
309 for example in syntax_ml['cellmagic']:
305 transform_checker(example, ipt.cellmagic)
310 transform_checker(example, ipt.cellmagic)
311
312 def test_has_comment():
313 tests = [('text', False),
314 ('text #comment', True),
315 ('text #comment\n', True),
316 ('#comment', True),
317 ('#comment\n', True),
318 ('a = "#string"', False),
319 ('a = "#string" # comment', True),
320 ('a #comment not "string"', True),
321 ]
322 tt.check_pairs(ipt.has_comment, tests)
General Comments 0
You need to be logged in to leave comments. Login now