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