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