##// END OF EJS Templates
Reuse common code for inputsplitter and prefilter.
Thomas Kluyver -
Show More
@@ -0,0 +1,26 b''
1 from IPython.core.splitinput import split_user_input
2 from IPython.testing import tools as tt
3
4 tests = [
5 ('x=1', ('', '', 'x', '=1')),
6 ('?', ('', '?', '', '')),
7 ('??', ('', '??', '', '')),
8 (' ?', (' ', '?', '', '')),
9 (' ??', (' ', '??', '', '')),
10 ('??x', ('', '??', 'x', '')),
11 ('?x=1', ('', '?', 'x', '=1')),
12 ('!ls', ('', '!', 'ls', '')),
13 (' !ls', (' ', '!', 'ls', '')),
14 ('!!ls', ('', '!!', 'ls', '')),
15 (' !!ls', (' ', '!!', 'ls', '')),
16 (',ls', ('', ',', 'ls', '')),
17 (';ls', ('', ';', 'ls', '')),
18 (' ;ls', (' ', ';', 'ls', '')),
19 ('f.g(x)', ('', '', 'f.g', '(x)')),
20 ('f.g (x)', ('', '', 'f.g', '(x)')),
21 ('?%hist', ('', '?', '%hist', '')),
22 ('?x*', ('', '?', 'x*', '')),
23 ]
24
25 def test_split_user_input():
26 return tt.check_pairs(split_user_input, tests)
@@ -1,892 +1,770 b''
1 """Analysis of text input into executable blocks.
1 """Analysis of text input into executable blocks.
2
2
3 The main class in this module, :class:`InputSplitter`, is designed to break
3 The main class in this module, :class:`InputSplitter`, is designed to break
4 input from either interactive, line-by-line environments or block-based ones,
4 input from either interactive, line-by-line environments or block-based ones,
5 into standalone blocks that can be executed by Python as 'single' statements
5 into standalone blocks that can be executed by Python as 'single' statements
6 (thus triggering sys.displayhook).
6 (thus triggering sys.displayhook).
7
7
8 A companion, :class:`IPythonInputSplitter`, provides the same functionality but
8 A companion, :class:`IPythonInputSplitter`, provides the same functionality but
9 with full support for the extended IPython syntax (magics, system calls, etc).
9 with full support for the extended IPython syntax (magics, system calls, etc).
10
10
11 For more details, see the class docstring below.
11 For more details, see the class docstring below.
12
12
13 Syntax Transformations
13 Syntax Transformations
14 ----------------------
14 ----------------------
15
15
16 One of the main jobs of the code in this file is to apply all syntax
16 One of the main jobs of the code in this file is to apply all syntax
17 transformations that make up 'the IPython language', i.e. magics, shell
17 transformations that make up 'the IPython language', i.e. magics, shell
18 escapes, etc. All transformations should be implemented as *fully stateless*
18 escapes, etc. All transformations should be implemented as *fully stateless*
19 entities, that simply take one line as their input and return a line.
19 entities, that simply take one line as their input and return a line.
20 Internally for implementation purposes they may be a normal function or a
20 Internally for implementation purposes they may be a normal function or a
21 callable object, but the only input they receive will be a single line and they
21 callable object, but the only input they receive will be a single line and they
22 should only return a line, without holding any data-dependent state between
22 should only return a line, without holding any data-dependent state between
23 calls.
23 calls.
24
24
25 As an example, the EscapedTransformer is a class so we can more clearly group
25 As an example, the EscapedTransformer is a class so we can more clearly group
26 together the functionality of dispatching to individual functions based on the
26 together the functionality of dispatching to individual functions based on the
27 starting escape character, but the only method for public use is its call
27 starting escape character, but the only method for public use is its call
28 method.
28 method.
29
29
30
30
31 ToDo
31 ToDo
32 ----
32 ----
33
33
34 - Should we make push() actually raise an exception once push_accepts_more()
34 - Should we make push() actually raise an exception once push_accepts_more()
35 returns False?
35 returns False?
36
36
37 - Naming cleanups. The tr_* names aren't the most elegant, though now they are
37 - Naming cleanups. The tr_* names aren't the most elegant, though now they are
38 at least just attributes of a class so not really very exposed.
38 at least just attributes of a class so not really very exposed.
39
39
40 - Think about the best way to support dynamic things: automagic, autocall,
40 - Think about the best way to support dynamic things: automagic, autocall,
41 macros, etc.
41 macros, etc.
42
42
43 - Think of a better heuristic for the application of the transforms in
43 - Think of a better heuristic for the application of the transforms in
44 IPythonInputSplitter.push() than looking at the buffer ending in ':'. Idea:
44 IPythonInputSplitter.push() than looking at the buffer ending in ':'. Idea:
45 track indentation change events (indent, dedent, nothing) and apply them only
45 track indentation change events (indent, dedent, nothing) and apply them only
46 if the indentation went up, but not otherwise.
46 if the indentation went up, but not otherwise.
47
47
48 - Think of the cleanest way for supporting user-specified transformations (the
48 - Think of the cleanest way for supporting user-specified transformations (the
49 user prefilters we had before).
49 user prefilters we had before).
50
50
51 Authors
51 Authors
52 -------
52 -------
53
53
54 * Fernando Perez
54 * Fernando Perez
55 * Brian Granger
55 * Brian Granger
56 """
56 """
57 #-----------------------------------------------------------------------------
57 #-----------------------------------------------------------------------------
58 # Copyright (C) 2010 The IPython Development Team
58 # Copyright (C) 2010 The IPython Development Team
59 #
59 #
60 # Distributed under the terms of the BSD License. The full license is in
60 # Distributed under the terms of the BSD License. The full license is in
61 # the file COPYING, distributed as part of this software.
61 # the file COPYING, distributed as part of this software.
62 #-----------------------------------------------------------------------------
62 #-----------------------------------------------------------------------------
63 from __future__ import print_function
63 from __future__ import print_function
64
64
65 #-----------------------------------------------------------------------------
65 #-----------------------------------------------------------------------------
66 # Imports
66 # Imports
67 #-----------------------------------------------------------------------------
67 #-----------------------------------------------------------------------------
68 # stdlib
68 # stdlib
69 import ast
69 import ast
70 import codeop
70 import codeop
71 import re
71 import re
72 import sys
72 import sys
73 import tokenize
73 import tokenize
74 from StringIO import StringIO
74 from StringIO import StringIO
75
75
76 # IPython modules
76 # IPython modules
77 from IPython.core.splitinput import split_user_input, LineInfo
77 from IPython.utils.text import make_quoted_expr
78 from IPython.utils.text import make_quoted_expr
78 from IPython.utils.py3compat import cast_unicode
79 from IPython.utils.py3compat import cast_unicode
79
80
80 #-----------------------------------------------------------------------------
81 #-----------------------------------------------------------------------------
81 # Globals
82 # Globals
82 #-----------------------------------------------------------------------------
83 #-----------------------------------------------------------------------------
83
84
84 # The escape sequences that define the syntax transformations IPython will
85 # The escape sequences that define the syntax transformations IPython will
85 # apply to user input. These can NOT be just changed here: many regular
86 # apply to user input. These can NOT be just changed here: many regular
86 # expressions and other parts of the code may use their hardcoded values, and
87 # expressions and other parts of the code may use their hardcoded values, and
87 # for all intents and purposes they constitute the 'IPython syntax', so they
88 # for all intents and purposes they constitute the 'IPython syntax', so they
88 # should be considered fixed.
89 # should be considered fixed.
89
90
90 ESC_SHELL = '!' # Send line to underlying system shell
91 ESC_SHELL = '!' # Send line to underlying system shell
91 ESC_SH_CAP = '!!' # Send line to system shell and capture output
92 ESC_SH_CAP = '!!' # Send line to system shell and capture output
92 ESC_HELP = '?' # Find information about object
93 ESC_HELP = '?' # Find information about object
93 ESC_HELP2 = '??' # Find extra-detailed information about object
94 ESC_HELP2 = '??' # Find extra-detailed information about object
94 ESC_MAGIC = '%' # Call magic function
95 ESC_MAGIC = '%' # Call magic function
95 ESC_QUOTE = ',' # Split args on whitespace, quote each as string and call
96 ESC_QUOTE = ',' # Split args on whitespace, quote each as string and call
96 ESC_QUOTE2 = ';' # Quote all args as a single string, call
97 ESC_QUOTE2 = ';' # Quote all args as a single string, call
97 ESC_PAREN = '/' # Call first argument with rest of line as arguments
98 ESC_PAREN = '/' # Call first argument with rest of line as arguments
98
99
99 #-----------------------------------------------------------------------------
100 #-----------------------------------------------------------------------------
100 # Utilities
101 # Utilities
101 #-----------------------------------------------------------------------------
102 #-----------------------------------------------------------------------------
102
103
103 # FIXME: These are general-purpose utilities that later can be moved to the
104 # FIXME: These are general-purpose utilities that later can be moved to the
104 # general ward. Kept here for now because we're being very strict about test
105 # general ward. Kept here for now because we're being very strict about test
105 # coverage with this code, and this lets us ensure that we keep 100% coverage
106 # coverage with this code, and this lets us ensure that we keep 100% coverage
106 # while developing.
107 # while developing.
107
108
108 # compiled regexps for autoindent management
109 # compiled regexps for autoindent management
109 dedent_re = re.compile('|'.join([
110 dedent_re = re.compile('|'.join([
110 r'^\s+raise(\s.*)?$', # raise statement (+ space + other stuff, maybe)
111 r'^\s+raise(\s.*)?$', # raise statement (+ space + other stuff, maybe)
111 r'^\s+raise\([^\)]*\).*$', # wacky raise with immediate open paren
112 r'^\s+raise\([^\)]*\).*$', # wacky raise with immediate open paren
112 r'^\s+return(\s.*)?$', # normal return (+ space + other stuff, maybe)
113 r'^\s+return(\s.*)?$', # normal return (+ space + other stuff, maybe)
113 r'^\s+return\([^\)]*\).*$', # wacky return with immediate open paren
114 r'^\s+return\([^\)]*\).*$', # wacky return with immediate open paren
114 r'^\s+pass\s*$' # pass (optionally followed by trailing spaces)
115 r'^\s+pass\s*$' # pass (optionally followed by trailing spaces)
115 ]))
116 ]))
116 ini_spaces_re = re.compile(r'^([ \t\r\f\v]+)')
117 ini_spaces_re = re.compile(r'^([ \t\r\f\v]+)')
117
118
118 # regexp to match pure comment lines so we don't accidentally insert 'if 1:'
119 # regexp to match pure comment lines so we don't accidentally insert 'if 1:'
119 # before pure comments
120 # before pure comments
120 comment_line_re = re.compile('^\s*\#')
121 comment_line_re = re.compile('^\s*\#')
121
122
122
123
123 def num_ini_spaces(s):
124 def num_ini_spaces(s):
124 """Return the number of initial spaces in a string.
125 """Return the number of initial spaces in a string.
125
126
126 Note that tabs are counted as a single space. For now, we do *not* support
127 Note that tabs are counted as a single space. For now, we do *not* support
127 mixing of tabs and spaces in the user's input.
128 mixing of tabs and spaces in the user's input.
128
129
129 Parameters
130 Parameters
130 ----------
131 ----------
131 s : string
132 s : string
132
133
133 Returns
134 Returns
134 -------
135 -------
135 n : int
136 n : int
136 """
137 """
137
138
138 ini_spaces = ini_spaces_re.match(s)
139 ini_spaces = ini_spaces_re.match(s)
139 if ini_spaces:
140 if ini_spaces:
140 return ini_spaces.end()
141 return ini_spaces.end()
141 else:
142 else:
142 return 0
143 return 0
143
144
144
145
145 def remove_comments(src):
146 def remove_comments(src):
146 """Remove all comments from input source.
147 """Remove all comments from input source.
147
148
148 Note: comments are NOT recognized inside of strings!
149 Note: comments are NOT recognized inside of strings!
149
150
150 Parameters
151 Parameters
151 ----------
152 ----------
152 src : string
153 src : string
153 A single or multiline input string.
154 A single or multiline input string.
154
155
155 Returns
156 Returns
156 -------
157 -------
157 String with all Python comments removed.
158 String with all Python comments removed.
158 """
159 """
159
160
160 return re.sub('#.*', '', src)
161 return re.sub('#.*', '', src)
161
162
162 def has_comment(src):
163 def has_comment(src):
163 """Indicate whether an input line has (i.e. ends in, or is) a comment.
164 """Indicate whether an input line has (i.e. ends in, or is) a comment.
164
165
165 This uses tokenize, so it can distinguish comments from # inside strings.
166 This uses tokenize, so it can distinguish comments from # inside strings.
166
167
167 Parameters
168 Parameters
168 ----------
169 ----------
169 src : string
170 src : string
170 A single line input string.
171 A single line input string.
171
172
172 Returns
173 Returns
173 -------
174 -------
174 Boolean: True if source has a comment.
175 Boolean: True if source has a comment.
175 """
176 """
176 readline = StringIO(src).readline
177 readline = StringIO(src).readline
177 toktypes = set()
178 toktypes = set()
178 try:
179 try:
179 for t in tokenize.generate_tokens(readline):
180 for t in tokenize.generate_tokens(readline):
180 toktypes.add(t[0])
181 toktypes.add(t[0])
181 except tokenize.TokenError:
182 except tokenize.TokenError:
182 pass
183 pass
183 return(tokenize.COMMENT in toktypes)
184 return(tokenize.COMMENT in toktypes)
184
185
185
186
186 def get_input_encoding():
187 def get_input_encoding():
187 """Return the default standard input encoding.
188 """Return the default standard input encoding.
188
189
189 If sys.stdin has no encoding, 'ascii' is returned."""
190 If sys.stdin has no encoding, 'ascii' is returned."""
190 # There are strange environments for which sys.stdin.encoding is None. We
191 # There are strange environments for which sys.stdin.encoding is None. We
191 # ensure that a valid encoding is returned.
192 # ensure that a valid encoding is returned.
192 encoding = getattr(sys.stdin, 'encoding', None)
193 encoding = getattr(sys.stdin, 'encoding', None)
193 if encoding is None:
194 if encoding is None:
194 encoding = 'ascii'
195 encoding = 'ascii'
195 return encoding
196 return encoding
196
197
197 #-----------------------------------------------------------------------------
198 #-----------------------------------------------------------------------------
198 # Classes and functions for normal Python syntax handling
199 # Classes and functions for normal Python syntax handling
199 #-----------------------------------------------------------------------------
200 #-----------------------------------------------------------------------------
200
201
201 class InputSplitter(object):
202 class InputSplitter(object):
202 """An object that can accumulate lines of Python source before execution.
203 """An object that can accumulate lines of Python source before execution.
203
204
204 This object is designed to be fed python source line-by-line, using
205 This object is designed to be fed python source line-by-line, using
205 :meth:`push`. It will return on each push whether the currently pushed
206 :meth:`push`. It will return on each push whether the currently pushed
206 code could be executed already. In addition, it provides a method called
207 code could be executed already. In addition, it provides a method called
207 :meth:`push_accepts_more` that can be used to query whether more input
208 :meth:`push_accepts_more` that can be used to query whether more input
208 can be pushed into a single interactive block.
209 can be pushed into a single interactive block.
209
210
210 This is a simple example of how an interactive terminal-based client can use
211 This is a simple example of how an interactive terminal-based client can use
211 this tool::
212 this tool::
212
213
213 isp = InputSplitter()
214 isp = InputSplitter()
214 while isp.push_accepts_more():
215 while isp.push_accepts_more():
215 indent = ' '*isp.indent_spaces
216 indent = ' '*isp.indent_spaces
216 prompt = '>>> ' + indent
217 prompt = '>>> ' + indent
217 line = indent + raw_input(prompt)
218 line = indent + raw_input(prompt)
218 isp.push(line)
219 isp.push(line)
219 print 'Input source was:\n', isp.source_reset(),
220 print 'Input source was:\n', isp.source_reset(),
220 """
221 """
221 # Number of spaces of indentation computed from input that has been pushed
222 # Number of spaces of indentation computed from input that has been pushed
222 # so far. This is the attributes callers should query to get the current
223 # so far. This is the attributes callers should query to get the current
223 # indentation level, in order to provide auto-indent facilities.
224 # indentation level, in order to provide auto-indent facilities.
224 indent_spaces = 0
225 indent_spaces = 0
225 # String, indicating the default input encoding. It is computed by default
226 # String, indicating the default input encoding. It is computed by default
226 # at initialization time via get_input_encoding(), but it can be reset by a
227 # at initialization time via get_input_encoding(), but it can be reset by a
227 # client with specific knowledge of the encoding.
228 # client with specific knowledge of the encoding.
228 encoding = ''
229 encoding = ''
229 # String where the current full source input is stored, properly encoded.
230 # String where the current full source input is stored, properly encoded.
230 # Reading this attribute is the normal way of querying the currently pushed
231 # Reading this attribute is the normal way of querying the currently pushed
231 # source code, that has been properly encoded.
232 # source code, that has been properly encoded.
232 source = ''
233 source = ''
233 # Code object corresponding to the current source. It is automatically
234 # Code object corresponding to the current source. It is automatically
234 # synced to the source, so it can be queried at any time to obtain the code
235 # synced to the source, so it can be queried at any time to obtain the code
235 # object; it will be None if the source doesn't compile to valid Python.
236 # object; it will be None if the source doesn't compile to valid Python.
236 code = None
237 code = None
237 # Input mode
238 # Input mode
238 input_mode = 'line'
239 input_mode = 'line'
239
240
240 # Private attributes
241 # Private attributes
241
242
242 # List with lines of input accumulated so far
243 # List with lines of input accumulated so far
243 _buffer = None
244 _buffer = None
244 # Command compiler
245 # Command compiler
245 _compile = None
246 _compile = None
246 # Mark when input has changed indentation all the way back to flush-left
247 # Mark when input has changed indentation all the way back to flush-left
247 _full_dedent = False
248 _full_dedent = False
248 # Boolean indicating whether the current block is complete
249 # Boolean indicating whether the current block is complete
249 _is_complete = None
250 _is_complete = None
250
251
251 def __init__(self, input_mode=None):
252 def __init__(self, input_mode=None):
252 """Create a new InputSplitter instance.
253 """Create a new InputSplitter instance.
253
254
254 Parameters
255 Parameters
255 ----------
256 ----------
256 input_mode : str
257 input_mode : str
257
258
258 One of ['line', 'cell']; default is 'line'.
259 One of ['line', 'cell']; default is 'line'.
259
260
260 The input_mode parameter controls how new inputs are used when fed via
261 The input_mode parameter controls how new inputs are used when fed via
261 the :meth:`push` method:
262 the :meth:`push` method:
262
263
263 - 'line': meant for line-oriented clients, inputs are appended one at a
264 - 'line': meant for line-oriented clients, inputs are appended one at a
264 time to the internal buffer and the whole buffer is compiled.
265 time to the internal buffer and the whole buffer is compiled.
265
266
266 - 'cell': meant for clients that can edit multi-line 'cells' of text at
267 - 'cell': meant for clients that can edit multi-line 'cells' of text at
267 a time. A cell can contain one or more blocks that can be compile in
268 a time. A cell can contain one or more blocks that can be compile in
268 'single' mode by Python. In this mode, each new input new input
269 'single' mode by Python. In this mode, each new input new input
269 completely replaces all prior inputs. Cell mode is thus equivalent
270 completely replaces all prior inputs. Cell mode is thus equivalent
270 to prepending a full reset() to every push() call.
271 to prepending a full reset() to every push() call.
271 """
272 """
272 self._buffer = []
273 self._buffer = []
273 self._compile = codeop.CommandCompiler()
274 self._compile = codeop.CommandCompiler()
274 self.encoding = get_input_encoding()
275 self.encoding = get_input_encoding()
275 self.input_mode = InputSplitter.input_mode if input_mode is None \
276 self.input_mode = InputSplitter.input_mode if input_mode is None \
276 else input_mode
277 else input_mode
277
278
278 def reset(self):
279 def reset(self):
279 """Reset the input buffer and associated state."""
280 """Reset the input buffer and associated state."""
280 self.indent_spaces = 0
281 self.indent_spaces = 0
281 self._buffer[:] = []
282 self._buffer[:] = []
282 self.source = ''
283 self.source = ''
283 self.code = None
284 self.code = None
284 self._is_complete = False
285 self._is_complete = False
285 self._full_dedent = False
286 self._full_dedent = False
286
287
287 def source_reset(self):
288 def source_reset(self):
288 """Return the input source and perform a full reset.
289 """Return the input source and perform a full reset.
289 """
290 """
290 out = self.source
291 out = self.source
291 self.reset()
292 self.reset()
292 return out
293 return out
293
294
294 def push(self, lines):
295 def push(self, lines):
295 """Push one or more lines of input.
296 """Push one or more lines of input.
296
297
297 This stores the given lines and returns a status code indicating
298 This stores the given lines and returns a status code indicating
298 whether the code forms a complete Python block or not.
299 whether the code forms a complete Python block or not.
299
300
300 Any exceptions generated in compilation are swallowed, but if an
301 Any exceptions generated in compilation are swallowed, but if an
301 exception was produced, the method returns True.
302 exception was produced, the method returns True.
302
303
303 Parameters
304 Parameters
304 ----------
305 ----------
305 lines : string
306 lines : string
306 One or more lines of Python input.
307 One or more lines of Python input.
307
308
308 Returns
309 Returns
309 -------
310 -------
310 is_complete : boolean
311 is_complete : boolean
311 True if the current input source (the result of the current input
312 True if the current input source (the result of the current input
312 plus prior inputs) forms a complete Python execution block. Note that
313 plus prior inputs) forms a complete Python execution block. Note that
313 this value is also stored as a private attribute (_is_complete), so it
314 this value is also stored as a private attribute (_is_complete), so it
314 can be queried at any time.
315 can be queried at any time.
315 """
316 """
316 if self.input_mode == 'cell':
317 if self.input_mode == 'cell':
317 self.reset()
318 self.reset()
318
319
319 self._store(lines)
320 self._store(lines)
320 source = self.source
321 source = self.source
321
322
322 # Before calling _compile(), reset the code object to None so that if an
323 # Before calling _compile(), reset the code object to None so that if an
323 # exception is raised in compilation, we don't mislead by having
324 # exception is raised in compilation, we don't mislead by having
324 # inconsistent code/source attributes.
325 # inconsistent code/source attributes.
325 self.code, self._is_complete = None, None
326 self.code, self._is_complete = None, None
326
327
327 # Honor termination lines properly
328 # Honor termination lines properly
328 if source.rstrip().endswith('\\'):
329 if source.rstrip().endswith('\\'):
329 return False
330 return False
330
331
331 self._update_indent(lines)
332 self._update_indent(lines)
332 try:
333 try:
333 self.code = self._compile(source, symbol="exec")
334 self.code = self._compile(source, symbol="exec")
334 # Invalid syntax can produce any of a number of different errors from
335 # Invalid syntax can produce any of a number of different errors from
335 # inside the compiler, so we have to catch them all. Syntax errors
336 # inside the compiler, so we have to catch them all. Syntax errors
336 # immediately produce a 'ready' block, so the invalid Python can be
337 # immediately produce a 'ready' block, so the invalid Python can be
337 # sent to the kernel for evaluation with possible ipython
338 # sent to the kernel for evaluation with possible ipython
338 # special-syntax conversion.
339 # special-syntax conversion.
339 except (SyntaxError, OverflowError, ValueError, TypeError,
340 except (SyntaxError, OverflowError, ValueError, TypeError,
340 MemoryError):
341 MemoryError):
341 self._is_complete = True
342 self._is_complete = True
342 else:
343 else:
343 # Compilation didn't produce any exceptions (though it may not have
344 # Compilation didn't produce any exceptions (though it may not have
344 # given a complete code object)
345 # given a complete code object)
345 self._is_complete = self.code is not None
346 self._is_complete = self.code is not None
346
347
347 return self._is_complete
348 return self._is_complete
348
349
349 def push_accepts_more(self):
350 def push_accepts_more(self):
350 """Return whether a block of interactive input can accept more input.
351 """Return whether a block of interactive input can accept more input.
351
352
352 This method is meant to be used by line-oriented frontends, who need to
353 This method is meant to be used by line-oriented frontends, who need to
353 guess whether a block is complete or not based solely on prior and
354 guess whether a block is complete or not based solely on prior and
354 current input lines. The InputSplitter considers it has a complete
355 current input lines. The InputSplitter considers it has a complete
355 interactive block and will not accept more input only when either a
356 interactive block and will not accept more input only when either a
356 SyntaxError is raised, or *all* of the following are true:
357 SyntaxError is raised, or *all* of the following are true:
357
358
358 1. The input compiles to a complete statement.
359 1. The input compiles to a complete statement.
359
360
360 2. The indentation level is flush-left (because if we are indented,
361 2. The indentation level is flush-left (because if we are indented,
361 like inside a function definition or for loop, we need to keep
362 like inside a function definition or for loop, we need to keep
362 reading new input).
363 reading new input).
363
364
364 3. There is one extra line consisting only of whitespace.
365 3. There is one extra line consisting only of whitespace.
365
366
366 Because of condition #3, this method should be used only by
367 Because of condition #3, this method should be used only by
367 *line-oriented* frontends, since it means that intermediate blank lines
368 *line-oriented* frontends, since it means that intermediate blank lines
368 are not allowed in function definitions (or any other indented block).
369 are not allowed in function definitions (or any other indented block).
369
370
370 If the current input produces a syntax error, this method immediately
371 If the current input produces a syntax error, this method immediately
371 returns False but does *not* raise the syntax error exception, as
372 returns False but does *not* raise the syntax error exception, as
372 typically clients will want to send invalid syntax to an execution
373 typically clients will want to send invalid syntax to an execution
373 backend which might convert the invalid syntax into valid Python via
374 backend which might convert the invalid syntax into valid Python via
374 one of the dynamic IPython mechanisms.
375 one of the dynamic IPython mechanisms.
375 """
376 """
376
377
377 # With incomplete input, unconditionally accept more
378 # With incomplete input, unconditionally accept more
378 if not self._is_complete:
379 if not self._is_complete:
379 return True
380 return True
380
381
381 # If we already have complete input and we're flush left, the answer
382 # If we already have complete input and we're flush left, the answer
382 # depends. In line mode, if there hasn't been any indentation,
383 # depends. In line mode, if there hasn't been any indentation,
383 # that's it. If we've come back from some indentation, we need
384 # that's it. If we've come back from some indentation, we need
384 # the blank final line to finish.
385 # the blank final line to finish.
385 # In cell mode, we need to check how many blocks the input so far
386 # In cell mode, we need to check how many blocks the input so far
386 # compiles into, because if there's already more than one full
387 # compiles into, because if there's already more than one full
387 # independent block of input, then the client has entered full
388 # independent block of input, then the client has entered full
388 # 'cell' mode and is feeding lines that each is complete. In this
389 # 'cell' mode and is feeding lines that each is complete. In this
389 # case we should then keep accepting. The Qt terminal-like console
390 # case we should then keep accepting. The Qt terminal-like console
390 # does precisely this, to provide the convenience of terminal-like
391 # does precisely this, to provide the convenience of terminal-like
391 # input of single expressions, but allowing the user (with a
392 # input of single expressions, but allowing the user (with a
392 # separate keystroke) to switch to 'cell' mode and type multiple
393 # separate keystroke) to switch to 'cell' mode and type multiple
393 # expressions in one shot.
394 # expressions in one shot.
394 if self.indent_spaces==0:
395 if self.indent_spaces==0:
395 if self.input_mode=='line':
396 if self.input_mode=='line':
396 if not self._full_dedent:
397 if not self._full_dedent:
397 return False
398 return False
398 else:
399 else:
399 try:
400 try:
400 code_ast = ast.parse(u''.join(self._buffer))
401 code_ast = ast.parse(u''.join(self._buffer))
401 except Exception:
402 except Exception:
402 return False
403 return False
403 else:
404 else:
404 if len(code_ast.body) == 1:
405 if len(code_ast.body) == 1:
405 return False
406 return False
406
407
407 # When input is complete, then termination is marked by an extra blank
408 # When input is complete, then termination is marked by an extra blank
408 # line at the end.
409 # line at the end.
409 last_line = self.source.splitlines()[-1]
410 last_line = self.source.splitlines()[-1]
410 return bool(last_line and not last_line.isspace())
411 return bool(last_line and not last_line.isspace())
411
412
412 #------------------------------------------------------------------------
413 #------------------------------------------------------------------------
413 # Private interface
414 # Private interface
414 #------------------------------------------------------------------------
415 #------------------------------------------------------------------------
415
416
416 def _find_indent(self, line):
417 def _find_indent(self, line):
417 """Compute the new indentation level for a single line.
418 """Compute the new indentation level for a single line.
418
419
419 Parameters
420 Parameters
420 ----------
421 ----------
421 line : str
422 line : str
422 A single new line of non-whitespace, non-comment Python input.
423 A single new line of non-whitespace, non-comment Python input.
423
424
424 Returns
425 Returns
425 -------
426 -------
426 indent_spaces : int
427 indent_spaces : int
427 New value for the indent level (it may be equal to self.indent_spaces
428 New value for the indent level (it may be equal to self.indent_spaces
428 if indentation doesn't change.
429 if indentation doesn't change.
429
430
430 full_dedent : boolean
431 full_dedent : boolean
431 Whether the new line causes a full flush-left dedent.
432 Whether the new line causes a full flush-left dedent.
432 """
433 """
433 indent_spaces = self.indent_spaces
434 indent_spaces = self.indent_spaces
434 full_dedent = self._full_dedent
435 full_dedent = self._full_dedent
435
436
436 inisp = num_ini_spaces(line)
437 inisp = num_ini_spaces(line)
437 if inisp < indent_spaces:
438 if inisp < indent_spaces:
438 indent_spaces = inisp
439 indent_spaces = inisp
439 if indent_spaces <= 0:
440 if indent_spaces <= 0:
440 #print 'Full dedent in text',self.source # dbg
441 #print 'Full dedent in text',self.source # dbg
441 full_dedent = True
442 full_dedent = True
442
443
443 if line.rstrip()[-1] == ':':
444 if line.rstrip()[-1] == ':':
444 indent_spaces += 4
445 indent_spaces += 4
445 elif dedent_re.match(line):
446 elif dedent_re.match(line):
446 indent_spaces -= 4
447 indent_spaces -= 4
447 if indent_spaces <= 0:
448 if indent_spaces <= 0:
448 full_dedent = True
449 full_dedent = True
449
450
450 # Safety
451 # Safety
451 if indent_spaces < 0:
452 if indent_spaces < 0:
452 indent_spaces = 0
453 indent_spaces = 0
453 #print 'safety' # dbg
454 #print 'safety' # dbg
454
455
455 return indent_spaces, full_dedent
456 return indent_spaces, full_dedent
456
457
457 def _update_indent(self, lines):
458 def _update_indent(self, lines):
458 for line in remove_comments(lines).splitlines():
459 for line in remove_comments(lines).splitlines():
459 if line and not line.isspace():
460 if line and not line.isspace():
460 self.indent_spaces, self._full_dedent = self._find_indent(line)
461 self.indent_spaces, self._full_dedent = self._find_indent(line)
461
462
462 def _store(self, lines, buffer=None, store='source'):
463 def _store(self, lines, buffer=None, store='source'):
463 """Store one or more lines of input.
464 """Store one or more lines of input.
464
465
465 If input lines are not newline-terminated, a newline is automatically
466 If input lines are not newline-terminated, a newline is automatically
466 appended."""
467 appended."""
467
468
468 if buffer is None:
469 if buffer is None:
469 buffer = self._buffer
470 buffer = self._buffer
470
471
471 if lines.endswith('\n'):
472 if lines.endswith('\n'):
472 buffer.append(lines)
473 buffer.append(lines)
473 else:
474 else:
474 buffer.append(lines+'\n')
475 buffer.append(lines+'\n')
475 setattr(self, store, self._set_source(buffer))
476 setattr(self, store, self._set_source(buffer))
476
477
477 def _set_source(self, buffer):
478 def _set_source(self, buffer):
478 return u''.join(buffer)
479 return u''.join(buffer)
479
480
480
481
481 #-----------------------------------------------------------------------------
482 #-----------------------------------------------------------------------------
482 # Functions and classes for IPython-specific syntactic support
483 # Functions and classes for IPython-specific syntactic support
483 #-----------------------------------------------------------------------------
484 #-----------------------------------------------------------------------------
484
485
485 # RegExp for splitting line contents into pre-char//first word-method//rest.
486 # For clarity, each group in on one line.
487
488 line_split = re.compile("""
489 ^(\s*) # any leading space
490 ([,;/%]|!!?|\?\??) # escape character or characters
491 \s*(%?[\w\.\*]*) # function/method, possibly with leading %
492 # to correctly treat things like '?%magic'
493 (\s+.*$|$) # rest of line
494 """, re.VERBOSE)
495
496
497 def split_user_input(line):
498 """Split user input into early whitespace, esc-char, function part and rest.
499
500 This is currently handles lines with '=' in them in a very inconsistent
501 manner.
502
503 Examples
504 ========
505 >>> split_user_input('x=1')
506 ('', '', 'x=1', '')
507 >>> split_user_input('?')
508 ('', '?', '', '')
509 >>> split_user_input('??')
510 ('', '??', '', '')
511 >>> split_user_input(' ?')
512 (' ', '?', '', '')
513 >>> split_user_input(' ??')
514 (' ', '??', '', '')
515 >>> split_user_input('??x')
516 ('', '??', 'x', '')
517 >>> split_user_input('?x=1')
518 ('', '', '?x=1', '')
519 >>> split_user_input('!ls')
520 ('', '!', 'ls', '')
521 >>> split_user_input(' !ls')
522 (' ', '!', 'ls', '')
523 >>> split_user_input('!!ls')
524 ('', '!!', 'ls', '')
525 >>> split_user_input(' !!ls')
526 (' ', '!!', 'ls', '')
527 >>> split_user_input(',ls')
528 ('', ',', 'ls', '')
529 >>> split_user_input(';ls')
530 ('', ';', 'ls', '')
531 >>> split_user_input(' ;ls')
532 (' ', ';', 'ls', '')
533 >>> split_user_input('f.g(x)')
534 ('', '', 'f.g(x)', '')
535 >>> split_user_input('f.g (x)')
536 ('', '', 'f.g', '(x)')
537 >>> split_user_input('?%hist')
538 ('', '?', '%hist', '')
539 >>> split_user_input('?x*')
540 ('', '?', 'x*', '')
541 """
542 match = line_split.match(line)
543 if match:
544 lspace, esc, fpart, rest = match.groups()
545 else:
546 # print "match failed for line '%s'" % line
547 try:
548 fpart, rest = line.split(None, 1)
549 except ValueError:
550 # print "split failed for line '%s'" % line
551 fpart, rest = line,''
552 lspace = re.match('^(\s*)(.*)', line).groups()[0]
553 esc = ''
554
555 # fpart has to be a valid python identifier, so it better be only pure
556 # ascii, no unicode:
557 try:
558 fpart = fpart.encode('ascii')
559 except UnicodeEncodeError:
560 lspace = unicode(lspace)
561 rest = fpart + u' ' + rest
562 fpart = u''
563
564 #print 'line:<%s>' % line # dbg
565 #print 'esc <%s> fpart <%s> rest <%s>' % (esc,fpart.strip(),rest) # dbg
566 return lspace, esc, fpart.strip(), rest.lstrip()
567
568
569 # The escaped translators ALL receive a line where their own escape has been
486 # The escaped translators ALL receive a line where their own escape has been
570 # stripped. Only '?' is valid at the end of the line, all others can only be
487 # stripped. Only '?' is valid at the end of the line, all others can only be
571 # placed at the start.
488 # placed at the start.
572
489
573 class LineInfo(object):
574 """A single line of input and associated info.
575
576 This is a utility class that mostly wraps the output of
577 :func:`split_user_input` into a convenient object to be passed around
578 during input transformations.
579
580 Includes the following as properties:
581
582 line
583 The original, raw line
584
585 lspace
586 Any early whitespace before actual text starts.
587
588 esc
589 The initial esc character (or characters, for double-char escapes like
590 '??' or '!!').
591
592 fpart
593 The 'function part', which is basically the maximal initial sequence
594 of valid python identifiers and the '.' character. This is what is
595 checked for alias and magic transformations, used for auto-calling,
596 etc.
597
598 rest
599 Everything else on the line.
600 """
601 def __init__(self, line):
602 self.line = line
603 self.lspace, self.esc, self.fpart, self.rest = \
604 split_user_input(line)
605
606 def __str__(self):
607 return "LineInfo [%s|%s|%s|%s]" % (self.lspace, self.esc,
608 self.fpart, self.rest)
609
610
611 # Transformations of the special syntaxes that don't rely on an explicit escape
490 # Transformations of the special syntaxes that don't rely on an explicit escape
612 # character but instead on patterns on the input line
491 # character but instead on patterns on the input line
613
492
614 # The core transformations are implemented as standalone functions that can be
493 # The core transformations are implemented as standalone functions that can be
615 # tested and validated in isolation. Each of these uses a regexp, we
494 # tested and validated in isolation. Each of these uses a regexp, we
616 # pre-compile these and keep them close to each function definition for clarity
495 # pre-compile these and keep them close to each function definition for clarity
617
496
618 _assign_system_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
497 _assign_system_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
619 r'\s*=\s*!\s*(?P<cmd>.*)')
498 r'\s*=\s*!\s*(?P<cmd>.*)')
620
499
621 def transform_assign_system(line):
500 def transform_assign_system(line):
622 """Handle the `files = !ls` syntax."""
501 """Handle the `files = !ls` syntax."""
623 m = _assign_system_re.match(line)
502 m = _assign_system_re.match(line)
624 if m is not None:
503 if m is not None:
625 cmd = m.group('cmd')
504 cmd = m.group('cmd')
626 lhs = m.group('lhs')
505 lhs = m.group('lhs')
627 expr = make_quoted_expr(cmd)
506 expr = make_quoted_expr(cmd)
628 new_line = '%s = get_ipython().getoutput(%s)' % (lhs, expr)
507 new_line = '%s = get_ipython().getoutput(%s)' % (lhs, expr)
629 return new_line
508 return new_line
630 return line
509 return line
631
510
632
511
633 _assign_magic_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
512 _assign_magic_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
634 r'\s*=\s*%\s*(?P<cmd>.*)')
513 r'\s*=\s*%\s*(?P<cmd>.*)')
635
514
636 def transform_assign_magic(line):
515 def transform_assign_magic(line):
637 """Handle the `a = %who` syntax."""
516 """Handle the `a = %who` syntax."""
638 m = _assign_magic_re.match(line)
517 m = _assign_magic_re.match(line)
639 if m is not None:
518 if m is not None:
640 cmd = m.group('cmd')
519 cmd = m.group('cmd')
641 lhs = m.group('lhs')
520 lhs = m.group('lhs')
642 expr = make_quoted_expr(cmd)
521 expr = make_quoted_expr(cmd)
643 new_line = '%s = get_ipython().magic(%s)' % (lhs, expr)
522 new_line = '%s = get_ipython().magic(%s)' % (lhs, expr)
644 return new_line
523 return new_line
645 return line
524 return line
646
525
647
526
648 _classic_prompt_re = re.compile(r'^([ \t]*>>> |^[ \t]*\.\.\. )')
527 _classic_prompt_re = re.compile(r'^([ \t]*>>> |^[ \t]*\.\.\. )')
649
528
650 def transform_classic_prompt(line):
529 def transform_classic_prompt(line):
651 """Handle inputs that start with '>>> ' syntax."""
530 """Handle inputs that start with '>>> ' syntax."""
652
531
653 if not line or line.isspace():
532 if not line or line.isspace():
654 return line
533 return line
655 m = _classic_prompt_re.match(line)
534 m = _classic_prompt_re.match(line)
656 if m:
535 if m:
657 return line[len(m.group(0)):]
536 return line[len(m.group(0)):]
658 else:
537 else:
659 return line
538 return line
660
539
661
540
662 _ipy_prompt_re = re.compile(r'^([ \t]*In \[\d+\]: |^[ \t]*\ \ \ \.\.\.+: )')
541 _ipy_prompt_re = re.compile(r'^([ \t]*In \[\d+\]: |^[ \t]*\ \ \ \.\.\.+: )')
663
542
664 def transform_ipy_prompt(line):
543 def transform_ipy_prompt(line):
665 """Handle inputs that start classic IPython prompt syntax."""
544 """Handle inputs that start classic IPython prompt syntax."""
666
545
667 if not line or line.isspace():
546 if not line or line.isspace():
668 return line
547 return line
669 #print 'LINE: %r' % line # dbg
548 #print 'LINE: %r' % line # dbg
670 m = _ipy_prompt_re.match(line)
549 m = _ipy_prompt_re.match(line)
671 if m:
550 if m:
672 #print 'MATCH! %r -> %r' % (line, line[len(m.group(0)):]) # dbg
551 #print 'MATCH! %r -> %r' % (line, line[len(m.group(0)):]) # dbg
673 return line[len(m.group(0)):]
552 return line[len(m.group(0)):]
674 else:
553 else:
675 return line
554 return line
676
555
677
556
678 def _make_help_call(target, esc, lspace, next_input=None):
557 def _make_help_call(target, esc, lspace, next_input=None):
679 """Prepares a pinfo(2)/psearch call from a target name and the escape
558 """Prepares a pinfo(2)/psearch call from a target name and the escape
680 (i.e. ? or ??)"""
559 (i.e. ? or ??)"""
681 method = 'pinfo2' if esc == '??' \
560 method = 'pinfo2' if esc == '??' \
682 else 'psearch' if '*' in target \
561 else 'psearch' if '*' in target \
683 else 'pinfo'
562 else 'pinfo'
684
563
685 if next_input:
564 if next_input:
686 tpl = '%sget_ipython().magic(u"%s %s", next_input=%s)'
565 tpl = '%sget_ipython().magic(u"%s %s", next_input=%s)'
687 return tpl % (lspace, method, target, make_quoted_expr(next_input))
566 return tpl % (lspace, method, target, make_quoted_expr(next_input))
688 else:
567 else:
689 return '%sget_ipython().magic(u"%s %s")' % (lspace, method, target)
568 return '%sget_ipython().magic(u"%s %s")' % (lspace, method, target)
690
569
691 _initial_space_re = re.compile(r'\s*')
570 _initial_space_re = re.compile(r'\s*')
692 _help_end_re = re.compile(r"""(%?
571 _help_end_re = re.compile(r"""(%?
693 [a-zA-Z_*][a-zA-Z0-9_*]* # Variable name
572 [a-zA-Z_*][\w*]* # Variable name
694 (\.[a-zA-Z_*][a-zA-Z0-9_*]*)* # .etc.etc
573 (\.[a-zA-Z_*][\w*]*)* # .etc.etc
695 )
574 )
696 (\?\??)$ # ? or ??""",
575 (\?\??)$ # ? or ??""",
697 re.VERBOSE)
576 re.VERBOSE)
698 def transform_help_end(line):
577 def transform_help_end(line):
699 """Translate lines with ?/?? at the end"""
578 """Translate lines with ?/?? at the end"""
700 m = _help_end_re.search(line)
579 m = _help_end_re.search(line)
701 if m is None or has_comment(line):
580 if m is None or has_comment(line):
702 return line
581 return line
703 target = m.group(1)
582 target = m.group(1)
704 esc = m.group(3)
583 esc = m.group(3)
705 lspace = _initial_space_re.match(line).group(0)
584 lspace = _initial_space_re.match(line).group(0)
706 newline = _make_help_call(target, esc, lspace)
707
585
708 # If we're mid-command, put it back on the next prompt for the user.
586 # If we're mid-command, put it back on the next prompt for the user.
709 next_input = line.rstrip('?') if line.strip() != m.group(0) else None
587 next_input = line.rstrip('?') if line.strip() != m.group(0) else None
710
588
711 return _make_help_call(target, esc, lspace, next_input)
589 return _make_help_call(target, esc, lspace, next_input)
712
590
713
591
714 class EscapedTransformer(object):
592 class EscapedTransformer(object):
715 """Class to transform lines that are explicitly escaped out."""
593 """Class to transform lines that are explicitly escaped out."""
716
594
717 def __init__(self):
595 def __init__(self):
718 tr = { ESC_SHELL : self._tr_system,
596 tr = { ESC_SHELL : self._tr_system,
719 ESC_SH_CAP : self._tr_system2,
597 ESC_SH_CAP : self._tr_system2,
720 ESC_HELP : self._tr_help,
598 ESC_HELP : self._tr_help,
721 ESC_HELP2 : self._tr_help,
599 ESC_HELP2 : self._tr_help,
722 ESC_MAGIC : self._tr_magic,
600 ESC_MAGIC : self._tr_magic,
723 ESC_QUOTE : self._tr_quote,
601 ESC_QUOTE : self._tr_quote,
724 ESC_QUOTE2 : self._tr_quote2,
602 ESC_QUOTE2 : self._tr_quote2,
725 ESC_PAREN : self._tr_paren }
603 ESC_PAREN : self._tr_paren }
726 self.tr = tr
604 self.tr = tr
727
605
728 # Support for syntax transformations that use explicit escapes typed by the
606 # Support for syntax transformations that use explicit escapes typed by the
729 # user at the beginning of a line
607 # user at the beginning of a line
730 @staticmethod
608 @staticmethod
731 def _tr_system(line_info):
609 def _tr_system(line_info):
732 "Translate lines escaped with: !"
610 "Translate lines escaped with: !"
733 cmd = line_info.line.lstrip().lstrip(ESC_SHELL)
611 cmd = line_info.line.lstrip().lstrip(ESC_SHELL)
734 return '%sget_ipython().system(%s)' % (line_info.lspace,
612 return '%sget_ipython().system(%s)' % (line_info.pre,
735 make_quoted_expr(cmd))
613 make_quoted_expr(cmd))
736
614
737 @staticmethod
615 @staticmethod
738 def _tr_system2(line_info):
616 def _tr_system2(line_info):
739 "Translate lines escaped with: !!"
617 "Translate lines escaped with: !!"
740 cmd = line_info.line.lstrip()[2:]
618 cmd = line_info.line.lstrip()[2:]
741 return '%sget_ipython().getoutput(%s)' % (line_info.lspace,
619 return '%sget_ipython().getoutput(%s)' % (line_info.pre,
742 make_quoted_expr(cmd))
620 make_quoted_expr(cmd))
743
621
744 @staticmethod
622 @staticmethod
745 def _tr_help(line_info):
623 def _tr_help(line_info):
746 "Translate lines escaped with: ?/??"
624 "Translate lines escaped with: ?/??"
747 # A naked help line should just fire the intro help screen
625 # A naked help line should just fire the intro help screen
748 if not line_info.line[1:]:
626 if not line_info.line[1:]:
749 return 'get_ipython().show_usage()'
627 return 'get_ipython().show_usage()'
750
628
751 return _make_help_call(line_info.fpart, line_info.esc, line_info.lspace)
629 return _make_help_call(line_info.ifun, line_info.esc, line_info.pre)
752
630
753 @staticmethod
631 @staticmethod
754 def _tr_magic(line_info):
632 def _tr_magic(line_info):
755 "Translate lines escaped with: %"
633 "Translate lines escaped with: %"
756 tpl = '%sget_ipython().magic(%s)'
634 tpl = '%sget_ipython().magic(%s)'
757 cmd = make_quoted_expr(' '.join([line_info.fpart,
635 cmd = make_quoted_expr(' '.join([line_info.ifun,
758 line_info.rest]).strip())
636 line_info.the_rest]).strip())
759 return tpl % (line_info.lspace, cmd)
637 return tpl % (line_info.pre, cmd)
760
638
761 @staticmethod
639 @staticmethod
762 def _tr_quote(line_info):
640 def _tr_quote(line_info):
763 "Translate lines escaped with: ,"
641 "Translate lines escaped with: ,"
764 return '%s%s("%s")' % (line_info.lspace, line_info.fpart,
642 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
765 '", "'.join(line_info.rest.split()) )
643 '", "'.join(line_info.the_rest.split()) )
766
644
767 @staticmethod
645 @staticmethod
768 def _tr_quote2(line_info):
646 def _tr_quote2(line_info):
769 "Translate lines escaped with: ;"
647 "Translate lines escaped with: ;"
770 return '%s%s("%s")' % (line_info.lspace, line_info.fpart,
648 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
771 line_info.rest)
649 line_info.the_rest)
772
650
773 @staticmethod
651 @staticmethod
774 def _tr_paren(line_info):
652 def _tr_paren(line_info):
775 "Translate lines escaped with: /"
653 "Translate lines escaped with: /"
776 return '%s%s(%s)' % (line_info.lspace, line_info.fpart,
654 return '%s%s(%s)' % (line_info.pre, line_info.ifun,
777 ", ".join(line_info.rest.split()))
655 ", ".join(line_info.the_rest.split()))
778
656
779 def __call__(self, line):
657 def __call__(self, line):
780 """Class to transform lines that are explicitly escaped out.
658 """Class to transform lines that are explicitly escaped out.
781
659
782 This calls the above _tr_* static methods for the actual line
660 This calls the above _tr_* static methods for the actual line
783 translations."""
661 translations."""
784
662
785 # Empty lines just get returned unmodified
663 # Empty lines just get returned unmodified
786 if not line or line.isspace():
664 if not line or line.isspace():
787 return line
665 return line
788
666
789 # Get line endpoints, where the escapes can be
667 # Get line endpoints, where the escapes can be
790 line_info = LineInfo(line)
668 line_info = LineInfo(line)
791
669
792 if not line_info.esc in self.tr:
670 if not line_info.esc in self.tr:
793 # If we don't recognize the escape, don't modify the line
671 # If we don't recognize the escape, don't modify the line
794 return line
672 return line
795
673
796 return self.tr[line_info.esc](line_info)
674 return self.tr[line_info.esc](line_info)
797
675
798
676
799 # A function-looking object to be used by the rest of the code. The purpose of
677 # A function-looking object to be used by the rest of the code. The purpose of
800 # the class in this case is to organize related functionality, more than to
678 # the class in this case is to organize related functionality, more than to
801 # manage state.
679 # manage state.
802 transform_escaped = EscapedTransformer()
680 transform_escaped = EscapedTransformer()
803
681
804
682
805 class IPythonInputSplitter(InputSplitter):
683 class IPythonInputSplitter(InputSplitter):
806 """An input splitter that recognizes all of IPython's special syntax."""
684 """An input splitter that recognizes all of IPython's special syntax."""
807
685
808 # String with raw, untransformed input.
686 # String with raw, untransformed input.
809 source_raw = ''
687 source_raw = ''
810
688
811 # Private attributes
689 # Private attributes
812
690
813 # List with lines of raw input accumulated so far.
691 # List with lines of raw input accumulated so far.
814 _buffer_raw = None
692 _buffer_raw = None
815
693
816 def __init__(self, input_mode=None):
694 def __init__(self, input_mode=None):
817 InputSplitter.__init__(self, input_mode)
695 InputSplitter.__init__(self, input_mode)
818 self._buffer_raw = []
696 self._buffer_raw = []
819
697
820 def reset(self):
698 def reset(self):
821 """Reset the input buffer and associated state."""
699 """Reset the input buffer and associated state."""
822 InputSplitter.reset(self)
700 InputSplitter.reset(self)
823 self._buffer_raw[:] = []
701 self._buffer_raw[:] = []
824 self.source_raw = ''
702 self.source_raw = ''
825
703
826 def source_raw_reset(self):
704 def source_raw_reset(self):
827 """Return input and raw source and perform a full reset.
705 """Return input and raw source and perform a full reset.
828 """
706 """
829 out = self.source
707 out = self.source
830 out_r = self.source_raw
708 out_r = self.source_raw
831 self.reset()
709 self.reset()
832 return out, out_r
710 return out, out_r
833
711
834 def push(self, lines):
712 def push(self, lines):
835 """Push one or more lines of IPython input.
713 """Push one or more lines of IPython input.
836 """
714 """
837 if not lines:
715 if not lines:
838 return super(IPythonInputSplitter, self).push(lines)
716 return super(IPythonInputSplitter, self).push(lines)
839
717
840 # We must ensure all input is pure unicode
718 # We must ensure all input is pure unicode
841 lines = cast_unicode(lines, self.encoding)
719 lines = cast_unicode(lines, self.encoding)
842
720
843 lines_list = lines.splitlines()
721 lines_list = lines.splitlines()
844
722
845 transforms = [transform_ipy_prompt, transform_classic_prompt,
723 transforms = [transform_ipy_prompt, transform_classic_prompt,
846 transform_escaped, transform_help_end,
724 transform_help_end, transform_escaped,
847 transform_assign_system, transform_assign_magic]
725 transform_assign_system, transform_assign_magic]
848
726
849 # Transform logic
727 # Transform logic
850 #
728 #
851 # We only apply the line transformers to the input if we have either no
729 # We only apply the line transformers to the input if we have either no
852 # input yet, or complete input, or if the last line of the buffer ends
730 # input yet, or complete input, or if the last line of the buffer ends
853 # with ':' (opening an indented block). This prevents the accidental
731 # with ':' (opening an indented block). This prevents the accidental
854 # transformation of escapes inside multiline expressions like
732 # transformation of escapes inside multiline expressions like
855 # triple-quoted strings or parenthesized expressions.
733 # triple-quoted strings or parenthesized expressions.
856 #
734 #
857 # The last heuristic, while ugly, ensures that the first line of an
735 # The last heuristic, while ugly, ensures that the first line of an
858 # indented block is correctly transformed.
736 # indented block is correctly transformed.
859 #
737 #
860 # FIXME: try to find a cleaner approach for this last bit.
738 # FIXME: try to find a cleaner approach for this last bit.
861
739
862 # If we were in 'block' mode, since we're going to pump the parent
740 # If we were in 'block' mode, since we're going to pump the parent
863 # class by hand line by line, we need to temporarily switch out to
741 # class by hand line by line, we need to temporarily switch out to
864 # 'line' mode, do a single manual reset and then feed the lines one
742 # 'line' mode, do a single manual reset and then feed the lines one
865 # by one. Note that this only matters if the input has more than one
743 # by one. Note that this only matters if the input has more than one
866 # line.
744 # line.
867 changed_input_mode = False
745 changed_input_mode = False
868
746
869 if self.input_mode == 'cell':
747 if self.input_mode == 'cell':
870 self.reset()
748 self.reset()
871 changed_input_mode = True
749 changed_input_mode = True
872 saved_input_mode = 'cell'
750 saved_input_mode = 'cell'
873 self.input_mode = 'line'
751 self.input_mode = 'line'
874
752
875 # Store raw source before applying any transformations to it. Note
753 # Store raw source before applying any transformations to it. Note
876 # that this must be done *after* the reset() call that would otherwise
754 # that this must be done *after* the reset() call that would otherwise
877 # flush the buffer.
755 # flush the buffer.
878 self._store(lines, self._buffer_raw, 'source_raw')
756 self._store(lines, self._buffer_raw, 'source_raw')
879
757
880 try:
758 try:
881 push = super(IPythonInputSplitter, self).push
759 push = super(IPythonInputSplitter, self).push
882 for line in lines_list:
760 for line in lines_list:
883 if self._is_complete or not self._buffer or \
761 if self._is_complete or not self._buffer or \
884 (self._buffer and self._buffer[-1].rstrip().endswith(':')):
762 (self._buffer and self._buffer[-1].rstrip().endswith(':')):
885 for f in transforms:
763 for f in transforms:
886 line = f(line)
764 line = f(line)
887
765
888 out = push(line)
766 out = push(line)
889 finally:
767 finally:
890 if changed_input_mode:
768 if changed_input_mode:
891 self.input_mode = saved_input_mode
769 self.input_mode = saved_input_mode
892 return out
770 return out
@@ -1,1015 +1,943 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Prefiltering components.
3 Prefiltering components.
4
4
5 Prefilters transform user input before it is exec'd by Python. These
5 Prefilters transform user input before it is exec'd by Python. These
6 transforms are used to implement additional syntax such as !ls and %magic.
6 transforms are used to implement additional syntax such as !ls and %magic.
7
7
8 Authors:
8 Authors:
9
9
10 * Brian Granger
10 * Brian Granger
11 * Fernando Perez
11 * Fernando Perez
12 * Dan Milstein
12 * Dan Milstein
13 * Ville Vainio
13 * Ville Vainio
14 """
14 """
15
15
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 # Copyright (C) 2008-2009 The IPython Development Team
17 # Copyright (C) 2008-2009 The IPython Development Team
18 #
18 #
19 # Distributed under the terms of the BSD License. The full license is in
19 # Distributed under the terms of the BSD License. The full license is in
20 # the file COPYING, distributed as part of this software.
20 # the file COPYING, distributed as part of this software.
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22
22
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24 # Imports
24 # Imports
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26
26
27 import __builtin__
27 import __builtin__
28 import codeop
28 import codeop
29 import re
29 import re
30
30
31 from IPython.core.alias import AliasManager
31 from IPython.core.alias import AliasManager
32 from IPython.core.autocall import IPyAutocall
32 from IPython.core.autocall import IPyAutocall
33 from IPython.config.configurable import Configurable
33 from IPython.config.configurable import Configurable
34 from IPython.core.macro import Macro
34 from IPython.core.macro import Macro
35 from IPython.core.splitinput import split_user_input
35 from IPython.core.splitinput import split_user_input, LineInfo
36 from IPython.core import page
36 from IPython.core import page
37
37
38 from IPython.utils.traitlets import List, Int, Any, Unicode, CBool, Bool, Instance
38 from IPython.utils.traitlets import List, Int, Any, Unicode, CBool, Bool, Instance
39 from IPython.utils.text import make_quoted_expr
39 from IPython.utils.text import make_quoted_expr
40 from IPython.utils.autoattr import auto_attr
40 from IPython.utils.autoattr import auto_attr
41
41
42 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
43 # Global utilities, errors and constants
43 # Global utilities, errors and constants
44 #-----------------------------------------------------------------------------
44 #-----------------------------------------------------------------------------
45
45
46 # Warning, these cannot be changed unless various regular expressions
46 # Warning, these cannot be changed unless various regular expressions
47 # are updated in a number of places. Not great, but at least we told you.
47 # are updated in a number of places. Not great, but at least we told you.
48 ESC_SHELL = '!'
48 ESC_SHELL = '!'
49 ESC_SH_CAP = '!!'
49 ESC_SH_CAP = '!!'
50 ESC_HELP = '?'
50 ESC_HELP = '?'
51 ESC_MAGIC = '%'
51 ESC_MAGIC = '%'
52 ESC_QUOTE = ','
52 ESC_QUOTE = ','
53 ESC_QUOTE2 = ';'
53 ESC_QUOTE2 = ';'
54 ESC_PAREN = '/'
54 ESC_PAREN = '/'
55
55
56
56
57 class PrefilterError(Exception):
57 class PrefilterError(Exception):
58 pass
58 pass
59
59
60
60
61 # RegExp to identify potential function names
61 # RegExp to identify potential function names
62 re_fun_name = re.compile(r'[a-zA-Z_]([a-zA-Z0-9_.]*) *$')
62 re_fun_name = re.compile(r'[a-zA-Z_]([a-zA-Z0-9_.]*) *$')
63
63
64 # RegExp to exclude strings with this start from autocalling. In
64 # RegExp to exclude strings with this start from autocalling. In
65 # particular, all binary operators should be excluded, so that if foo is
65 # particular, all binary operators should be excluded, so that if foo is
66 # callable, foo OP bar doesn't become foo(OP bar), which is invalid. The
66 # callable, foo OP bar doesn't become foo(OP bar), which is invalid. The
67 # characters '!=()' don't need to be checked for, as the checkPythonChars
67 # characters '!=()' don't need to be checked for, as the checkPythonChars
68 # routine explicitely does so, to catch direct calls and rebindings of
68 # routine explicitely does so, to catch direct calls and rebindings of
69 # existing names.
69 # existing names.
70
70
71 # Warning: the '-' HAS TO BE AT THE END of the first group, otherwise
71 # Warning: the '-' HAS TO BE AT THE END of the first group, otherwise
72 # it affects the rest of the group in square brackets.
72 # it affects the rest of the group in square brackets.
73 re_exclude_auto = re.compile(r'^[,&^\|\*/\+-]'
73 re_exclude_auto = re.compile(r'^[,&^\|\*/\+-]'
74 r'|^is |^not |^in |^and |^or ')
74 r'|^is |^not |^in |^and |^or ')
75
75
76 # try to catch also methods for stuff in lists/tuples/dicts: off
76 # try to catch also methods for stuff in lists/tuples/dicts: off
77 # (experimental). For this to work, the line_split regexp would need
77 # (experimental). For this to work, the line_split regexp would need
78 # to be modified so it wouldn't break things at '['. That line is
78 # to be modified so it wouldn't break things at '['. That line is
79 # nasty enough that I shouldn't change it until I can test it _well_.
79 # nasty enough that I shouldn't change it until I can test it _well_.
80 #self.re_fun_name = re.compile (r'[a-zA-Z_]([a-zA-Z0-9_.\[\]]*) ?$')
80 #self.re_fun_name = re.compile (r'[a-zA-Z_]([a-zA-Z0-9_.\[\]]*) ?$')
81
81
82
82
83 # Handler Check Utilities
83 # Handler Check Utilities
84 def is_shadowed(identifier, ip):
84 def is_shadowed(identifier, ip):
85 """Is the given identifier defined in one of the namespaces which shadow
85 """Is the given identifier defined in one of the namespaces which shadow
86 the alias and magic namespaces? Note that an identifier is different
86 the alias and magic namespaces? Note that an identifier is different
87 than ifun, because it can not contain a '.' character."""
87 than ifun, because it can not contain a '.' character."""
88 # This is much safer than calling ofind, which can change state
88 # This is much safer than calling ofind, which can change state
89 return (identifier in ip.user_ns \
89 return (identifier in ip.user_ns \
90 or identifier in ip.internal_ns \
90 or identifier in ip.internal_ns \
91 or identifier in ip.ns_table['builtin'])
91 or identifier in ip.ns_table['builtin'])
92
92
93
93
94 #-----------------------------------------------------------------------------
94 #-----------------------------------------------------------------------------
95 # The LineInfo class used throughout
96 #-----------------------------------------------------------------------------
97
98
99 class LineInfo(object):
100 """A single line of input and associated info.
101
102 Includes the following as properties:
103
104 line
105 The original, raw line
106
107 continue_prompt
108 Is this line a continuation in a sequence of multiline input?
109
110 pre
111 The initial esc character or whitespace.
112
113 pre_char
114 The escape character(s) in pre or the empty string if there isn't one.
115 Note that '!!' is a possible value for pre_char. Otherwise it will
116 always be a single character.
117
118 pre_whitespace
119 The leading whitespace from pre if it exists. If there is a pre_char,
120 this is just ''.
121
122 ifun
123 The 'function part', which is basically the maximal initial sequence
124 of valid python identifiers and the '.' character. This is what is
125 checked for alias and magic transformations, used for auto-calling,
126 etc.
127
128 the_rest
129 Everything else on the line.
130 """
131 def __init__(self, line, continue_prompt):
132 self.line = line
133 self.continue_prompt = continue_prompt
134 self.pre, self.esc, self.ifun, self.the_rest = split_user_input(line)
135
136 self.pre_char = self.pre.strip()
137 if self.pre_char:
138 self.pre_whitespace = '' # No whitespace allowd before esc chars
139 else:
140 self.pre_whitespace = self.pre
141
142 self._oinfo = None
143
144 def ofind(self, ip):
145 """Do a full, attribute-walking lookup of the ifun in the various
146 namespaces for the given IPython InteractiveShell instance.
147
148 Return a dict with keys: found,obj,ospace,ismagic
149
150 Note: can cause state changes because of calling getattr, but should
151 only be run if autocall is on and if the line hasn't matched any
152 other, less dangerous handlers.
153
154 Does cache the results of the call, so can be called multiple times
155 without worrying about *further* damaging state.
156 """
157 if not self._oinfo:
158 # ip.shell._ofind is actually on the Magic class!
159 self._oinfo = ip.shell._ofind(self.ifun)
160 return self._oinfo
161
162 def __str__(self):
163 return "Lineinfo [%s|%s|%s]" %(self.pre, self.ifun, self.the_rest)
164
165
166 #-----------------------------------------------------------------------------
167 # Main Prefilter manager
95 # Main Prefilter manager
168 #-----------------------------------------------------------------------------
96 #-----------------------------------------------------------------------------
169
97
170
98
171 class PrefilterManager(Configurable):
99 class PrefilterManager(Configurable):
172 """Main prefilter component.
100 """Main prefilter component.
173
101
174 The IPython prefilter is run on all user input before it is run. The
102 The IPython prefilter is run on all user input before it is run. The
175 prefilter consumes lines of input and produces transformed lines of
103 prefilter consumes lines of input and produces transformed lines of
176 input.
104 input.
177
105
178 The iplementation consists of two phases:
106 The iplementation consists of two phases:
179
107
180 1. Transformers
108 1. Transformers
181 2. Checkers and handlers
109 2. Checkers and handlers
182
110
183 Over time, we plan on deprecating the checkers and handlers and doing
111 Over time, we plan on deprecating the checkers and handlers and doing
184 everything in the transformers.
112 everything in the transformers.
185
113
186 The transformers are instances of :class:`PrefilterTransformer` and have
114 The transformers are instances of :class:`PrefilterTransformer` and have
187 a single method :meth:`transform` that takes a line and returns a
115 a single method :meth:`transform` that takes a line and returns a
188 transformed line. The transformation can be accomplished using any
116 transformed line. The transformation can be accomplished using any
189 tool, but our current ones use regular expressions for speed. We also
117 tool, but our current ones use regular expressions for speed. We also
190 ship :mod:`pyparsing` in :mod:`IPython.external` for use in transformers.
118 ship :mod:`pyparsing` in :mod:`IPython.external` for use in transformers.
191
119
192 After all the transformers have been run, the line is fed to the checkers,
120 After all the transformers have been run, the line is fed to the checkers,
193 which are instances of :class:`PrefilterChecker`. The line is passed to
121 which are instances of :class:`PrefilterChecker`. The line is passed to
194 the :meth:`check` method, which either returns `None` or a
122 the :meth:`check` method, which either returns `None` or a
195 :class:`PrefilterHandler` instance. If `None` is returned, the other
123 :class:`PrefilterHandler` instance. If `None` is returned, the other
196 checkers are tried. If an :class:`PrefilterHandler` instance is returned,
124 checkers are tried. If an :class:`PrefilterHandler` instance is returned,
197 the line is passed to the :meth:`handle` method of the returned
125 the line is passed to the :meth:`handle` method of the returned
198 handler and no further checkers are tried.
126 handler and no further checkers are tried.
199
127
200 Both transformers and checkers have a `priority` attribute, that determines
128 Both transformers and checkers have a `priority` attribute, that determines
201 the order in which they are called. Smaller priorities are tried first.
129 the order in which they are called. Smaller priorities are tried first.
202
130
203 Both transformers and checkers also have `enabled` attribute, which is
131 Both transformers and checkers also have `enabled` attribute, which is
204 a boolean that determines if the instance is used.
132 a boolean that determines if the instance is used.
205
133
206 Users or developers can change the priority or enabled attribute of
134 Users or developers can change the priority or enabled attribute of
207 transformers or checkers, but they must call the :meth:`sort_checkers`
135 transformers or checkers, but they must call the :meth:`sort_checkers`
208 or :meth:`sort_transformers` method after changing the priority.
136 or :meth:`sort_transformers` method after changing the priority.
209 """
137 """
210
138
211 multi_line_specials = CBool(True, config=True)
139 multi_line_specials = CBool(True, config=True)
212 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
140 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
213
141
214 def __init__(self, shell=None, config=None):
142 def __init__(self, shell=None, config=None):
215 super(PrefilterManager, self).__init__(shell=shell, config=config)
143 super(PrefilterManager, self).__init__(shell=shell, config=config)
216 self.shell = shell
144 self.shell = shell
217 self.init_transformers()
145 self.init_transformers()
218 self.init_handlers()
146 self.init_handlers()
219 self.init_checkers()
147 self.init_checkers()
220
148
221 #-------------------------------------------------------------------------
149 #-------------------------------------------------------------------------
222 # API for managing transformers
150 # API for managing transformers
223 #-------------------------------------------------------------------------
151 #-------------------------------------------------------------------------
224
152
225 def init_transformers(self):
153 def init_transformers(self):
226 """Create the default transformers."""
154 """Create the default transformers."""
227 self._transformers = []
155 self._transformers = []
228 for transformer_cls in _default_transformers:
156 for transformer_cls in _default_transformers:
229 transformer_cls(
157 transformer_cls(
230 shell=self.shell, prefilter_manager=self, config=self.config
158 shell=self.shell, prefilter_manager=self, config=self.config
231 )
159 )
232
160
233 def sort_transformers(self):
161 def sort_transformers(self):
234 """Sort the transformers by priority.
162 """Sort the transformers by priority.
235
163
236 This must be called after the priority of a transformer is changed.
164 This must be called after the priority of a transformer is changed.
237 The :meth:`register_transformer` method calls this automatically.
165 The :meth:`register_transformer` method calls this automatically.
238 """
166 """
239 self._transformers.sort(key=lambda x: x.priority)
167 self._transformers.sort(key=lambda x: x.priority)
240
168
241 @property
169 @property
242 def transformers(self):
170 def transformers(self):
243 """Return a list of checkers, sorted by priority."""
171 """Return a list of checkers, sorted by priority."""
244 return self._transformers
172 return self._transformers
245
173
246 def register_transformer(self, transformer):
174 def register_transformer(self, transformer):
247 """Register a transformer instance."""
175 """Register a transformer instance."""
248 if transformer not in self._transformers:
176 if transformer not in self._transformers:
249 self._transformers.append(transformer)
177 self._transformers.append(transformer)
250 self.sort_transformers()
178 self.sort_transformers()
251
179
252 def unregister_transformer(self, transformer):
180 def unregister_transformer(self, transformer):
253 """Unregister a transformer instance."""
181 """Unregister a transformer instance."""
254 if transformer in self._transformers:
182 if transformer in self._transformers:
255 self._transformers.remove(transformer)
183 self._transformers.remove(transformer)
256
184
257 #-------------------------------------------------------------------------
185 #-------------------------------------------------------------------------
258 # API for managing checkers
186 # API for managing checkers
259 #-------------------------------------------------------------------------
187 #-------------------------------------------------------------------------
260
188
261 def init_checkers(self):
189 def init_checkers(self):
262 """Create the default checkers."""
190 """Create the default checkers."""
263 self._checkers = []
191 self._checkers = []
264 for checker in _default_checkers:
192 for checker in _default_checkers:
265 checker(
193 checker(
266 shell=self.shell, prefilter_manager=self, config=self.config
194 shell=self.shell, prefilter_manager=self, config=self.config
267 )
195 )
268
196
269 def sort_checkers(self):
197 def sort_checkers(self):
270 """Sort the checkers by priority.
198 """Sort the checkers by priority.
271
199
272 This must be called after the priority of a checker is changed.
200 This must be called after the priority of a checker is changed.
273 The :meth:`register_checker` method calls this automatically.
201 The :meth:`register_checker` method calls this automatically.
274 """
202 """
275 self._checkers.sort(key=lambda x: x.priority)
203 self._checkers.sort(key=lambda x: x.priority)
276
204
277 @property
205 @property
278 def checkers(self):
206 def checkers(self):
279 """Return a list of checkers, sorted by priority."""
207 """Return a list of checkers, sorted by priority."""
280 return self._checkers
208 return self._checkers
281
209
282 def register_checker(self, checker):
210 def register_checker(self, checker):
283 """Register a checker instance."""
211 """Register a checker instance."""
284 if checker not in self._checkers:
212 if checker not in self._checkers:
285 self._checkers.append(checker)
213 self._checkers.append(checker)
286 self.sort_checkers()
214 self.sort_checkers()
287
215
288 def unregister_checker(self, checker):
216 def unregister_checker(self, checker):
289 """Unregister a checker instance."""
217 """Unregister a checker instance."""
290 if checker in self._checkers:
218 if checker in self._checkers:
291 self._checkers.remove(checker)
219 self._checkers.remove(checker)
292
220
293 #-------------------------------------------------------------------------
221 #-------------------------------------------------------------------------
294 # API for managing checkers
222 # API for managing checkers
295 #-------------------------------------------------------------------------
223 #-------------------------------------------------------------------------
296
224
297 def init_handlers(self):
225 def init_handlers(self):
298 """Create the default handlers."""
226 """Create the default handlers."""
299 self._handlers = {}
227 self._handlers = {}
300 self._esc_handlers = {}
228 self._esc_handlers = {}
301 for handler in _default_handlers:
229 for handler in _default_handlers:
302 handler(
230 handler(
303 shell=self.shell, prefilter_manager=self, config=self.config
231 shell=self.shell, prefilter_manager=self, config=self.config
304 )
232 )
305
233
306 @property
234 @property
307 def handlers(self):
235 def handlers(self):
308 """Return a dict of all the handlers."""
236 """Return a dict of all the handlers."""
309 return self._handlers
237 return self._handlers
310
238
311 def register_handler(self, name, handler, esc_strings):
239 def register_handler(self, name, handler, esc_strings):
312 """Register a handler instance by name with esc_strings."""
240 """Register a handler instance by name with esc_strings."""
313 self._handlers[name] = handler
241 self._handlers[name] = handler
314 for esc_str in esc_strings:
242 for esc_str in esc_strings:
315 self._esc_handlers[esc_str] = handler
243 self._esc_handlers[esc_str] = handler
316
244
317 def unregister_handler(self, name, handler, esc_strings):
245 def unregister_handler(self, name, handler, esc_strings):
318 """Unregister a handler instance by name with esc_strings."""
246 """Unregister a handler instance by name with esc_strings."""
319 try:
247 try:
320 del self._handlers[name]
248 del self._handlers[name]
321 except KeyError:
249 except KeyError:
322 pass
250 pass
323 for esc_str in esc_strings:
251 for esc_str in esc_strings:
324 h = self._esc_handlers.get(esc_str)
252 h = self._esc_handlers.get(esc_str)
325 if h is handler:
253 if h is handler:
326 del self._esc_handlers[esc_str]
254 del self._esc_handlers[esc_str]
327
255
328 def get_handler_by_name(self, name):
256 def get_handler_by_name(self, name):
329 """Get a handler by its name."""
257 """Get a handler by its name."""
330 return self._handlers.get(name)
258 return self._handlers.get(name)
331
259
332 def get_handler_by_esc(self, esc_str):
260 def get_handler_by_esc(self, esc_str):
333 """Get a handler by its escape string."""
261 """Get a handler by its escape string."""
334 return self._esc_handlers.get(esc_str)
262 return self._esc_handlers.get(esc_str)
335
263
336 #-------------------------------------------------------------------------
264 #-------------------------------------------------------------------------
337 # Main prefiltering API
265 # Main prefiltering API
338 #-------------------------------------------------------------------------
266 #-------------------------------------------------------------------------
339
267
340 def prefilter_line_info(self, line_info):
268 def prefilter_line_info(self, line_info):
341 """Prefilter a line that has been converted to a LineInfo object.
269 """Prefilter a line that has been converted to a LineInfo object.
342
270
343 This implements the checker/handler part of the prefilter pipe.
271 This implements the checker/handler part of the prefilter pipe.
344 """
272 """
345 # print "prefilter_line_info: ", line_info
273 # print "prefilter_line_info: ", line_info
346 handler = self.find_handler(line_info)
274 handler = self.find_handler(line_info)
347 return handler.handle(line_info)
275 return handler.handle(line_info)
348
276
349 def find_handler(self, line_info):
277 def find_handler(self, line_info):
350 """Find a handler for the line_info by trying checkers."""
278 """Find a handler for the line_info by trying checkers."""
351 for checker in self.checkers:
279 for checker in self.checkers:
352 if checker.enabled:
280 if checker.enabled:
353 handler = checker.check(line_info)
281 handler = checker.check(line_info)
354 if handler:
282 if handler:
355 return handler
283 return handler
356 return self.get_handler_by_name('normal')
284 return self.get_handler_by_name('normal')
357
285
358 def transform_line(self, line, continue_prompt):
286 def transform_line(self, line, continue_prompt):
359 """Calls the enabled transformers in order of increasing priority."""
287 """Calls the enabled transformers in order of increasing priority."""
360 for transformer in self.transformers:
288 for transformer in self.transformers:
361 if transformer.enabled:
289 if transformer.enabled:
362 line = transformer.transform(line, continue_prompt)
290 line = transformer.transform(line, continue_prompt)
363 return line
291 return line
364
292
365 def prefilter_line(self, line, continue_prompt=False):
293 def prefilter_line(self, line, continue_prompt=False):
366 """Prefilter a single input line as text.
294 """Prefilter a single input line as text.
367
295
368 This method prefilters a single line of text by calling the
296 This method prefilters a single line of text by calling the
369 transformers and then the checkers/handlers.
297 transformers and then the checkers/handlers.
370 """
298 """
371
299
372 # print "prefilter_line: ", line, continue_prompt
300 # print "prefilter_line: ", line, continue_prompt
373 # All handlers *must* return a value, even if it's blank ('').
301 # All handlers *must* return a value, even if it's blank ('').
374
302
375 # save the line away in case we crash, so the post-mortem handler can
303 # save the line away in case we crash, so the post-mortem handler can
376 # record it
304 # record it
377 self.shell._last_input_line = line
305 self.shell._last_input_line = line
378
306
379 if not line:
307 if not line:
380 # Return immediately on purely empty lines, so that if the user
308 # Return immediately on purely empty lines, so that if the user
381 # previously typed some whitespace that started a continuation
309 # previously typed some whitespace that started a continuation
382 # prompt, he can break out of that loop with just an empty line.
310 # prompt, he can break out of that loop with just an empty line.
383 # This is how the default python prompt works.
311 # This is how the default python prompt works.
384 return ''
312 return ''
385
313
386 # At this point, we invoke our transformers.
314 # At this point, we invoke our transformers.
387 if not continue_prompt or (continue_prompt and self.multi_line_specials):
315 if not continue_prompt or (continue_prompt and self.multi_line_specials):
388 line = self.transform_line(line, continue_prompt)
316 line = self.transform_line(line, continue_prompt)
389
317
390 # Now we compute line_info for the checkers and handlers
318 # Now we compute line_info for the checkers and handlers
391 line_info = LineInfo(line, continue_prompt)
319 line_info = LineInfo(line, continue_prompt)
392
320
393 # the input history needs to track even empty lines
321 # the input history needs to track even empty lines
394 stripped = line.strip()
322 stripped = line.strip()
395
323
396 normal_handler = self.get_handler_by_name('normal')
324 normal_handler = self.get_handler_by_name('normal')
397 if not stripped:
325 if not stripped:
398 if not continue_prompt:
326 if not continue_prompt:
399 self.shell.displayhook.prompt_count -= 1
327 self.shell.displayhook.prompt_count -= 1
400
328
401 return normal_handler.handle(line_info)
329 return normal_handler.handle(line_info)
402
330
403 # special handlers are only allowed for single line statements
331 # special handlers are only allowed for single line statements
404 if continue_prompt and not self.multi_line_specials:
332 if continue_prompt and not self.multi_line_specials:
405 return normal_handler.handle(line_info)
333 return normal_handler.handle(line_info)
406
334
407 prefiltered = self.prefilter_line_info(line_info)
335 prefiltered = self.prefilter_line_info(line_info)
408 # print "prefiltered line: %r" % prefiltered
336 # print "prefiltered line: %r" % prefiltered
409 return prefiltered
337 return prefiltered
410
338
411 def prefilter_lines(self, lines, continue_prompt=False):
339 def prefilter_lines(self, lines, continue_prompt=False):
412 """Prefilter multiple input lines of text.
340 """Prefilter multiple input lines of text.
413
341
414 This is the main entry point for prefiltering multiple lines of
342 This is the main entry point for prefiltering multiple lines of
415 input. This simply calls :meth:`prefilter_line` for each line of
343 input. This simply calls :meth:`prefilter_line` for each line of
416 input.
344 input.
417
345
418 This covers cases where there are multiple lines in the user entry,
346 This covers cases where there are multiple lines in the user entry,
419 which is the case when the user goes back to a multiline history
347 which is the case when the user goes back to a multiline history
420 entry and presses enter.
348 entry and presses enter.
421 """
349 """
422 llines = lines.rstrip('\n').split('\n')
350 llines = lines.rstrip('\n').split('\n')
423 # We can get multiple lines in one shot, where multiline input 'blends'
351 # We can get multiple lines in one shot, where multiline input 'blends'
424 # into one line, in cases like recalling from the readline history
352 # into one line, in cases like recalling from the readline history
425 # buffer. We need to make sure that in such cases, we correctly
353 # buffer. We need to make sure that in such cases, we correctly
426 # communicate downstream which line is first and which are continuation
354 # communicate downstream which line is first and which are continuation
427 # ones.
355 # ones.
428 if len(llines) > 1:
356 if len(llines) > 1:
429 out = '\n'.join([self.prefilter_line(line, lnum>0)
357 out = '\n'.join([self.prefilter_line(line, lnum>0)
430 for lnum, line in enumerate(llines) ])
358 for lnum, line in enumerate(llines) ])
431 else:
359 else:
432 out = self.prefilter_line(llines[0], continue_prompt)
360 out = self.prefilter_line(llines[0], continue_prompt)
433
361
434 return out
362 return out
435
363
436 #-----------------------------------------------------------------------------
364 #-----------------------------------------------------------------------------
437 # Prefilter transformers
365 # Prefilter transformers
438 #-----------------------------------------------------------------------------
366 #-----------------------------------------------------------------------------
439
367
440
368
441 class PrefilterTransformer(Configurable):
369 class PrefilterTransformer(Configurable):
442 """Transform a line of user input."""
370 """Transform a line of user input."""
443
371
444 priority = Int(100, config=True)
372 priority = Int(100, config=True)
445 # Transformers don't currently use shell or prefilter_manager, but as we
373 # Transformers don't currently use shell or prefilter_manager, but as we
446 # move away from checkers and handlers, they will need them.
374 # move away from checkers and handlers, they will need them.
447 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
375 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
448 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
376 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
449 enabled = Bool(True, config=True)
377 enabled = Bool(True, config=True)
450
378
451 def __init__(self, shell=None, prefilter_manager=None, config=None):
379 def __init__(self, shell=None, prefilter_manager=None, config=None):
452 super(PrefilterTransformer, self).__init__(
380 super(PrefilterTransformer, self).__init__(
453 shell=shell, prefilter_manager=prefilter_manager, config=config
381 shell=shell, prefilter_manager=prefilter_manager, config=config
454 )
382 )
455 self.prefilter_manager.register_transformer(self)
383 self.prefilter_manager.register_transformer(self)
456
384
457 def transform(self, line, continue_prompt):
385 def transform(self, line, continue_prompt):
458 """Transform a line, returning the new one."""
386 """Transform a line, returning the new one."""
459 return None
387 return None
460
388
461 def __repr__(self):
389 def __repr__(self):
462 return "<%s(priority=%r, enabled=%r)>" % (
390 return "<%s(priority=%r, enabled=%r)>" % (
463 self.__class__.__name__, self.priority, self.enabled)
391 self.__class__.__name__, self.priority, self.enabled)
464
392
465
393
466 _assign_system_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
394 _assign_system_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
467 r'\s*=\s*!(?P<cmd>.*)')
395 r'\s*=\s*!(?P<cmd>.*)')
468
396
469
397
470 class AssignSystemTransformer(PrefilterTransformer):
398 class AssignSystemTransformer(PrefilterTransformer):
471 """Handle the `files = !ls` syntax."""
399 """Handle the `files = !ls` syntax."""
472
400
473 priority = Int(100, config=True)
401 priority = Int(100, config=True)
474
402
475 def transform(self, line, continue_prompt):
403 def transform(self, line, continue_prompt):
476 m = _assign_system_re.match(line)
404 m = _assign_system_re.match(line)
477 if m is not None:
405 if m is not None:
478 cmd = m.group('cmd')
406 cmd = m.group('cmd')
479 lhs = m.group('lhs')
407 lhs = m.group('lhs')
480 expr = make_quoted_expr("sc =%s" % cmd)
408 expr = make_quoted_expr("sc =%s" % cmd)
481 new_line = '%s = get_ipython().magic(%s)' % (lhs, expr)
409 new_line = '%s = get_ipython().magic(%s)' % (lhs, expr)
482 return new_line
410 return new_line
483 return line
411 return line
484
412
485
413
486 _assign_magic_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
414 _assign_magic_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
487 r'\s*=\s*%(?P<cmd>.*)')
415 r'\s*=\s*%(?P<cmd>.*)')
488
416
489 class AssignMagicTransformer(PrefilterTransformer):
417 class AssignMagicTransformer(PrefilterTransformer):
490 """Handle the `a = %who` syntax."""
418 """Handle the `a = %who` syntax."""
491
419
492 priority = Int(200, config=True)
420 priority = Int(200, config=True)
493
421
494 def transform(self, line, continue_prompt):
422 def transform(self, line, continue_prompt):
495 m = _assign_magic_re.match(line)
423 m = _assign_magic_re.match(line)
496 if m is not None:
424 if m is not None:
497 cmd = m.group('cmd')
425 cmd = m.group('cmd')
498 lhs = m.group('lhs')
426 lhs = m.group('lhs')
499 expr = make_quoted_expr(cmd)
427 expr = make_quoted_expr(cmd)
500 new_line = '%s = get_ipython().magic(%s)' % (lhs, expr)
428 new_line = '%s = get_ipython().magic(%s)' % (lhs, expr)
501 return new_line
429 return new_line
502 return line
430 return line
503
431
504
432
505 _classic_prompt_re = re.compile(r'(^[ \t]*>>> |^[ \t]*\.\.\. )')
433 _classic_prompt_re = re.compile(r'(^[ \t]*>>> |^[ \t]*\.\.\. )')
506
434
507 class PyPromptTransformer(PrefilterTransformer):
435 class PyPromptTransformer(PrefilterTransformer):
508 """Handle inputs that start with '>>> ' syntax."""
436 """Handle inputs that start with '>>> ' syntax."""
509
437
510 priority = Int(50, config=True)
438 priority = Int(50, config=True)
511
439
512 def transform(self, line, continue_prompt):
440 def transform(self, line, continue_prompt):
513
441
514 if not line or line.isspace() or line.strip() == '...':
442 if not line or line.isspace() or line.strip() == '...':
515 # This allows us to recognize multiple input prompts separated by
443 # This allows us to recognize multiple input prompts separated by
516 # blank lines and pasted in a single chunk, very common when
444 # blank lines and pasted in a single chunk, very common when
517 # pasting doctests or long tutorial passages.
445 # pasting doctests or long tutorial passages.
518 return ''
446 return ''
519 m = _classic_prompt_re.match(line)
447 m = _classic_prompt_re.match(line)
520 if m:
448 if m:
521 return line[len(m.group(0)):]
449 return line[len(m.group(0)):]
522 else:
450 else:
523 return line
451 return line
524
452
525
453
526 _ipy_prompt_re = re.compile(r'(^[ \t]*In \[\d+\]: |^[ \t]*\ \ \ \.\.\.+: )')
454 _ipy_prompt_re = re.compile(r'(^[ \t]*In \[\d+\]: |^[ \t]*\ \ \ \.\.\.+: )')
527
455
528 class IPyPromptTransformer(PrefilterTransformer):
456 class IPyPromptTransformer(PrefilterTransformer):
529 """Handle inputs that start classic IPython prompt syntax."""
457 """Handle inputs that start classic IPython prompt syntax."""
530
458
531 priority = Int(50, config=True)
459 priority = Int(50, config=True)
532
460
533 def transform(self, line, continue_prompt):
461 def transform(self, line, continue_prompt):
534
462
535 if not line or line.isspace() or line.strip() == '...':
463 if not line or line.isspace() or line.strip() == '...':
536 # This allows us to recognize multiple input prompts separated by
464 # This allows us to recognize multiple input prompts separated by
537 # blank lines and pasted in a single chunk, very common when
465 # blank lines and pasted in a single chunk, very common when
538 # pasting doctests or long tutorial passages.
466 # pasting doctests or long tutorial passages.
539 return ''
467 return ''
540 m = _ipy_prompt_re.match(line)
468 m = _ipy_prompt_re.match(line)
541 if m:
469 if m:
542 return line[len(m.group(0)):]
470 return line[len(m.group(0)):]
543 else:
471 else:
544 return line
472 return line
545
473
546 #-----------------------------------------------------------------------------
474 #-----------------------------------------------------------------------------
547 # Prefilter checkers
475 # Prefilter checkers
548 #-----------------------------------------------------------------------------
476 #-----------------------------------------------------------------------------
549
477
550
478
551 class PrefilterChecker(Configurable):
479 class PrefilterChecker(Configurable):
552 """Inspect an input line and return a handler for that line."""
480 """Inspect an input line and return a handler for that line."""
553
481
554 priority = Int(100, config=True)
482 priority = Int(100, config=True)
555 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
483 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
556 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
484 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
557 enabled = Bool(True, config=True)
485 enabled = Bool(True, config=True)
558
486
559 def __init__(self, shell=None, prefilter_manager=None, config=None):
487 def __init__(self, shell=None, prefilter_manager=None, config=None):
560 super(PrefilterChecker, self).__init__(
488 super(PrefilterChecker, self).__init__(
561 shell=shell, prefilter_manager=prefilter_manager, config=config
489 shell=shell, prefilter_manager=prefilter_manager, config=config
562 )
490 )
563 self.prefilter_manager.register_checker(self)
491 self.prefilter_manager.register_checker(self)
564
492
565 def check(self, line_info):
493 def check(self, line_info):
566 """Inspect line_info and return a handler instance or None."""
494 """Inspect line_info and return a handler instance or None."""
567 return None
495 return None
568
496
569 def __repr__(self):
497 def __repr__(self):
570 return "<%s(priority=%r, enabled=%r)>" % (
498 return "<%s(priority=%r, enabled=%r)>" % (
571 self.__class__.__name__, self.priority, self.enabled)
499 self.__class__.__name__, self.priority, self.enabled)
572
500
573
501
574 class EmacsChecker(PrefilterChecker):
502 class EmacsChecker(PrefilterChecker):
575
503
576 priority = Int(100, config=True)
504 priority = Int(100, config=True)
577 enabled = Bool(False, config=True)
505 enabled = Bool(False, config=True)
578
506
579 def check(self, line_info):
507 def check(self, line_info):
580 "Emacs ipython-mode tags certain input lines."
508 "Emacs ipython-mode tags certain input lines."
581 if line_info.line.endswith('# PYTHON-MODE'):
509 if line_info.line.endswith('# PYTHON-MODE'):
582 return self.prefilter_manager.get_handler_by_name('emacs')
510 return self.prefilter_manager.get_handler_by_name('emacs')
583 else:
511 else:
584 return None
512 return None
585
513
586
514
587 class ShellEscapeChecker(PrefilterChecker):
515 class ShellEscapeChecker(PrefilterChecker):
588
516
589 priority = Int(200, config=True)
517 priority = Int(200, config=True)
590
518
591 def check(self, line_info):
519 def check(self, line_info):
592 if line_info.line.lstrip().startswith(ESC_SHELL):
520 if line_info.line.lstrip().startswith(ESC_SHELL):
593 return self.prefilter_manager.get_handler_by_name('shell')
521 return self.prefilter_manager.get_handler_by_name('shell')
594
522
595
523
596 class MacroChecker(PrefilterChecker):
524 class MacroChecker(PrefilterChecker):
597
525
598 priority = Int(250, config=True)
526 priority = Int(250, config=True)
599
527
600 def check(self, line_info):
528 def check(self, line_info):
601 obj = self.shell.user_ns.get(line_info.ifun)
529 obj = self.shell.user_ns.get(line_info.ifun)
602 if isinstance(obj, Macro):
530 if isinstance(obj, Macro):
603 return self.prefilter_manager.get_handler_by_name('macro')
531 return self.prefilter_manager.get_handler_by_name('macro')
604 else:
532 else:
605 return None
533 return None
606
534
607
535
608 class IPyAutocallChecker(PrefilterChecker):
536 class IPyAutocallChecker(PrefilterChecker):
609
537
610 priority = Int(300, config=True)
538 priority = Int(300, config=True)
611
539
612 def check(self, line_info):
540 def check(self, line_info):
613 "Instances of IPyAutocall in user_ns get autocalled immediately"
541 "Instances of IPyAutocall in user_ns get autocalled immediately"
614 obj = self.shell.user_ns.get(line_info.ifun, None)
542 obj = self.shell.user_ns.get(line_info.ifun, None)
615 if isinstance(obj, IPyAutocall):
543 if isinstance(obj, IPyAutocall):
616 obj.set_ip(self.shell)
544 obj.set_ip(self.shell)
617 return self.prefilter_manager.get_handler_by_name('auto')
545 return self.prefilter_manager.get_handler_by_name('auto')
618 else:
546 else:
619 return None
547 return None
620
548
621
549
622 class MultiLineMagicChecker(PrefilterChecker):
550 class MultiLineMagicChecker(PrefilterChecker):
623
551
624 priority = Int(400, config=True)
552 priority = Int(400, config=True)
625
553
626 def check(self, line_info):
554 def check(self, line_info):
627 "Allow ! and !! in multi-line statements if multi_line_specials is on"
555 "Allow ! and !! in multi-line statements if multi_line_specials is on"
628 # Note that this one of the only places we check the first character of
556 # Note that this one of the only places we check the first character of
629 # ifun and *not* the pre_char. Also note that the below test matches
557 # ifun and *not* the pre_char. Also note that the below test matches
630 # both ! and !!.
558 # both ! and !!.
631 if line_info.continue_prompt \
559 if line_info.continue_prompt \
632 and self.prefilter_manager.multi_line_specials:
560 and self.prefilter_manager.multi_line_specials:
633 if line_info.esc == ESC_MAGIC:
561 if line_info.esc == ESC_MAGIC:
634 return self.prefilter_manager.get_handler_by_name('magic')
562 return self.prefilter_manager.get_handler_by_name('magic')
635 else:
563 else:
636 return None
564 return None
637
565
638
566
639 class EscCharsChecker(PrefilterChecker):
567 class EscCharsChecker(PrefilterChecker):
640
568
641 priority = Int(500, config=True)
569 priority = Int(500, config=True)
642
570
643 def check(self, line_info):
571 def check(self, line_info):
644 """Check for escape character and return either a handler to handle it,
572 """Check for escape character and return either a handler to handle it,
645 or None if there is no escape char."""
573 or None if there is no escape char."""
646 if line_info.line[-1] == ESC_HELP \
574 if line_info.line[-1] == ESC_HELP \
647 and line_info.esc != ESC_SHELL \
575 and line_info.esc != ESC_SHELL \
648 and line_info.esc != ESC_SH_CAP:
576 and line_info.esc != ESC_SH_CAP:
649 # the ? can be at the end, but *not* for either kind of shell escape,
577 # the ? can be at the end, but *not* for either kind of shell escape,
650 # because a ? can be a vaild final char in a shell cmd
578 # because a ? can be a vaild final char in a shell cmd
651 return self.prefilter_manager.get_handler_by_name('help')
579 return self.prefilter_manager.get_handler_by_name('help')
652 else:
580 else:
653 if line_info.pre:
581 if line_info.pre:
654 return None
582 return None
655 # This returns None like it should if no handler exists
583 # This returns None like it should if no handler exists
656 return self.prefilter_manager.get_handler_by_esc(line_info.esc)
584 return self.prefilter_manager.get_handler_by_esc(line_info.esc)
657
585
658
586
659 class AssignmentChecker(PrefilterChecker):
587 class AssignmentChecker(PrefilterChecker):
660
588
661 priority = Int(600, config=True)
589 priority = Int(600, config=True)
662
590
663 def check(self, line_info):
591 def check(self, line_info):
664 """Check to see if user is assigning to a var for the first time, in
592 """Check to see if user is assigning to a var for the first time, in
665 which case we want to avoid any sort of automagic / autocall games.
593 which case we want to avoid any sort of automagic / autocall games.
666
594
667 This allows users to assign to either alias or magic names true python
595 This allows users to assign to either alias or magic names true python
668 variables (the magic/alias systems always take second seat to true
596 variables (the magic/alias systems always take second seat to true
669 python code). E.g. ls='hi', or ls,that=1,2"""
597 python code). E.g. ls='hi', or ls,that=1,2"""
670 if line_info.the_rest:
598 if line_info.the_rest:
671 if line_info.the_rest[0] in '=,':
599 if line_info.the_rest[0] in '=,':
672 return self.prefilter_manager.get_handler_by_name('normal')
600 return self.prefilter_manager.get_handler_by_name('normal')
673 else:
601 else:
674 return None
602 return None
675
603
676
604
677 class AutoMagicChecker(PrefilterChecker):
605 class AutoMagicChecker(PrefilterChecker):
678
606
679 priority = Int(700, config=True)
607 priority = Int(700, config=True)
680
608
681 def check(self, line_info):
609 def check(self, line_info):
682 """If the ifun is magic, and automagic is on, run it. Note: normal,
610 """If the ifun is magic, and automagic is on, run it. Note: normal,
683 non-auto magic would already have been triggered via '%' in
611 non-auto magic would already have been triggered via '%' in
684 check_esc_chars. This just checks for automagic. Also, before
612 check_esc_chars. This just checks for automagic. Also, before
685 triggering the magic handler, make sure that there is nothing in the
613 triggering the magic handler, make sure that there is nothing in the
686 user namespace which could shadow it."""
614 user namespace which could shadow it."""
687 if not self.shell.automagic or not hasattr(self.shell,'magic_'+line_info.ifun):
615 if not self.shell.automagic or not hasattr(self.shell,'magic_'+line_info.ifun):
688 return None
616 return None
689
617
690 # We have a likely magic method. Make sure we should actually call it.
618 # We have a likely magic method. Make sure we should actually call it.
691 if line_info.continue_prompt and not self.prefilter_manager.multi_line_specials:
619 if line_info.continue_prompt and not self.prefilter_manager.multi_line_specials:
692 return None
620 return None
693
621
694 head = line_info.ifun.split('.',1)[0]
622 head = line_info.ifun.split('.',1)[0]
695 if is_shadowed(head, self.shell):
623 if is_shadowed(head, self.shell):
696 return None
624 return None
697
625
698 return self.prefilter_manager.get_handler_by_name('magic')
626 return self.prefilter_manager.get_handler_by_name('magic')
699
627
700
628
701 class AliasChecker(PrefilterChecker):
629 class AliasChecker(PrefilterChecker):
702
630
703 priority = Int(800, config=True)
631 priority = Int(800, config=True)
704
632
705 def check(self, line_info):
633 def check(self, line_info):
706 "Check if the initital identifier on the line is an alias."
634 "Check if the initital identifier on the line is an alias."
707 # Note: aliases can not contain '.'
635 # Note: aliases can not contain '.'
708 head = line_info.ifun.split('.',1)[0]
636 head = line_info.ifun.split('.',1)[0]
709 if line_info.ifun not in self.shell.alias_manager \
637 if line_info.ifun not in self.shell.alias_manager \
710 or head not in self.shell.alias_manager \
638 or head not in self.shell.alias_manager \
711 or is_shadowed(head, self.shell):
639 or is_shadowed(head, self.shell):
712 return None
640 return None
713
641
714 return self.prefilter_manager.get_handler_by_name('alias')
642 return self.prefilter_manager.get_handler_by_name('alias')
715
643
716
644
717 class PythonOpsChecker(PrefilterChecker):
645 class PythonOpsChecker(PrefilterChecker):
718
646
719 priority = Int(900, config=True)
647 priority = Int(900, config=True)
720
648
721 def check(self, line_info):
649 def check(self, line_info):
722 """If the 'rest' of the line begins with a function call or pretty much
650 """If the 'rest' of the line begins with a function call or pretty much
723 any python operator, we should simply execute the line (regardless of
651 any python operator, we should simply execute the line (regardless of
724 whether or not there's a possible autocall expansion). This avoids
652 whether or not there's a possible autocall expansion). This avoids
725 spurious (and very confusing) geattr() accesses."""
653 spurious (and very confusing) geattr() accesses."""
726 if line_info.the_rest and line_info.the_rest[0] in '!=()<>,+*/%^&|':
654 if line_info.the_rest and line_info.the_rest[0] in '!=()<>,+*/%^&|':
727 return self.prefilter_manager.get_handler_by_name('normal')
655 return self.prefilter_manager.get_handler_by_name('normal')
728 else:
656 else:
729 return None
657 return None
730
658
731
659
732 class AutocallChecker(PrefilterChecker):
660 class AutocallChecker(PrefilterChecker):
733
661
734 priority = Int(1000, config=True)
662 priority = Int(1000, config=True)
735
663
736 def check(self, line_info):
664 def check(self, line_info):
737 "Check if the initial word/function is callable and autocall is on."
665 "Check if the initial word/function is callable and autocall is on."
738 if not self.shell.autocall:
666 if not self.shell.autocall:
739 return None
667 return None
740
668
741 oinfo = line_info.ofind(self.shell) # This can mutate state via getattr
669 oinfo = line_info.ofind(self.shell) # This can mutate state via getattr
742 if not oinfo['found']:
670 if not oinfo['found']:
743 return None
671 return None
744
672
745 if callable(oinfo['obj']) \
673 if callable(oinfo['obj']) \
746 and (not re_exclude_auto.match(line_info.the_rest)) \
674 and (not re_exclude_auto.match(line_info.the_rest)) \
747 and re_fun_name.match(line_info.ifun):
675 and re_fun_name.match(line_info.ifun):
748 return self.prefilter_manager.get_handler_by_name('auto')
676 return self.prefilter_manager.get_handler_by_name('auto')
749 else:
677 else:
750 return None
678 return None
751
679
752
680
753 #-----------------------------------------------------------------------------
681 #-----------------------------------------------------------------------------
754 # Prefilter handlers
682 # Prefilter handlers
755 #-----------------------------------------------------------------------------
683 #-----------------------------------------------------------------------------
756
684
757
685
758 class PrefilterHandler(Configurable):
686 class PrefilterHandler(Configurable):
759
687
760 handler_name = Unicode('normal')
688 handler_name = Unicode('normal')
761 esc_strings = List([])
689 esc_strings = List([])
762 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
690 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
763 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
691 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
764
692
765 def __init__(self, shell=None, prefilter_manager=None, config=None):
693 def __init__(self, shell=None, prefilter_manager=None, config=None):
766 super(PrefilterHandler, self).__init__(
694 super(PrefilterHandler, self).__init__(
767 shell=shell, prefilter_manager=prefilter_manager, config=config
695 shell=shell, prefilter_manager=prefilter_manager, config=config
768 )
696 )
769 self.prefilter_manager.register_handler(
697 self.prefilter_manager.register_handler(
770 self.handler_name,
698 self.handler_name,
771 self,
699 self,
772 self.esc_strings
700 self.esc_strings
773 )
701 )
774
702
775 def handle(self, line_info):
703 def handle(self, line_info):
776 # print "normal: ", line_info
704 # print "normal: ", line_info
777 """Handle normal input lines. Use as a template for handlers."""
705 """Handle normal input lines. Use as a template for handlers."""
778
706
779 # With autoindent on, we need some way to exit the input loop, and I
707 # With autoindent on, we need some way to exit the input loop, and I
780 # don't want to force the user to have to backspace all the way to
708 # don't want to force the user to have to backspace all the way to
781 # clear the line. The rule will be in this case, that either two
709 # clear the line. The rule will be in this case, that either two
782 # lines of pure whitespace in a row, or a line of pure whitespace but
710 # lines of pure whitespace in a row, or a line of pure whitespace but
783 # of a size different to the indent level, will exit the input loop.
711 # of a size different to the indent level, will exit the input loop.
784 line = line_info.line
712 line = line_info.line
785 continue_prompt = line_info.continue_prompt
713 continue_prompt = line_info.continue_prompt
786
714
787 if (continue_prompt and
715 if (continue_prompt and
788 self.shell.autoindent and
716 self.shell.autoindent and
789 line.isspace() and
717 line.isspace() and
790 0 < abs(len(line) - self.shell.indent_current_nsp) <= 2):
718 0 < abs(len(line) - self.shell.indent_current_nsp) <= 2):
791 line = ''
719 line = ''
792
720
793 return line
721 return line
794
722
795 def __str__(self):
723 def __str__(self):
796 return "<%s(name=%s)>" % (self.__class__.__name__, self.handler_name)
724 return "<%s(name=%s)>" % (self.__class__.__name__, self.handler_name)
797
725
798
726
799 class AliasHandler(PrefilterHandler):
727 class AliasHandler(PrefilterHandler):
800
728
801 handler_name = Unicode('alias')
729 handler_name = Unicode('alias')
802
730
803 def handle(self, line_info):
731 def handle(self, line_info):
804 """Handle alias input lines. """
732 """Handle alias input lines. """
805 transformed = self.shell.alias_manager.expand_aliases(line_info.ifun,line_info.the_rest)
733 transformed = self.shell.alias_manager.expand_aliases(line_info.ifun,line_info.the_rest)
806 # pre is needed, because it carries the leading whitespace. Otherwise
734 # pre is needed, because it carries the leading whitespace. Otherwise
807 # aliases won't work in indented sections.
735 # aliases won't work in indented sections.
808 line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace,
736 line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace,
809 make_quoted_expr(transformed))
737 make_quoted_expr(transformed))
810
738
811 return line_out
739 return line_out
812
740
813
741
814 class ShellEscapeHandler(PrefilterHandler):
742 class ShellEscapeHandler(PrefilterHandler):
815
743
816 handler_name = Unicode('shell')
744 handler_name = Unicode('shell')
817 esc_strings = List([ESC_SHELL, ESC_SH_CAP])
745 esc_strings = List([ESC_SHELL, ESC_SH_CAP])
818
746
819 def handle(self, line_info):
747 def handle(self, line_info):
820 """Execute the line in a shell, empty return value"""
748 """Execute the line in a shell, empty return value"""
821 magic_handler = self.prefilter_manager.get_handler_by_name('magic')
749 magic_handler = self.prefilter_manager.get_handler_by_name('magic')
822
750
823 line = line_info.line
751 line = line_info.line
824 if line.lstrip().startswith(ESC_SH_CAP):
752 if line.lstrip().startswith(ESC_SH_CAP):
825 # rewrite LineInfo's line, ifun and the_rest to properly hold the
753 # rewrite LineInfo's line, ifun and the_rest to properly hold the
826 # call to %sx and the actual command to be executed, so
754 # call to %sx and the actual command to be executed, so
827 # handle_magic can work correctly. Note that this works even if
755 # handle_magic can work correctly. Note that this works even if
828 # the line is indented, so it handles multi_line_specials
756 # the line is indented, so it handles multi_line_specials
829 # properly.
757 # properly.
830 new_rest = line.lstrip()[2:]
758 new_rest = line.lstrip()[2:]
831 line_info.line = '%ssx %s' % (ESC_MAGIC, new_rest)
759 line_info.line = '%ssx %s' % (ESC_MAGIC, new_rest)
832 line_info.ifun = 'sx'
760 line_info.ifun = 'sx'
833 line_info.the_rest = new_rest
761 line_info.the_rest = new_rest
834 return magic_handler.handle(line_info)
762 return magic_handler.handle(line_info)
835 else:
763 else:
836 cmd = line.lstrip().lstrip(ESC_SHELL)
764 cmd = line.lstrip().lstrip(ESC_SHELL)
837 line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace,
765 line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace,
838 make_quoted_expr(cmd))
766 make_quoted_expr(cmd))
839 return line_out
767 return line_out
840
768
841
769
842 class MacroHandler(PrefilterHandler):
770 class MacroHandler(PrefilterHandler):
843 handler_name = Unicode("macro")
771 handler_name = Unicode("macro")
844
772
845 def handle(self, line_info):
773 def handle(self, line_info):
846 obj = self.shell.user_ns.get(line_info.ifun)
774 obj = self.shell.user_ns.get(line_info.ifun)
847 pre_space = line_info.pre_whitespace
775 pre_space = line_info.pre_whitespace
848 line_sep = "\n" + pre_space
776 line_sep = "\n" + pre_space
849 return pre_space + line_sep.join(obj.value.splitlines())
777 return pre_space + line_sep.join(obj.value.splitlines())
850
778
851
779
852 class MagicHandler(PrefilterHandler):
780 class MagicHandler(PrefilterHandler):
853
781
854 handler_name = Unicode('magic')
782 handler_name = Unicode('magic')
855 esc_strings = List([ESC_MAGIC])
783 esc_strings = List([ESC_MAGIC])
856
784
857 def handle(self, line_info):
785 def handle(self, line_info):
858 """Execute magic functions."""
786 """Execute magic functions."""
859 ifun = line_info.ifun
787 ifun = line_info.ifun
860 the_rest = line_info.the_rest
788 the_rest = line_info.the_rest
861 cmd = '%sget_ipython().magic(%s)' % (line_info.pre_whitespace,
789 cmd = '%sget_ipython().magic(%s)' % (line_info.pre_whitespace,
862 make_quoted_expr(ifun + " " + the_rest))
790 make_quoted_expr(ifun + " " + the_rest))
863 return cmd
791 return cmd
864
792
865
793
866 class AutoHandler(PrefilterHandler):
794 class AutoHandler(PrefilterHandler):
867
795
868 handler_name = Unicode('auto')
796 handler_name = Unicode('auto')
869 esc_strings = List([ESC_PAREN, ESC_QUOTE, ESC_QUOTE2])
797 esc_strings = List([ESC_PAREN, ESC_QUOTE, ESC_QUOTE2])
870
798
871 def handle(self, line_info):
799 def handle(self, line_info):
872 """Handle lines which can be auto-executed, quoting if requested."""
800 """Handle lines which can be auto-executed, quoting if requested."""
873 line = line_info.line
801 line = line_info.line
874 ifun = line_info.ifun
802 ifun = line_info.ifun
875 the_rest = line_info.the_rest
803 the_rest = line_info.the_rest
876 pre = line_info.pre
804 pre = line_info.pre
877 esc = line_info.esc
805 esc = line_info.esc
878 continue_prompt = line_info.continue_prompt
806 continue_prompt = line_info.continue_prompt
879 obj = line_info.ofind(self)['obj']
807 obj = line_info.ofind(self)['obj']
880 #print 'pre <%s> ifun <%s> rest <%s>' % (pre,ifun,the_rest) # dbg
808 #print 'pre <%s> ifun <%s> rest <%s>' % (pre,ifun,the_rest) # dbg
881
809
882 # This should only be active for single-line input!
810 # This should only be active for single-line input!
883 if continue_prompt:
811 if continue_prompt:
884 return line
812 return line
885
813
886 force_auto = isinstance(obj, IPyAutocall)
814 force_auto = isinstance(obj, IPyAutocall)
887 auto_rewrite = getattr(obj, 'rewrite', True)
815 auto_rewrite = getattr(obj, 'rewrite', True)
888
816
889 if esc == ESC_QUOTE:
817 if esc == ESC_QUOTE:
890 # Auto-quote splitting on whitespace
818 # Auto-quote splitting on whitespace
891 newcmd = '%s("%s")' % (ifun,'", "'.join(the_rest.split()) )
819 newcmd = '%s("%s")' % (ifun,'", "'.join(the_rest.split()) )
892 elif esc == ESC_QUOTE2:
820 elif esc == ESC_QUOTE2:
893 # Auto-quote whole string
821 # Auto-quote whole string
894 newcmd = '%s("%s")' % (ifun,the_rest)
822 newcmd = '%s("%s")' % (ifun,the_rest)
895 elif esc == ESC_PAREN:
823 elif esc == ESC_PAREN:
896 newcmd = '%s(%s)' % (ifun,",".join(the_rest.split()))
824 newcmd = '%s(%s)' % (ifun,",".join(the_rest.split()))
897 else:
825 else:
898 # Auto-paren.
826 # Auto-paren.
899 # We only apply it to argument-less calls if the autocall
827 # We only apply it to argument-less calls if the autocall
900 # parameter is set to 2. We only need to check that autocall is <
828 # parameter is set to 2. We only need to check that autocall is <
901 # 2, since this function isn't called unless it's at least 1.
829 # 2, since this function isn't called unless it's at least 1.
902 if not the_rest and (self.shell.autocall < 2) and not force_auto:
830 if not the_rest and (self.shell.autocall < 2) and not force_auto:
903 newcmd = '%s %s' % (ifun,the_rest)
831 newcmd = '%s %s' % (ifun,the_rest)
904 auto_rewrite = False
832 auto_rewrite = False
905 else:
833 else:
906 if not force_auto and the_rest.startswith('['):
834 if not force_auto and the_rest.startswith('['):
907 if hasattr(obj,'__getitem__'):
835 if hasattr(obj,'__getitem__'):
908 # Don't autocall in this case: item access for an object
836 # Don't autocall in this case: item access for an object
909 # which is BOTH callable and implements __getitem__.
837 # which is BOTH callable and implements __getitem__.
910 newcmd = '%s %s' % (ifun,the_rest)
838 newcmd = '%s %s' % (ifun,the_rest)
911 auto_rewrite = False
839 auto_rewrite = False
912 else:
840 else:
913 # if the object doesn't support [] access, go ahead and
841 # if the object doesn't support [] access, go ahead and
914 # autocall
842 # autocall
915 newcmd = '%s(%s)' % (ifun.rstrip(),the_rest)
843 newcmd = '%s(%s)' % (ifun.rstrip(),the_rest)
916 elif the_rest.endswith(';'):
844 elif the_rest.endswith(';'):
917 newcmd = '%s(%s);' % (ifun.rstrip(),the_rest[:-1])
845 newcmd = '%s(%s);' % (ifun.rstrip(),the_rest[:-1])
918 else:
846 else:
919 newcmd = '%s(%s)' % (ifun.rstrip(), the_rest)
847 newcmd = '%s(%s)' % (ifun.rstrip(), the_rest)
920
848
921 if auto_rewrite:
849 if auto_rewrite:
922 self.shell.auto_rewrite_input(newcmd)
850 self.shell.auto_rewrite_input(newcmd)
923
851
924 return newcmd
852 return newcmd
925
853
926
854
927 class HelpHandler(PrefilterHandler):
855 class HelpHandler(PrefilterHandler):
928
856
929 handler_name = Unicode('help')
857 handler_name = Unicode('help')
930 esc_strings = List([ESC_HELP])
858 esc_strings = List([ESC_HELP])
931
859
932 def handle(self, line_info):
860 def handle(self, line_info):
933 """Try to get some help for the object.
861 """Try to get some help for the object.
934
862
935 obj? or ?obj -> basic information.
863 obj? or ?obj -> basic information.
936 obj?? or ??obj -> more details.
864 obj?? or ??obj -> more details.
937 """
865 """
938 normal_handler = self.prefilter_manager.get_handler_by_name('normal')
866 normal_handler = self.prefilter_manager.get_handler_by_name('normal')
939 line = line_info.line
867 line = line_info.line
940 # We need to make sure that we don't process lines which would be
868 # We need to make sure that we don't process lines which would be
941 # otherwise valid python, such as "x=1 # what?"
869 # otherwise valid python, such as "x=1 # what?"
942 try:
870 try:
943 codeop.compile_command(line)
871 codeop.compile_command(line)
944 except SyntaxError:
872 except SyntaxError:
945 # We should only handle as help stuff which is NOT valid syntax
873 # We should only handle as help stuff which is NOT valid syntax
946 if line[0]==ESC_HELP:
874 if line[0]==ESC_HELP:
947 line = line[1:]
875 line = line[1:]
948 elif line[-1]==ESC_HELP:
876 elif line[-1]==ESC_HELP:
949 line = line[:-1]
877 line = line[:-1]
950 if line:
878 if line:
951 #print 'line:<%r>' % line # dbg
879 #print 'line:<%r>' % line # dbg
952 self.shell.magic_pinfo(line_info.ifun)
880 self.shell.magic_pinfo(line_info.ifun)
953 else:
881 else:
954 self.shell.show_usage()
882 self.shell.show_usage()
955 return '' # Empty string is needed here!
883 return '' # Empty string is needed here!
956 except:
884 except:
957 raise
885 raise
958 # Pass any other exceptions through to the normal handler
886 # Pass any other exceptions through to the normal handler
959 return normal_handler.handle(line_info)
887 return normal_handler.handle(line_info)
960 else:
888 else:
961 # If the code compiles ok, we should handle it normally
889 # If the code compiles ok, we should handle it normally
962 return normal_handler.handle(line_info)
890 return normal_handler.handle(line_info)
963
891
964
892
965 class EmacsHandler(PrefilterHandler):
893 class EmacsHandler(PrefilterHandler):
966
894
967 handler_name = Unicode('emacs')
895 handler_name = Unicode('emacs')
968 esc_strings = List([])
896 esc_strings = List([])
969
897
970 def handle(self, line_info):
898 def handle(self, line_info):
971 """Handle input lines marked by python-mode."""
899 """Handle input lines marked by python-mode."""
972
900
973 # Currently, nothing is done. Later more functionality can be added
901 # Currently, nothing is done. Later more functionality can be added
974 # here if needed.
902 # here if needed.
975
903
976 # The input cache shouldn't be updated
904 # The input cache shouldn't be updated
977 return line_info.line
905 return line_info.line
978
906
979
907
980 #-----------------------------------------------------------------------------
908 #-----------------------------------------------------------------------------
981 # Defaults
909 # Defaults
982 #-----------------------------------------------------------------------------
910 #-----------------------------------------------------------------------------
983
911
984
912
985 _default_transformers = [
913 _default_transformers = [
986 AssignSystemTransformer,
914 AssignSystemTransformer,
987 AssignMagicTransformer,
915 AssignMagicTransformer,
988 PyPromptTransformer,
916 PyPromptTransformer,
989 IPyPromptTransformer,
917 IPyPromptTransformer,
990 ]
918 ]
991
919
992 _default_checkers = [
920 _default_checkers = [
993 EmacsChecker,
921 EmacsChecker,
994 ShellEscapeChecker,
922 ShellEscapeChecker,
995 MacroChecker,
923 MacroChecker,
996 IPyAutocallChecker,
924 IPyAutocallChecker,
997 MultiLineMagicChecker,
925 MultiLineMagicChecker,
998 EscCharsChecker,
926 EscCharsChecker,
999 AssignmentChecker,
927 AssignmentChecker,
1000 AutoMagicChecker,
928 AutoMagicChecker,
1001 AliasChecker,
929 AliasChecker,
1002 PythonOpsChecker,
930 PythonOpsChecker,
1003 AutocallChecker
931 AutocallChecker
1004 ]
932 ]
1005
933
1006 _default_handlers = [
934 _default_handlers = [
1007 PrefilterHandler,
935 PrefilterHandler,
1008 AliasHandler,
936 AliasHandler,
1009 ShellEscapeHandler,
937 ShellEscapeHandler,
1010 MacroHandler,
938 MacroHandler,
1011 MagicHandler,
939 MagicHandler,
1012 AutoHandler,
940 AutoHandler,
1013 HelpHandler,
941 HelpHandler,
1014 EmacsHandler
942 EmacsHandler
1015 ]
943 ]
@@ -1,86 +1,138 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Simple utility for splitting user input.
3 Simple utility for splitting user input. This is used by both inputsplitter and
4 prefilter.
4
5
5 Authors:
6 Authors:
6
7
7 * Brian Granger
8 * Brian Granger
8 * Fernando Perez
9 * Fernando Perez
9 """
10 """
10
11
11 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
12 # Copyright (C) 2008-2009 The IPython Development Team
13 # Copyright (C) 2008-2009 The IPython Development Team
13 #
14 #
14 # Distributed under the terms of the BSD License. The full license is in
15 # Distributed under the terms of the BSD License. The full license is in
15 # the file COPYING, distributed as part of this software.
16 # the file COPYING, distributed as part of this software.
16 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
17
18
18 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
19 # Imports
20 # Imports
20 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
21
22
22 import re
23 import re
23 import sys
24 import sys
24
25
25 from IPython.utils import py3compat
26 from IPython.utils import py3compat
26
27
27 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
28 # Main function
29 # Main function
29 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
30
31
31
32 # RegExp for splitting line contents into pre-char//first word-method//rest.
32 # RegExp for splitting line contents into pre-char//first word-method//rest.
33 # For clarity, each group in on one line.
33 # For clarity, each group in on one line.
34
34
35 # WARNING: update the regexp if the escapes in interactiveshell are changed, as they
35 # WARNING: update the regexp if the escapes in interactiveshell are changed, as
36 # are hardwired in.
36 # they are hardwired in.
37
37
38 # Although it's not solely driven by the regex, note that:
38 # Although it's not solely driven by the regex, note that:
39 # ,;/% only trigger if they are the first character on the line
39 # ,;/% only trigger if they are the first character on the line
40 # ! and !! trigger if they are first char(s) *or* follow an indent
40 # ! and !! trigger if they are first char(s) *or* follow an indent
41 # ? triggers as first or last char.
41 # ? triggers as first or last char.
42
42
43 # The four parts of the regex are:
43 line_split = re.compile("""
44 # 1) pre: initial whitespace
44 ^(\s*) # any leading space
45 # 2) esc: escape character
45 ([,;/%]|!!?|\?\??)? # escape character or characters
46 # 3) ifun: first word/method (mix of \w and '.')
46 \s*(%?[\w\.\*]*) # function/method, possibly with leading %
47 # 4) the_rest: rest of line (separated from ifun by space if non-empty)
47 # to correctly treat things like '?%magic'
48 line_split = re.compile(r'^(\s*)'
48 (.*?$|$) # rest of line
49 r'([,;/%?]|!!?)?'
49 """, re.VERBOSE)
50 r'\s*([\w\.]+)'
51 r'(.*$|$)')
52
53 # r'[\w\.]+'
54 # r'\s*=\s*%.*'
55
50
56 def split_user_input(line, pattern=None):
51 def split_user_input(line, pattern=None):
57 """Split user input into pre-char/whitespace, function part and rest.
52 """Split user input into initial whitespace, escape character, function part
58
53 and the rest.
59 This is currently handles lines with '=' in them in a very inconsistent
60 manner.
61 """
54 """
62 # We need to ensure that the rest of this routine deals only with unicode
55 # We need to ensure that the rest of this routine deals only with unicode
63 line = py3compat.cast_unicode(line, sys.stdin.encoding or 'utf-8')
56 line = py3compat.cast_unicode(line, sys.stdin.encoding or 'utf-8')
64
57
65 if pattern is None:
58 if pattern is None:
66 pattern = line_split
59 pattern = line_split
67 match = pattern.match(line)
60 match = pattern.match(line)
68 if not match:
61 if not match:
69 # print "match failed for line '%s'" % line
62 # print "match failed for line '%s'" % line
70 try:
63 try:
71 ifun, the_rest = line.split(None,1)
64 ifun, the_rest = line.split(None,1)
72 except ValueError:
65 except ValueError:
73 # print "split failed for line '%s'" % line
66 # print "split failed for line '%s'" % line
74 ifun, the_rest = line, u''
67 ifun, the_rest = line, u''
75 pre = re.match('^(\s*)(.*)',line).groups()[0]
68 pre = re.match('^(\s*)(.*)',line).groups()[0]
76 esc = ""
69 esc = ""
77 else:
70 else:
78 pre, esc, ifun, the_rest = match.groups()
71 pre, esc, ifun, the_rest = match.groups()
79
80 if not py3compat.isidentifier(ifun, dotted=True):
81 the_rest = ifun + u' ' + the_rest
82 ifun = u''
83
72
84 #print 'line:<%s>' % line # dbg
73 #print 'line:<%s>' % line # dbg
85 #print 'pre <%s> ifun <%s> rest <%s>' % (pre,ifun.strip(),the_rest) # dbg
74 #print 'pre <%s> ifun <%s> rest <%s>' % (pre,ifun.strip(),the_rest) # dbg
86 return pre, esc, ifun.strip(), the_rest.lstrip()
75 return pre, esc or '', ifun.strip(), the_rest.lstrip()
76
77 class LineInfo(object):
78 """A single line of input and associated info.
79
80 Includes the following as properties:
81
82 line
83 The original, raw line
84
85 continue_prompt
86 Is this line a continuation in a sequence of multiline input?
87
88 pre
89 Any leading whitespace.
90
91 esc
92 The escape character(s) in pre or the empty string if there isn't one.
93 Note that '!!' and '??' are possible values for esc. Otherwise it will
94 always be a single character.
95
96 ifun
97 The 'function part', which is basically the maximal initial sequence
98 of valid python identifiers and the '.' character. This is what is
99 checked for alias and magic transformations, used for auto-calling,
100 etc. In contrast to Python identifiers, it may start with "%" and contain
101 "*".
102
103 the_rest
104 Everything else on the line.
105 """
106 def __init__(self, line, continue_prompt=False):
107 self.line = line
108 self.continue_prompt = continue_prompt
109 self.pre, self.esc, self.ifun, self.the_rest = split_user_input(line)
110
111 self.pre_char = self.pre.strip()
112 if self.pre_char:
113 self.pre_whitespace = '' # No whitespace allowd before esc chars
114 else:
115 self.pre_whitespace = self.pre
116
117 self._oinfo = None
118
119 def ofind(self, ip):
120 """Do a full, attribute-walking lookup of the ifun in the various
121 namespaces for the given IPython InteractiveShell instance.
122
123 Return a dict with keys: found,obj,ospace,ismagic
124
125 Note: can cause state changes because of calling getattr, but should
126 only be run if autocall is on and if the line hasn't matched any
127 other, less dangerous handlers.
128
129 Does cache the results of the call, so can be called multiple times
130 without worrying about *further* damaging state.
131 """
132 if not self._oinfo:
133 # ip.shell._ofind is actually on the Magic class!
134 self._oinfo = ip.shell._ofind(self.ifun)
135 return self._oinfo
136
137 def __str__(self):
138 return "LineInfo [%s|%s|%s|%s]" %(self.pre, self.esc, self.ifun, self.the_rest)
@@ -1,698 +1,698 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tests for the inputsplitter module.
2 """Tests for the inputsplitter module.
3
3
4 Authors
4 Authors
5 -------
5 -------
6 * Fernando Perez
6 * Fernando Perez
7 * Robert Kern
7 * Robert Kern
8 """
8 """
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10 # Copyright (C) 2010 The IPython Development Team
10 # Copyright (C) 2010 The IPython Development Team
11 #
11 #
12 # Distributed under the terms of the BSD License. The full license is in
12 # Distributed under the terms of the BSD License. The full license is in
13 # the file COPYING, distributed as part of this software.
13 # the file COPYING, distributed as part of this software.
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 # Imports
17 # Imports
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # stdlib
19 # stdlib
20 import unittest
20 import unittest
21 import sys
21 import sys
22
22
23 # Third party
23 # Third party
24 import nose.tools as nt
24 import nose.tools as nt
25
25
26 # Our own
26 # Our own
27 from IPython.core import inputsplitter as isp
27 from IPython.core import inputsplitter as isp
28 from IPython.testing import tools as tt
28 from IPython.testing import tools as tt
29
29
30 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
31 # Semi-complete examples (also used as tests)
31 # Semi-complete examples (also used as tests)
32 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
33
33
34 # Note: at the bottom, there's a slightly more complete version of this that
34 # Note: at the bottom, there's a slightly more complete version of this that
35 # can be useful during development of code here.
35 # can be useful during development of code here.
36
36
37 def mini_interactive_loop(input_func):
37 def mini_interactive_loop(input_func):
38 """Minimal example of the logic of an interactive interpreter loop.
38 """Minimal example of the logic of an interactive interpreter loop.
39
39
40 This serves as an example, and it is used by the test system with a fake
40 This serves as an example, and it is used by the test system with a fake
41 raw_input that simulates interactive input."""
41 raw_input that simulates interactive input."""
42
42
43 from IPython.core.inputsplitter import InputSplitter
43 from IPython.core.inputsplitter import InputSplitter
44
44
45 isp = InputSplitter()
45 isp = InputSplitter()
46 # In practice, this input loop would be wrapped in an outside loop to read
46 # In practice, this input loop would be wrapped in an outside loop to read
47 # input indefinitely, until some exit/quit command was issued. Here we
47 # input indefinitely, until some exit/quit command was issued. Here we
48 # only illustrate the basic inner loop.
48 # only illustrate the basic inner loop.
49 while isp.push_accepts_more():
49 while isp.push_accepts_more():
50 indent = ' '*isp.indent_spaces
50 indent = ' '*isp.indent_spaces
51 prompt = '>>> ' + indent
51 prompt = '>>> ' + indent
52 line = indent + input_func(prompt)
52 line = indent + input_func(prompt)
53 isp.push(line)
53 isp.push(line)
54
54
55 # Here we just return input so we can use it in a test suite, but a real
55 # Here we just return input so we can use it in a test suite, but a real
56 # interpreter would instead send it for execution somewhere.
56 # interpreter would instead send it for execution somewhere.
57 src = isp.source_reset()
57 src = isp.source_reset()
58 #print 'Input source was:\n', src # dbg
58 #print 'Input source was:\n', src # dbg
59 return src
59 return src
60
60
61 #-----------------------------------------------------------------------------
61 #-----------------------------------------------------------------------------
62 # Test utilities, just for local use
62 # Test utilities, just for local use
63 #-----------------------------------------------------------------------------
63 #-----------------------------------------------------------------------------
64
64
65 def assemble(block):
65 def assemble(block):
66 """Assemble a block into multi-line sub-blocks."""
66 """Assemble a block into multi-line sub-blocks."""
67 return ['\n'.join(sub_block)+'\n' for sub_block in block]
67 return ['\n'.join(sub_block)+'\n' for sub_block in block]
68
68
69
69
70 def pseudo_input(lines):
70 def pseudo_input(lines):
71 """Return a function that acts like raw_input but feeds the input list."""
71 """Return a function that acts like raw_input but feeds the input list."""
72 ilines = iter(lines)
72 ilines = iter(lines)
73 def raw_in(prompt):
73 def raw_in(prompt):
74 try:
74 try:
75 return next(ilines)
75 return next(ilines)
76 except StopIteration:
76 except StopIteration:
77 return ''
77 return ''
78 return raw_in
78 return raw_in
79
79
80 #-----------------------------------------------------------------------------
80 #-----------------------------------------------------------------------------
81 # Tests
81 # Tests
82 #-----------------------------------------------------------------------------
82 #-----------------------------------------------------------------------------
83 def test_spaces():
83 def test_spaces():
84 tests = [('', 0),
84 tests = [('', 0),
85 (' ', 1),
85 (' ', 1),
86 ('\n', 0),
86 ('\n', 0),
87 (' \n', 1),
87 (' \n', 1),
88 ('x', 0),
88 ('x', 0),
89 (' x', 1),
89 (' x', 1),
90 (' x',2),
90 (' x',2),
91 (' x',4),
91 (' x',4),
92 # Note: tabs are counted as a single whitespace!
92 # Note: tabs are counted as a single whitespace!
93 ('\tx', 1),
93 ('\tx', 1),
94 ('\t x', 2),
94 ('\t x', 2),
95 ]
95 ]
96 tt.check_pairs(isp.num_ini_spaces, tests)
96 tt.check_pairs(isp.num_ini_spaces, tests)
97
97
98
98
99 def test_remove_comments():
99 def test_remove_comments():
100 tests = [('text', 'text'),
100 tests = [('text', 'text'),
101 ('text # comment', 'text '),
101 ('text # comment', 'text '),
102 ('text # comment\n', 'text \n'),
102 ('text # comment\n', 'text \n'),
103 ('text # comment \n', 'text \n'),
103 ('text # comment \n', 'text \n'),
104 ('line # c \nline\n','line \nline\n'),
104 ('line # c \nline\n','line \nline\n'),
105 ('line # c \nline#c2 \nline\nline #c\n\n',
105 ('line # c \nline#c2 \nline\nline #c\n\n',
106 'line \nline\nline\nline \n\n'),
106 'line \nline\nline\nline \n\n'),
107 ]
107 ]
108 tt.check_pairs(isp.remove_comments, tests)
108 tt.check_pairs(isp.remove_comments, tests)
109
109
110 def test_has_comment():
110 def test_has_comment():
111 tests = [('text', False),
111 tests = [('text', False),
112 ('text #comment', True),
112 ('text #comment', True),
113 ('text #comment\n', True),
113 ('text #comment\n', True),
114 ('#comment', True),
114 ('#comment', True),
115 ('#comment\n', True),
115 ('#comment\n', True),
116 ('a = "#string"', False),
116 ('a = "#string"', False),
117 ('a = "#string" # comment', True),
117 ('a = "#string" # comment', True),
118 ('a #comment not "string"', True),
118 ('a #comment not "string"', True),
119 ]
119 ]
120 tt.check_pairs(isp.has_comment, tests)
120 tt.check_pairs(isp.has_comment, tests)
121
121
122
122
123 def test_get_input_encoding():
123 def test_get_input_encoding():
124 encoding = isp.get_input_encoding()
124 encoding = isp.get_input_encoding()
125 nt.assert_true(isinstance(encoding, basestring))
125 nt.assert_true(isinstance(encoding, basestring))
126 # simple-minded check that at least encoding a simple string works with the
126 # simple-minded check that at least encoding a simple string works with the
127 # encoding we got.
127 # encoding we got.
128 nt.assert_equal(u'test'.encode(encoding), b'test')
128 nt.assert_equal(u'test'.encode(encoding), b'test')
129
129
130
130
131 class NoInputEncodingTestCase(unittest.TestCase):
131 class NoInputEncodingTestCase(unittest.TestCase):
132 def setUp(self):
132 def setUp(self):
133 self.old_stdin = sys.stdin
133 self.old_stdin = sys.stdin
134 class X: pass
134 class X: pass
135 fake_stdin = X()
135 fake_stdin = X()
136 sys.stdin = fake_stdin
136 sys.stdin = fake_stdin
137
137
138 def test(self):
138 def test(self):
139 # Verify that if sys.stdin has no 'encoding' attribute we do the right
139 # Verify that if sys.stdin has no 'encoding' attribute we do the right
140 # thing
140 # thing
141 enc = isp.get_input_encoding()
141 enc = isp.get_input_encoding()
142 self.assertEqual(enc, 'ascii')
142 self.assertEqual(enc, 'ascii')
143
143
144 def tearDown(self):
144 def tearDown(self):
145 sys.stdin = self.old_stdin
145 sys.stdin = self.old_stdin
146
146
147
147
148 class InputSplitterTestCase(unittest.TestCase):
148 class InputSplitterTestCase(unittest.TestCase):
149 def setUp(self):
149 def setUp(self):
150 self.isp = isp.InputSplitter()
150 self.isp = isp.InputSplitter()
151
151
152 def test_reset(self):
152 def test_reset(self):
153 isp = self.isp
153 isp = self.isp
154 isp.push('x=1')
154 isp.push('x=1')
155 isp.reset()
155 isp.reset()
156 self.assertEqual(isp._buffer, [])
156 self.assertEqual(isp._buffer, [])
157 self.assertEqual(isp.indent_spaces, 0)
157 self.assertEqual(isp.indent_spaces, 0)
158 self.assertEqual(isp.source, '')
158 self.assertEqual(isp.source, '')
159 self.assertEqual(isp.code, None)
159 self.assertEqual(isp.code, None)
160 self.assertEqual(isp._is_complete, False)
160 self.assertEqual(isp._is_complete, False)
161
161
162 def test_source(self):
162 def test_source(self):
163 self.isp._store('1')
163 self.isp._store('1')
164 self.isp._store('2')
164 self.isp._store('2')
165 self.assertEqual(self.isp.source, '1\n2\n')
165 self.assertEqual(self.isp.source, '1\n2\n')
166 self.assertTrue(len(self.isp._buffer)>0)
166 self.assertTrue(len(self.isp._buffer)>0)
167 self.assertEqual(self.isp.source_reset(), '1\n2\n')
167 self.assertEqual(self.isp.source_reset(), '1\n2\n')
168 self.assertEqual(self.isp._buffer, [])
168 self.assertEqual(self.isp._buffer, [])
169 self.assertEqual(self.isp.source, '')
169 self.assertEqual(self.isp.source, '')
170
170
171 def test_indent(self):
171 def test_indent(self):
172 isp = self.isp # shorthand
172 isp = self.isp # shorthand
173 isp.push('x=1')
173 isp.push('x=1')
174 self.assertEqual(isp.indent_spaces, 0)
174 self.assertEqual(isp.indent_spaces, 0)
175 isp.push('if 1:\n x=1')
175 isp.push('if 1:\n x=1')
176 self.assertEqual(isp.indent_spaces, 4)
176 self.assertEqual(isp.indent_spaces, 4)
177 isp.push('y=2\n')
177 isp.push('y=2\n')
178 self.assertEqual(isp.indent_spaces, 0)
178 self.assertEqual(isp.indent_spaces, 0)
179
179
180 def test_indent2(self):
180 def test_indent2(self):
181 # In cell mode, inputs must be fed in whole blocks, so skip this test
181 # In cell mode, inputs must be fed in whole blocks, so skip this test
182 if self.isp.input_mode == 'cell': return
182 if self.isp.input_mode == 'cell': return
183
183
184 isp = self.isp
184 isp = self.isp
185 isp.push('if 1:')
185 isp.push('if 1:')
186 self.assertEqual(isp.indent_spaces, 4)
186 self.assertEqual(isp.indent_spaces, 4)
187 isp.push(' x=1')
187 isp.push(' x=1')
188 self.assertEqual(isp.indent_spaces, 4)
188 self.assertEqual(isp.indent_spaces, 4)
189 # Blank lines shouldn't change the indent level
189 # Blank lines shouldn't change the indent level
190 isp.push(' '*2)
190 isp.push(' '*2)
191 self.assertEqual(isp.indent_spaces, 4)
191 self.assertEqual(isp.indent_spaces, 4)
192
192
193 def test_indent3(self):
193 def test_indent3(self):
194 # In cell mode, inputs must be fed in whole blocks, so skip this test
194 # In cell mode, inputs must be fed in whole blocks, so skip this test
195 if self.isp.input_mode == 'cell': return
195 if self.isp.input_mode == 'cell': return
196
196
197 isp = self.isp
197 isp = self.isp
198 # When a multiline statement contains parens or multiline strings, we
198 # When a multiline statement contains parens or multiline strings, we
199 # shouldn't get confused.
199 # shouldn't get confused.
200 isp.push("if 1:")
200 isp.push("if 1:")
201 isp.push(" x = (1+\n 2)")
201 isp.push(" x = (1+\n 2)")
202 self.assertEqual(isp.indent_spaces, 4)
202 self.assertEqual(isp.indent_spaces, 4)
203
203
204 def test_indent4(self):
204 def test_indent4(self):
205 # In cell mode, inputs must be fed in whole blocks, so skip this test
205 # In cell mode, inputs must be fed in whole blocks, so skip this test
206 if self.isp.input_mode == 'cell': return
206 if self.isp.input_mode == 'cell': return
207
207
208 isp = self.isp
208 isp = self.isp
209 # whitespace after ':' should not screw up indent level
209 # whitespace after ':' should not screw up indent level
210 isp.push('if 1: \n x=1')
210 isp.push('if 1: \n x=1')
211 self.assertEqual(isp.indent_spaces, 4)
211 self.assertEqual(isp.indent_spaces, 4)
212 isp.push('y=2\n')
212 isp.push('y=2\n')
213 self.assertEqual(isp.indent_spaces, 0)
213 self.assertEqual(isp.indent_spaces, 0)
214 isp.push('if 1:\t\n x=1')
214 isp.push('if 1:\t\n x=1')
215 self.assertEqual(isp.indent_spaces, 4)
215 self.assertEqual(isp.indent_spaces, 4)
216 isp.push('y=2\n')
216 isp.push('y=2\n')
217 self.assertEqual(isp.indent_spaces, 0)
217 self.assertEqual(isp.indent_spaces, 0)
218
218
219 def test_dedent_pass(self):
219 def test_dedent_pass(self):
220 isp = self.isp # shorthand
220 isp = self.isp # shorthand
221 # should NOT cause dedent
221 # should NOT cause dedent
222 isp.push('if 1:\n passes = 5')
222 isp.push('if 1:\n passes = 5')
223 self.assertEqual(isp.indent_spaces, 4)
223 self.assertEqual(isp.indent_spaces, 4)
224 isp.push('if 1:\n pass')
224 isp.push('if 1:\n pass')
225 self.assertEqual(isp.indent_spaces, 0)
225 self.assertEqual(isp.indent_spaces, 0)
226 isp.push('if 1:\n pass ')
226 isp.push('if 1:\n pass ')
227 self.assertEqual(isp.indent_spaces, 0)
227 self.assertEqual(isp.indent_spaces, 0)
228
228
229 def test_dedent_raise(self):
229 def test_dedent_raise(self):
230 isp = self.isp # shorthand
230 isp = self.isp # shorthand
231 # should NOT cause dedent
231 # should NOT cause dedent
232 isp.push('if 1:\n raised = 4')
232 isp.push('if 1:\n raised = 4')
233 self.assertEqual(isp.indent_spaces, 4)
233 self.assertEqual(isp.indent_spaces, 4)
234 isp.push('if 1:\n raise TypeError()')
234 isp.push('if 1:\n raise TypeError()')
235 self.assertEqual(isp.indent_spaces, 0)
235 self.assertEqual(isp.indent_spaces, 0)
236 isp.push('if 1:\n raise')
236 isp.push('if 1:\n raise')
237 self.assertEqual(isp.indent_spaces, 0)
237 self.assertEqual(isp.indent_spaces, 0)
238 isp.push('if 1:\n raise ')
238 isp.push('if 1:\n raise ')
239 self.assertEqual(isp.indent_spaces, 0)
239 self.assertEqual(isp.indent_spaces, 0)
240
240
241 def test_dedent_return(self):
241 def test_dedent_return(self):
242 isp = self.isp # shorthand
242 isp = self.isp # shorthand
243 # should NOT cause dedent
243 # should NOT cause dedent
244 isp.push('if 1:\n returning = 4')
244 isp.push('if 1:\n returning = 4')
245 self.assertEqual(isp.indent_spaces, 4)
245 self.assertEqual(isp.indent_spaces, 4)
246 isp.push('if 1:\n return 5 + 493')
246 isp.push('if 1:\n return 5 + 493')
247 self.assertEqual(isp.indent_spaces, 0)
247 self.assertEqual(isp.indent_spaces, 0)
248 isp.push('if 1:\n return')
248 isp.push('if 1:\n return')
249 self.assertEqual(isp.indent_spaces, 0)
249 self.assertEqual(isp.indent_spaces, 0)
250 isp.push('if 1:\n return ')
250 isp.push('if 1:\n return ')
251 self.assertEqual(isp.indent_spaces, 0)
251 self.assertEqual(isp.indent_spaces, 0)
252 isp.push('if 1:\n return(0)')
252 isp.push('if 1:\n return(0)')
253 self.assertEqual(isp.indent_spaces, 0)
253 self.assertEqual(isp.indent_spaces, 0)
254
254
255 def test_push(self):
255 def test_push(self):
256 isp = self.isp
256 isp = self.isp
257 self.assertTrue(isp.push('x=1'))
257 self.assertTrue(isp.push('x=1'))
258
258
259 def test_push2(self):
259 def test_push2(self):
260 isp = self.isp
260 isp = self.isp
261 self.assertFalse(isp.push('if 1:'))
261 self.assertFalse(isp.push('if 1:'))
262 for line in [' x=1', '# a comment', ' y=2']:
262 for line in [' x=1', '# a comment', ' y=2']:
263 self.assertTrue(isp.push(line))
263 self.assertTrue(isp.push(line))
264
264
265 def test_push3(self):
265 def test_push3(self):
266 isp = self.isp
266 isp = self.isp
267 isp.push('if True:')
267 isp.push('if True:')
268 isp.push(' a = 1')
268 isp.push(' a = 1')
269 self.assertFalse(isp.push('b = [1,'))
269 self.assertFalse(isp.push('b = [1,'))
270
270
271 def test_replace_mode(self):
271 def test_replace_mode(self):
272 isp = self.isp
272 isp = self.isp
273 isp.input_mode = 'cell'
273 isp.input_mode = 'cell'
274 isp.push('x=1')
274 isp.push('x=1')
275 self.assertEqual(isp.source, 'x=1\n')
275 self.assertEqual(isp.source, 'x=1\n')
276 isp.push('x=2')
276 isp.push('x=2')
277 self.assertEqual(isp.source, 'x=2\n')
277 self.assertEqual(isp.source, 'x=2\n')
278
278
279 def test_push_accepts_more(self):
279 def test_push_accepts_more(self):
280 isp = self.isp
280 isp = self.isp
281 isp.push('x=1')
281 isp.push('x=1')
282 self.assertFalse(isp.push_accepts_more())
282 self.assertFalse(isp.push_accepts_more())
283
283
284 def test_push_accepts_more2(self):
284 def test_push_accepts_more2(self):
285 # In cell mode, inputs must be fed in whole blocks, so skip this test
285 # In cell mode, inputs must be fed in whole blocks, so skip this test
286 if self.isp.input_mode == 'cell': return
286 if self.isp.input_mode == 'cell': return
287
287
288 isp = self.isp
288 isp = self.isp
289 isp.push('if 1:')
289 isp.push('if 1:')
290 self.assertTrue(isp.push_accepts_more())
290 self.assertTrue(isp.push_accepts_more())
291 isp.push(' x=1')
291 isp.push(' x=1')
292 self.assertTrue(isp.push_accepts_more())
292 self.assertTrue(isp.push_accepts_more())
293 isp.push('')
293 isp.push('')
294 self.assertFalse(isp.push_accepts_more())
294 self.assertFalse(isp.push_accepts_more())
295
295
296 def test_push_accepts_more3(self):
296 def test_push_accepts_more3(self):
297 isp = self.isp
297 isp = self.isp
298 isp.push("x = (2+\n3)")
298 isp.push("x = (2+\n3)")
299 self.assertFalse(isp.push_accepts_more())
299 self.assertFalse(isp.push_accepts_more())
300
300
301 def test_push_accepts_more4(self):
301 def test_push_accepts_more4(self):
302 # In cell mode, inputs must be fed in whole blocks, so skip this test
302 # In cell mode, inputs must be fed in whole blocks, so skip this test
303 if self.isp.input_mode == 'cell': return
303 if self.isp.input_mode == 'cell': return
304
304
305 isp = self.isp
305 isp = self.isp
306 # When a multiline statement contains parens or multiline strings, we
306 # When a multiline statement contains parens or multiline strings, we
307 # shouldn't get confused.
307 # shouldn't get confused.
308 # FIXME: we should be able to better handle de-dents in statements like
308 # FIXME: we should be able to better handle de-dents in statements like
309 # multiline strings and multiline expressions (continued with \ or
309 # multiline strings and multiline expressions (continued with \ or
310 # parens). Right now we aren't handling the indentation tracking quite
310 # parens). Right now we aren't handling the indentation tracking quite
311 # correctly with this, though in practice it may not be too much of a
311 # correctly with this, though in practice it may not be too much of a
312 # problem. We'll need to see.
312 # problem. We'll need to see.
313 isp.push("if 1:")
313 isp.push("if 1:")
314 isp.push(" x = (2+")
314 isp.push(" x = (2+")
315 isp.push(" 3)")
315 isp.push(" 3)")
316 self.assertTrue(isp.push_accepts_more())
316 self.assertTrue(isp.push_accepts_more())
317 isp.push(" y = 3")
317 isp.push(" y = 3")
318 self.assertTrue(isp.push_accepts_more())
318 self.assertTrue(isp.push_accepts_more())
319 isp.push('')
319 isp.push('')
320 self.assertFalse(isp.push_accepts_more())
320 self.assertFalse(isp.push_accepts_more())
321
321
322 def test_push_accepts_more5(self):
322 def test_push_accepts_more5(self):
323 # In cell mode, inputs must be fed in whole blocks, so skip this test
323 # In cell mode, inputs must be fed in whole blocks, so skip this test
324 if self.isp.input_mode == 'cell': return
324 if self.isp.input_mode == 'cell': return
325
325
326 isp = self.isp
326 isp = self.isp
327 isp.push('try:')
327 isp.push('try:')
328 isp.push(' a = 5')
328 isp.push(' a = 5')
329 isp.push('except:')
329 isp.push('except:')
330 isp.push(' raise')
330 isp.push(' raise')
331 self.assertTrue(isp.push_accepts_more())
331 self.assertTrue(isp.push_accepts_more())
332
332
333 def test_continuation(self):
333 def test_continuation(self):
334 isp = self.isp
334 isp = self.isp
335 isp.push("import os, \\")
335 isp.push("import os, \\")
336 self.assertTrue(isp.push_accepts_more())
336 self.assertTrue(isp.push_accepts_more())
337 isp.push("sys")
337 isp.push("sys")
338 self.assertFalse(isp.push_accepts_more())
338 self.assertFalse(isp.push_accepts_more())
339
339
340 def test_syntax_error(self):
340 def test_syntax_error(self):
341 isp = self.isp
341 isp = self.isp
342 # Syntax errors immediately produce a 'ready' block, so the invalid
342 # Syntax errors immediately produce a 'ready' block, so the invalid
343 # Python can be sent to the kernel for evaluation with possible ipython
343 # Python can be sent to the kernel for evaluation with possible ipython
344 # special-syntax conversion.
344 # special-syntax conversion.
345 isp.push('run foo')
345 isp.push('run foo')
346 self.assertFalse(isp.push_accepts_more())
346 self.assertFalse(isp.push_accepts_more())
347
347
348 def test_unicode(self):
348 def test_unicode(self):
349 self.isp.push(u"PΓ©rez")
349 self.isp.push(u"PΓ©rez")
350 self.isp.push(u'\xc3\xa9')
350 self.isp.push(u'\xc3\xa9')
351 self.isp.push(u"u'\xc3\xa9'")
351 self.isp.push(u"u'\xc3\xa9'")
352
352
353 class InteractiveLoopTestCase(unittest.TestCase):
353 class InteractiveLoopTestCase(unittest.TestCase):
354 """Tests for an interactive loop like a python shell.
354 """Tests for an interactive loop like a python shell.
355 """
355 """
356 def check_ns(self, lines, ns):
356 def check_ns(self, lines, ns):
357 """Validate that the given input lines produce the resulting namespace.
357 """Validate that the given input lines produce the resulting namespace.
358
358
359 Note: the input lines are given exactly as they would be typed in an
359 Note: the input lines are given exactly as they would be typed in an
360 auto-indenting environment, as mini_interactive_loop above already does
360 auto-indenting environment, as mini_interactive_loop above already does
361 auto-indenting and prepends spaces to the input.
361 auto-indenting and prepends spaces to the input.
362 """
362 """
363 src = mini_interactive_loop(pseudo_input(lines))
363 src = mini_interactive_loop(pseudo_input(lines))
364 test_ns = {}
364 test_ns = {}
365 exec src in test_ns
365 exec src in test_ns
366 # We can't check that the provided ns is identical to the test_ns,
366 # We can't check that the provided ns is identical to the test_ns,
367 # because Python fills test_ns with extra keys (copyright, etc). But
367 # because Python fills test_ns with extra keys (copyright, etc). But
368 # we can check that the given dict is *contained* in test_ns
368 # we can check that the given dict is *contained* in test_ns
369 for k,v in ns.iteritems():
369 for k,v in ns.iteritems():
370 self.assertEqual(test_ns[k], v)
370 self.assertEqual(test_ns[k], v)
371
371
372 def test_simple(self):
372 def test_simple(self):
373 self.check_ns(['x=1'], dict(x=1))
373 self.check_ns(['x=1'], dict(x=1))
374
374
375 def test_simple2(self):
375 def test_simple2(self):
376 self.check_ns(['if 1:', 'x=2'], dict(x=2))
376 self.check_ns(['if 1:', 'x=2'], dict(x=2))
377
377
378 def test_xy(self):
378 def test_xy(self):
379 self.check_ns(['x=1; y=2'], dict(x=1, y=2))
379 self.check_ns(['x=1; y=2'], dict(x=1, y=2))
380
380
381 def test_abc(self):
381 def test_abc(self):
382 self.check_ns(['if 1:','a=1','b=2','c=3'], dict(a=1, b=2, c=3))
382 self.check_ns(['if 1:','a=1','b=2','c=3'], dict(a=1, b=2, c=3))
383
383
384 def test_multi(self):
384 def test_multi(self):
385 self.check_ns(['x =(1+','1+','2)'], dict(x=4))
385 self.check_ns(['x =(1+','1+','2)'], dict(x=4))
386
386
387
387
388 def test_LineInfo():
388 def test_LineInfo():
389 """Simple test for LineInfo construction and str()"""
389 """Simple test for LineInfo construction and str()"""
390 linfo = isp.LineInfo(' %cd /home')
390 linfo = isp.LineInfo(' %cd /home')
391 nt.assert_equals(str(linfo), 'LineInfo [ |%|cd|/home]')
391 nt.assert_equals(str(linfo), 'LineInfo [ |%|cd|/home]')
392
392
393
393
394 def test_split_user_input():
394 def test_split_user_input():
395 """Unicode test - split_user_input already has good doctests"""
395 """Unicode test - split_user_input already has good doctests"""
396 line = u"PΓ©rez Fernando"
396 line = u"PΓ©rez Fernando"
397 parts = isp.split_user_input(line)
398 parts_expected = (u'', u'', u'', line)
397 parts_expected = (u'', u'', u'', line)
399 nt.assert_equal(parts, parts_expected)
398 tt.check_pairs(isp.split_user_input, [(line, parts_expected),])
400
399
401
400
402 # Transformer tests
401 # Transformer tests
403 def transform_checker(tests, func):
402 def transform_checker(tests, func):
404 """Utility to loop over test inputs"""
403 """Utility to loop over test inputs"""
405 for inp, tr in tests:
404 for inp, tr in tests:
406 nt.assert_equals(func(inp), tr)
405 nt.assert_equals(func(inp), tr)
407
406
408 # Data for all the syntax tests in the form of lists of pairs of
407 # Data for all the syntax tests in the form of lists of pairs of
409 # raw/transformed input. We store it here as a global dict so that we can use
408 # raw/transformed input. We store it here as a global dict so that we can use
410 # it both within single-function tests and also to validate the behavior of the
409 # it both within single-function tests and also to validate the behavior of the
411 # larger objects
410 # larger objects
412
411
413 syntax = \
412 syntax = \
414 dict(assign_system =
413 dict(assign_system =
415 [('a =! ls', 'a = get_ipython().getoutput(u"ls")'),
414 [('a =! ls', 'a = get_ipython().getoutput(u"ls")'),
416 ('b = !ls', 'b = get_ipython().getoutput(u"ls")'),
415 ('b = !ls', 'b = get_ipython().getoutput(u"ls")'),
417 ('x=1', 'x=1'), # normal input is unmodified
416 ('x=1', 'x=1'), # normal input is unmodified
418 (' ',' '), # blank lines are kept intact
417 (' ',' '), # blank lines are kept intact
419 ],
418 ],
420
419
421 assign_magic =
420 assign_magic =
422 [('a =% who', 'a = get_ipython().magic(u"who")'),
421 [('a =% who', 'a = get_ipython().magic(u"who")'),
423 ('b = %who', 'b = get_ipython().magic(u"who")'),
422 ('b = %who', 'b = get_ipython().magic(u"who")'),
424 ('x=1', 'x=1'), # normal input is unmodified
423 ('x=1', 'x=1'), # normal input is unmodified
425 (' ',' '), # blank lines are kept intact
424 (' ',' '), # blank lines are kept intact
426 ],
425 ],
427
426
428 classic_prompt =
427 classic_prompt =
429 [('>>> x=1', 'x=1'),
428 [('>>> x=1', 'x=1'),
430 ('x=1', 'x=1'), # normal input is unmodified
429 ('x=1', 'x=1'), # normal input is unmodified
431 (' ', ' '), # blank lines are kept intact
430 (' ', ' '), # blank lines are kept intact
432 ('... ', ''), # continuation prompts
431 ('... ', ''), # continuation prompts
433 ],
432 ],
434
433
435 ipy_prompt =
434 ipy_prompt =
436 [('In [1]: x=1', 'x=1'),
435 [('In [1]: x=1', 'x=1'),
437 ('x=1', 'x=1'), # normal input is unmodified
436 ('x=1', 'x=1'), # normal input is unmodified
438 (' ',' '), # blank lines are kept intact
437 (' ',' '), # blank lines are kept intact
439 (' ....: ', ''), # continuation prompts
438 (' ....: ', ''), # continuation prompts
440 ],
439 ],
441
440
442 # Tests for the escape transformer to leave normal code alone
441 # Tests for the escape transformer to leave normal code alone
443 escaped_noesc =
442 escaped_noesc =
444 [ (' ', ' '),
443 [ (' ', ' '),
445 ('x=1', 'x=1'),
444 ('x=1', 'x=1'),
446 ],
445 ],
447
446
448 # System calls
447 # System calls
449 escaped_shell =
448 escaped_shell =
450 [ ('!ls', 'get_ipython().system(u"ls")'),
449 [ ('!ls', 'get_ipython().system(u"ls")'),
451 # Double-escape shell, this means to capture the output of the
450 # Double-escape shell, this means to capture the output of the
452 # subprocess and return it
451 # subprocess and return it
453 ('!!ls', 'get_ipython().getoutput(u"ls")'),
452 ('!!ls', 'get_ipython().getoutput(u"ls")'),
454 ],
453 ],
455
454
456 # Help/object info
455 # Help/object info
457 escaped_help =
456 escaped_help =
458 [ ('?', 'get_ipython().show_usage()'),
457 [ ('?', 'get_ipython().show_usage()'),
459 ('?x1', 'get_ipython().magic(u"pinfo x1")'),
458 ('?x1', 'get_ipython().magic(u"pinfo x1")'),
460 ('??x2', 'get_ipython().magic(u"pinfo2 x2")'),
459 ('??x2', 'get_ipython().magic(u"pinfo2 x2")'),
461 ('?a.*s', 'get_ipython().magic(u"psearch a.*s")'),
460 ('?a.*s', 'get_ipython().magic(u"psearch a.*s")'),
462 ('?%hist', 'get_ipython().magic(u"pinfo %hist")'),
461 ('?%hist', 'get_ipython().magic(u"pinfo %hist")'),
463 ('?abc = qwe', 'get_ipython().magic(u"pinfo abc")'),
462 ('?abc = qwe', 'get_ipython().magic(u"pinfo abc")'),
464 ],
463 ],
465
464
466 end_help =
465 end_help =
467 [ ('x3?', 'get_ipython().magic(u"pinfo x3")'),
466 [ ('x3?', 'get_ipython().magic(u"pinfo x3")'),
468 ('x4??', 'get_ipython().magic(u"pinfo2 x4")'),
467 ('x4??', 'get_ipython().magic(u"pinfo2 x4")'),
469 ('%hist?', 'get_ipython().magic(u"pinfo %hist")'),
468 ('%hist?', 'get_ipython().magic(u"pinfo %hist")'),
470 ('f*?', 'get_ipython().magic(u"psearch f*")'),
469 ('f*?', 'get_ipython().magic(u"psearch f*")'),
471 ('ax.*aspe*?', 'get_ipython().magic(u"psearch ax.*aspe*")'),
470 ('ax.*aspe*?', 'get_ipython().magic(u"psearch ax.*aspe*")'),
472 ('a = abc?', 'get_ipython().magic(u"pinfo abc", next_input=u"a = abc")'),
471 ('a = abc?', 'get_ipython().magic(u"pinfo abc", next_input=u"a = abc")'),
473 ('a = abc.qe??', 'get_ipython().magic(u"pinfo2 abc.qe", next_input=u"a = abc.qe")'),
472 ('a = abc.qe??', 'get_ipython().magic(u"pinfo2 abc.qe", next_input=u"a = abc.qe")'),
474 ('a = *.items?', 'get_ipython().magic(u"psearch *.items", next_input=u"a = *.items")'),
473 ('a = *.items?', 'get_ipython().magic(u"psearch *.items", next_input=u"a = *.items")'),
475 ('plot(a?', 'get_ipython().magic(u"pinfo a", next_input=u"plot(a")'),
474 ('plot(a?', 'get_ipython().magic(u"pinfo a", next_input=u"plot(a")'),
476 ('a*2 #comment?', 'a*2 #comment?'),
475 ('a*2 #comment?', 'a*2 #comment?'),
477 ],
476 ],
478
477
479 # Explicit magic calls
478 # Explicit magic calls
480 escaped_magic =
479 escaped_magic =
481 [ ('%cd', 'get_ipython().magic(u"cd")'),
480 [ ('%cd', 'get_ipython().magic(u"cd")'),
482 ('%cd /home', 'get_ipython().magic(u"cd /home")'),
481 ('%cd /home', 'get_ipython().magic(u"cd /home")'),
483 (' %magic', ' get_ipython().magic(u"magic")'),
482 (' %magic', ' get_ipython().magic(u"magic")'),
484 ],
483 ],
485
484
486 # Quoting with separate arguments
485 # Quoting with separate arguments
487 escaped_quote =
486 escaped_quote =
488 [ (',f', 'f("")'),
487 [ (',f', 'f("")'),
489 (',f x', 'f("x")'),
488 (',f x', 'f("x")'),
490 (' ,f y', ' f("y")'),
489 (' ,f y', ' f("y")'),
491 (',f a b', 'f("a", "b")'),
490 (',f a b', 'f("a", "b")'),
492 ],
491 ],
493
492
494 # Quoting with single argument
493 # Quoting with single argument
495 escaped_quote2 =
494 escaped_quote2 =
496 [ (';f', 'f("")'),
495 [ (';f', 'f("")'),
497 (';f x', 'f("x")'),
496 (';f x', 'f("x")'),
498 (' ;f y', ' f("y")'),
497 (' ;f y', ' f("y")'),
499 (';f a b', 'f("a b")'),
498 (';f a b', 'f("a b")'),
500 ],
499 ],
501
500
502 # Simply apply parens
501 # Simply apply parens
503 escaped_paren =
502 escaped_paren =
504 [ ('/f', 'f()'),
503 [ ('/f', 'f()'),
505 ('/f x', 'f(x)'),
504 ('/f x', 'f(x)'),
506 (' /f y', ' f(y)'),
505 (' /f y', ' f(y)'),
507 ('/f a b', 'f(a, b)'),
506 ('/f a b', 'f(a, b)'),
508 ],
507 ],
509
508
510 # Check that we transform prompts before other transforms
509 # Check that we transform prompts before other transforms
511 mixed =
510 mixed =
512 [ ('In [1]: %lsmagic', 'get_ipython().magic(u"lsmagic")'),
511 [ ('In [1]: %lsmagic', 'get_ipython().magic(u"lsmagic")'),
513 ('>>> %lsmagic', 'get_ipython().magic(u"lsmagic")'),
512 ('>>> %lsmagic', 'get_ipython().magic(u"lsmagic")'),
514 ('In [2]: !ls', 'get_ipython().system(u"ls")'),
513 ('In [2]: !ls', 'get_ipython().system(u"ls")'),
515 ('In [3]: abs?', 'get_ipython().magic(u"pinfo abs")'),
514 ('In [3]: abs?', 'get_ipython().magic(u"pinfo abs")'),
516 ('In [4]: b = %who', 'b = get_ipython().magic(u"who")'),
515 ('In [4]: b = %who', 'b = get_ipython().magic(u"who")'),
517 ],
516 ],
518 )
517 )
519
518
520 # multiline syntax examples. Each of these should be a list of lists, with
519 # multiline syntax examples. Each of these should be a list of lists, with
521 # each entry itself having pairs of raw/transformed input. The union (with
520 # each entry itself having pairs of raw/transformed input. The union (with
522 # '\n'.join() of the transformed inputs is what the splitter should produce
521 # '\n'.join() of the transformed inputs is what the splitter should produce
523 # when fed the raw lines one at a time via push.
522 # when fed the raw lines one at a time via push.
524 syntax_ml = \
523 syntax_ml = \
525 dict(classic_prompt =
524 dict(classic_prompt =
526 [ [('>>> for i in range(10):','for i in range(10):'),
525 [ [('>>> for i in range(10):','for i in range(10):'),
527 ('... print i',' print i'),
526 ('... print i',' print i'),
528 ('... ', ''),
527 ('... ', ''),
529 ],
528 ],
530 ],
529 ],
531
530
532 ipy_prompt =
531 ipy_prompt =
533 [ [('In [24]: for i in range(10):','for i in range(10):'),
532 [ [('In [24]: for i in range(10):','for i in range(10):'),
534 (' ....: print i',' print i'),
533 (' ....: print i',' print i'),
535 (' ....: ', ''),
534 (' ....: ', ''),
536 ],
535 ],
537 ],
536 ],
538 )
537 )
539
538
540
539
541 def test_assign_system():
540 def test_assign_system():
542 tt.check_pairs(isp.transform_assign_system, syntax['assign_system'])
541 tt.check_pairs(isp.transform_assign_system, syntax['assign_system'])
543
542
544
543
545 def test_assign_magic():
544 def test_assign_magic():
546 tt.check_pairs(isp.transform_assign_magic, syntax['assign_magic'])
545 tt.check_pairs(isp.transform_assign_magic, syntax['assign_magic'])
547
546
548
547
549 def test_classic_prompt():
548 def test_classic_prompt():
550 transform_checker(syntax['classic_prompt'], isp.transform_classic_prompt)
549 transform_checker(syntax['classic_prompt'], isp.transform_classic_prompt)
551 for example in syntax_ml['classic_prompt']:
550 for example in syntax_ml['classic_prompt']:
552 transform_checker(example, isp.transform_classic_prompt)
551 transform_checker(example, isp.transform_classic_prompt)
553
552
554
553
555 def test_ipy_prompt():
554 def test_ipy_prompt():
556 transform_checker(syntax['ipy_prompt'], isp.transform_ipy_prompt)
555 transform_checker(syntax['ipy_prompt'], isp.transform_ipy_prompt)
557 for example in syntax_ml['ipy_prompt']:
556 for example in syntax_ml['ipy_prompt']:
558 transform_checker(example, isp.transform_ipy_prompt)
557 transform_checker(example, isp.transform_ipy_prompt)
559
558
560 def test_end_help():
559 def test_end_help():
561 tt.check_pairs(isp.transform_help_end, syntax['end_help'])
560 tt.check_pairs(isp.transform_help_end, syntax['end_help'])
562
561
563 def test_escaped_noesc():
562 def test_escaped_noesc():
564 tt.check_pairs(isp.transform_escaped, syntax['escaped_noesc'])
563 tt.check_pairs(isp.transform_escaped, syntax['escaped_noesc'])
565
564
566
565
567 def test_escaped_shell():
566 def test_escaped_shell():
568 tt.check_pairs(isp.transform_escaped, syntax['escaped_shell'])
567 tt.check_pairs(isp.transform_escaped, syntax['escaped_shell'])
569
568
570
569
571 def test_escaped_help():
570 def test_escaped_help():
572 tt.check_pairs(isp.transform_escaped, syntax['escaped_help'])
571 tt.check_pairs(isp.transform_escaped, syntax['escaped_help'])
573
572
574
573
575 def test_escaped_magic():
574 def test_escaped_magic():
576 tt.check_pairs(isp.transform_escaped, syntax['escaped_magic'])
575 tt.check_pairs(isp.transform_escaped, syntax['escaped_magic'])
577
576
578
577
579 def test_escaped_quote():
578 def test_escaped_quote():
580 tt.check_pairs(isp.transform_escaped, syntax['escaped_quote'])
579 tt.check_pairs(isp.transform_escaped, syntax['escaped_quote'])
581
580
582
581
583 def test_escaped_quote2():
582 def test_escaped_quote2():
584 tt.check_pairs(isp.transform_escaped, syntax['escaped_quote2'])
583 tt.check_pairs(isp.transform_escaped, syntax['escaped_quote2'])
585
584
586
585
587 def test_escaped_paren():
586 def test_escaped_paren():
588 tt.check_pairs(isp.transform_escaped, syntax['escaped_paren'])
587 tt.check_pairs(isp.transform_escaped, syntax['escaped_paren'])
589
588
590
589
591 class IPythonInputTestCase(InputSplitterTestCase):
590 class IPythonInputTestCase(InputSplitterTestCase):
592 """By just creating a new class whose .isp is a different instance, we
591 """By just creating a new class whose .isp is a different instance, we
593 re-run the same test battery on the new input splitter.
592 re-run the same test battery on the new input splitter.
594
593
595 In addition, this runs the tests over the syntax and syntax_ml dicts that
594 In addition, this runs the tests over the syntax and syntax_ml dicts that
596 were tested by individual functions, as part of the OO interface.
595 were tested by individual functions, as part of the OO interface.
597
596
598 It also makes some checks on the raw buffer storage.
597 It also makes some checks on the raw buffer storage.
599 """
598 """
600
599
601 def setUp(self):
600 def setUp(self):
602 self.isp = isp.IPythonInputSplitter(input_mode='line')
601 self.isp = isp.IPythonInputSplitter(input_mode='line')
603
602
604 def test_syntax(self):
603 def test_syntax(self):
605 """Call all single-line syntax tests from the main object"""
604 """Call all single-line syntax tests from the main object"""
606 isp = self.isp
605 isp = self.isp
607 for example in syntax.itervalues():
606 for example in syntax.itervalues():
608 for raw, out_t in example:
607 for raw, out_t in example:
609 if raw.startswith(' '):
608 if raw.startswith(' '):
610 continue
609 continue
611
610
612 isp.push(raw)
611 isp.push(raw)
613 out, out_raw = isp.source_raw_reset()
612 out, out_raw = isp.source_raw_reset()
614 self.assertEqual(out.rstrip(), out_t)
613 self.assertEqual(out.rstrip(), out_t,
614 tt.pair_fail_msg.format("inputsplitter",raw, out_t, out))
615 self.assertEqual(out_raw.rstrip(), raw.rstrip())
615 self.assertEqual(out_raw.rstrip(), raw.rstrip())
616
616
617 def test_syntax_multiline(self):
617 def test_syntax_multiline(self):
618 isp = self.isp
618 isp = self.isp
619 for example in syntax_ml.itervalues():
619 for example in syntax_ml.itervalues():
620 out_t_parts = []
620 out_t_parts = []
621 raw_parts = []
621 raw_parts = []
622 for line_pairs in example:
622 for line_pairs in example:
623 for lraw, out_t_part in line_pairs:
623 for lraw, out_t_part in line_pairs:
624 isp.push(lraw)
624 isp.push(lraw)
625 out_t_parts.append(out_t_part)
625 out_t_parts.append(out_t_part)
626 raw_parts.append(lraw)
626 raw_parts.append(lraw)
627
627
628 out, out_raw = isp.source_raw_reset()
628 out, out_raw = isp.source_raw_reset()
629 out_t = '\n'.join(out_t_parts).rstrip()
629 out_t = '\n'.join(out_t_parts).rstrip()
630 raw = '\n'.join(raw_parts).rstrip()
630 raw = '\n'.join(raw_parts).rstrip()
631 self.assertEqual(out.rstrip(), out_t)
631 self.assertEqual(out.rstrip(), out_t)
632 self.assertEqual(out_raw.rstrip(), raw)
632 self.assertEqual(out_raw.rstrip(), raw)
633
633
634
634
635 class BlockIPythonInputTestCase(IPythonInputTestCase):
635 class BlockIPythonInputTestCase(IPythonInputTestCase):
636
636
637 # Deactivate tests that don't make sense for the block mode
637 # Deactivate tests that don't make sense for the block mode
638 test_push3 = test_split = lambda s: None
638 test_push3 = test_split = lambda s: None
639
639
640 def setUp(self):
640 def setUp(self):
641 self.isp = isp.IPythonInputSplitter(input_mode='cell')
641 self.isp = isp.IPythonInputSplitter(input_mode='cell')
642
642
643 def test_syntax_multiline(self):
643 def test_syntax_multiline(self):
644 isp = self.isp
644 isp = self.isp
645 for example in syntax_ml.itervalues():
645 for example in syntax_ml.itervalues():
646 raw_parts = []
646 raw_parts = []
647 out_t_parts = []
647 out_t_parts = []
648 for line_pairs in example:
648 for line_pairs in example:
649 for raw, out_t_part in line_pairs:
649 for raw, out_t_part in line_pairs:
650 raw_parts.append(raw)
650 raw_parts.append(raw)
651 out_t_parts.append(out_t_part)
651 out_t_parts.append(out_t_part)
652
652
653 raw = '\n'.join(raw_parts)
653 raw = '\n'.join(raw_parts)
654 out_t = '\n'.join(out_t_parts)
654 out_t = '\n'.join(out_t_parts)
655
655
656 isp.push(raw)
656 isp.push(raw)
657 out, out_raw = isp.source_raw_reset()
657 out, out_raw = isp.source_raw_reset()
658 # Match ignoring trailing whitespace
658 # Match ignoring trailing whitespace
659 self.assertEqual(out.rstrip(), out_t.rstrip())
659 self.assertEqual(out.rstrip(), out_t.rstrip())
660 self.assertEqual(out_raw.rstrip(), raw.rstrip())
660 self.assertEqual(out_raw.rstrip(), raw.rstrip())
661
661
662
662
663 #-----------------------------------------------------------------------------
663 #-----------------------------------------------------------------------------
664 # Main - use as a script, mostly for developer experiments
664 # Main - use as a script, mostly for developer experiments
665 #-----------------------------------------------------------------------------
665 #-----------------------------------------------------------------------------
666
666
667 if __name__ == '__main__':
667 if __name__ == '__main__':
668 # A simple demo for interactive experimentation. This code will not get
668 # A simple demo for interactive experimentation. This code will not get
669 # picked up by any test suite.
669 # picked up by any test suite.
670 from IPython.core.inputsplitter import InputSplitter, IPythonInputSplitter
670 from IPython.core.inputsplitter import InputSplitter, IPythonInputSplitter
671
671
672 # configure here the syntax to use, prompt and whether to autoindent
672 # configure here the syntax to use, prompt and whether to autoindent
673 #isp, start_prompt = InputSplitter(), '>>> '
673 #isp, start_prompt = InputSplitter(), '>>> '
674 isp, start_prompt = IPythonInputSplitter(), 'In> '
674 isp, start_prompt = IPythonInputSplitter(), 'In> '
675
675
676 autoindent = True
676 autoindent = True
677 #autoindent = False
677 #autoindent = False
678
678
679 try:
679 try:
680 while True:
680 while True:
681 prompt = start_prompt
681 prompt = start_prompt
682 while isp.push_accepts_more():
682 while isp.push_accepts_more():
683 indent = ' '*isp.indent_spaces
683 indent = ' '*isp.indent_spaces
684 if autoindent:
684 if autoindent:
685 line = indent + raw_input(prompt+indent)
685 line = indent + raw_input(prompt+indent)
686 else:
686 else:
687 line = raw_input(prompt)
687 line = raw_input(prompt)
688 isp.push(line)
688 isp.push(line)
689 prompt = '... '
689 prompt = '... '
690
690
691 # Here we just return input so we can use it in a test suite, but a
691 # Here we just return input so we can use it in a test suite, but a
692 # real interpreter would instead send it for execution somewhere.
692 # real interpreter would instead send it for execution somewhere.
693 #src = isp.source; raise EOFError # dbg
693 #src = isp.source; raise EOFError # dbg
694 src, raw = isp.source_raw_reset()
694 src, raw = isp.source_raw_reset()
695 print 'Input source was:\n', src
695 print 'Input source was:\n', src
696 print 'Raw source was:\n', raw
696 print 'Raw source was:\n', raw
697 except EOFError:
697 except EOFError:
698 print 'Bye'
698 print 'Bye'
@@ -1,345 +1,345 b''
1 """Generic testing tools that do NOT depend on Twisted.
1 """Generic testing tools that do NOT depend on Twisted.
2
2
3 In particular, this module exposes a set of top-level assert* functions that
3 In particular, this module exposes a set of top-level assert* functions that
4 can be used in place of nose.tools.assert* in method generators (the ones in
4 can be used in place of nose.tools.assert* in method generators (the ones in
5 nose can not, at least as of nose 0.10.4).
5 nose can not, at least as of nose 0.10.4).
6
6
7 Note: our testing package contains testing.util, which does depend on Twisted
7 Note: our testing package contains testing.util, which does depend on Twisted
8 and provides utilities for tests that manage Deferreds. All testing support
8 and provides utilities for tests that manage Deferreds. All testing support
9 tools that only depend on nose, IPython or the standard library should go here
9 tools that only depend on nose, IPython or the standard library should go here
10 instead.
10 instead.
11
11
12
12
13 Authors
13 Authors
14 -------
14 -------
15 - Fernando Perez <Fernando.Perez@berkeley.edu>
15 - Fernando Perez <Fernando.Perez@berkeley.edu>
16 """
16 """
17
17
18 from __future__ import absolute_import
18 from __future__ import absolute_import
19
19
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21 # Copyright (C) 2009 The IPython Development Team
21 # Copyright (C) 2009 The IPython Development Team
22 #
22 #
23 # Distributed under the terms of the BSD License. The full license is in
23 # Distributed under the terms of the BSD License. The full license is in
24 # the file COPYING, distributed as part of this software.
24 # the file COPYING, distributed as part of this software.
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26
26
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28 # Imports
28 # Imports
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30
30
31 import os
31 import os
32 import re
32 import re
33 import sys
33 import sys
34 import tempfile
34 import tempfile
35
35
36 from contextlib import contextmanager
36 from contextlib import contextmanager
37
37
38 try:
38 try:
39 # These tools are used by parts of the runtime, so we make the nose
39 # These tools are used by parts of the runtime, so we make the nose
40 # dependency optional at this point. Nose is a hard dependency to run the
40 # dependency optional at this point. Nose is a hard dependency to run the
41 # test suite, but NOT to use ipython itself.
41 # test suite, but NOT to use ipython itself.
42 import nose.tools as nt
42 import nose.tools as nt
43 has_nose = True
43 has_nose = True
44 except ImportError:
44 except ImportError:
45 has_nose = False
45 has_nose = False
46
46
47 from IPython.config.loader import Config
47 from IPython.config.loader import Config
48 from IPython.utils.process import find_cmd, getoutputerror
48 from IPython.utils.process import find_cmd, getoutputerror
49 from IPython.utils.text import list_strings
49 from IPython.utils.text import list_strings
50 from IPython.utils.io import temp_pyfile
50 from IPython.utils.io import temp_pyfile
51
51
52 from . import decorators as dec
52 from . import decorators as dec
53 from . import skipdoctest
53 from . import skipdoctest
54
54
55 #-----------------------------------------------------------------------------
55 #-----------------------------------------------------------------------------
56 # Globals
56 # Globals
57 #-----------------------------------------------------------------------------
57 #-----------------------------------------------------------------------------
58
58
59 # Make a bunch of nose.tools assert wrappers that can be used in test
59 # Make a bunch of nose.tools assert wrappers that can be used in test
60 # generators. This will expose an assert* function for each one in nose.tools.
60 # generators. This will expose an assert* function for each one in nose.tools.
61
61
62 _tpl = """
62 _tpl = """
63 def %(name)s(*a,**kw):
63 def %(name)s(*a,**kw):
64 return nt.%(name)s(*a,**kw)
64 return nt.%(name)s(*a,**kw)
65 """
65 """
66
66
67 if has_nose:
67 if has_nose:
68 for _x in [a for a in dir(nt) if a.startswith('assert')]:
68 for _x in [a for a in dir(nt) if a.startswith('assert')]:
69 exec _tpl % dict(name=_x)
69 exec _tpl % dict(name=_x)
70
70
71 #-----------------------------------------------------------------------------
71 #-----------------------------------------------------------------------------
72 # Functions and classes
72 # Functions and classes
73 #-----------------------------------------------------------------------------
73 #-----------------------------------------------------------------------------
74
74
75 # The docstring for full_path doctests differently on win32 (different path
75 # The docstring for full_path doctests differently on win32 (different path
76 # separator) so just skip the doctest there. The example remains informative.
76 # separator) so just skip the doctest there. The example remains informative.
77 doctest_deco = skipdoctest.skip_doctest if sys.platform == 'win32' else dec.null_deco
77 doctest_deco = skipdoctest.skip_doctest if sys.platform == 'win32' else dec.null_deco
78
78
79 @doctest_deco
79 @doctest_deco
80 def full_path(startPath,files):
80 def full_path(startPath,files):
81 """Make full paths for all the listed files, based on startPath.
81 """Make full paths for all the listed files, based on startPath.
82
82
83 Only the base part of startPath is kept, since this routine is typically
83 Only the base part of startPath is kept, since this routine is typically
84 used with a script's __file__ variable as startPath. The base of startPath
84 used with a script's __file__ variable as startPath. The base of startPath
85 is then prepended to all the listed files, forming the output list.
85 is then prepended to all the listed files, forming the output list.
86
86
87 Parameters
87 Parameters
88 ----------
88 ----------
89 startPath : string
89 startPath : string
90 Initial path to use as the base for the results. This path is split
90 Initial path to use as the base for the results. This path is split
91 using os.path.split() and only its first component is kept.
91 using os.path.split() and only its first component is kept.
92
92
93 files : string or list
93 files : string or list
94 One or more files.
94 One or more files.
95
95
96 Examples
96 Examples
97 --------
97 --------
98
98
99 >>> full_path('/foo/bar.py',['a.txt','b.txt'])
99 >>> full_path('/foo/bar.py',['a.txt','b.txt'])
100 ['/foo/a.txt', '/foo/b.txt']
100 ['/foo/a.txt', '/foo/b.txt']
101
101
102 >>> full_path('/foo',['a.txt','b.txt'])
102 >>> full_path('/foo',['a.txt','b.txt'])
103 ['/a.txt', '/b.txt']
103 ['/a.txt', '/b.txt']
104
104
105 If a single file is given, the output is still a list:
105 If a single file is given, the output is still a list:
106 >>> full_path('/foo','a.txt')
106 >>> full_path('/foo','a.txt')
107 ['/a.txt']
107 ['/a.txt']
108 """
108 """
109
109
110 files = list_strings(files)
110 files = list_strings(files)
111 base = os.path.split(startPath)[0]
111 base = os.path.split(startPath)[0]
112 return [ os.path.join(base,f) for f in files ]
112 return [ os.path.join(base,f) for f in files ]
113
113
114
114
115 def parse_test_output(txt):
115 def parse_test_output(txt):
116 """Parse the output of a test run and return errors, failures.
116 """Parse the output of a test run and return errors, failures.
117
117
118 Parameters
118 Parameters
119 ----------
119 ----------
120 txt : str
120 txt : str
121 Text output of a test run, assumed to contain a line of one of the
121 Text output of a test run, assumed to contain a line of one of the
122 following forms::
122 following forms::
123 'FAILED (errors=1)'
123 'FAILED (errors=1)'
124 'FAILED (failures=1)'
124 'FAILED (failures=1)'
125 'FAILED (errors=1, failures=1)'
125 'FAILED (errors=1, failures=1)'
126
126
127 Returns
127 Returns
128 -------
128 -------
129 nerr, nfail: number of errors and failures.
129 nerr, nfail: number of errors and failures.
130 """
130 """
131
131
132 err_m = re.search(r'^FAILED \(errors=(\d+)\)', txt, re.MULTILINE)
132 err_m = re.search(r'^FAILED \(errors=(\d+)\)', txt, re.MULTILINE)
133 if err_m:
133 if err_m:
134 nerr = int(err_m.group(1))
134 nerr = int(err_m.group(1))
135 nfail = 0
135 nfail = 0
136 return nerr, nfail
136 return nerr, nfail
137
137
138 fail_m = re.search(r'^FAILED \(failures=(\d+)\)', txt, re.MULTILINE)
138 fail_m = re.search(r'^FAILED \(failures=(\d+)\)', txt, re.MULTILINE)
139 if fail_m:
139 if fail_m:
140 nerr = 0
140 nerr = 0
141 nfail = int(fail_m.group(1))
141 nfail = int(fail_m.group(1))
142 return nerr, nfail
142 return nerr, nfail
143
143
144 both_m = re.search(r'^FAILED \(errors=(\d+), failures=(\d+)\)', txt,
144 both_m = re.search(r'^FAILED \(errors=(\d+), failures=(\d+)\)', txt,
145 re.MULTILINE)
145 re.MULTILINE)
146 if both_m:
146 if both_m:
147 nerr = int(both_m.group(1))
147 nerr = int(both_m.group(1))
148 nfail = int(both_m.group(2))
148 nfail = int(both_m.group(2))
149 return nerr, nfail
149 return nerr, nfail
150
150
151 # If the input didn't match any of these forms, assume no error/failures
151 # If the input didn't match any of these forms, assume no error/failures
152 return 0, 0
152 return 0, 0
153
153
154
154
155 # So nose doesn't think this is a test
155 # So nose doesn't think this is a test
156 parse_test_output.__test__ = False
156 parse_test_output.__test__ = False
157
157
158
158
159 def default_argv():
159 def default_argv():
160 """Return a valid default argv for creating testing instances of ipython"""
160 """Return a valid default argv for creating testing instances of ipython"""
161
161
162 return ['--quick', # so no config file is loaded
162 return ['--quick', # so no config file is loaded
163 # Other defaults to minimize side effects on stdout
163 # Other defaults to minimize side effects on stdout
164 '--colors=NoColor', '--no-term-title','--no-banner',
164 '--colors=NoColor', '--no-term-title','--no-banner',
165 '--autocall=0']
165 '--autocall=0']
166
166
167
167
168 def default_config():
168 def default_config():
169 """Return a config object with good defaults for testing."""
169 """Return a config object with good defaults for testing."""
170 config = Config()
170 config = Config()
171 config.TerminalInteractiveShell.colors = 'NoColor'
171 config.TerminalInteractiveShell.colors = 'NoColor'
172 config.TerminalTerminalInteractiveShell.term_title = False,
172 config.TerminalTerminalInteractiveShell.term_title = False,
173 config.TerminalInteractiveShell.autocall = 0
173 config.TerminalInteractiveShell.autocall = 0
174 config.HistoryManager.hist_file = tempfile.mktemp(u'test_hist.sqlite')
174 config.HistoryManager.hist_file = tempfile.mktemp(u'test_hist.sqlite')
175 config.HistoryManager.db_cache_size = 10000
175 config.HistoryManager.db_cache_size = 10000
176 return config
176 return config
177
177
178
178
179 def ipexec(fname, options=None):
179 def ipexec(fname, options=None):
180 """Utility to call 'ipython filename'.
180 """Utility to call 'ipython filename'.
181
181
182 Starts IPython witha minimal and safe configuration to make startup as fast
182 Starts IPython witha minimal and safe configuration to make startup as fast
183 as possible.
183 as possible.
184
184
185 Note that this starts IPython in a subprocess!
185 Note that this starts IPython in a subprocess!
186
186
187 Parameters
187 Parameters
188 ----------
188 ----------
189 fname : str
189 fname : str
190 Name of file to be executed (should have .py or .ipy extension).
190 Name of file to be executed (should have .py or .ipy extension).
191
191
192 options : optional, list
192 options : optional, list
193 Extra command-line flags to be passed to IPython.
193 Extra command-line flags to be passed to IPython.
194
194
195 Returns
195 Returns
196 -------
196 -------
197 (stdout, stderr) of ipython subprocess.
197 (stdout, stderr) of ipython subprocess.
198 """
198 """
199 if options is None: options = []
199 if options is None: options = []
200
200
201 # For these subprocess calls, eliminate all prompt printing so we only see
201 # For these subprocess calls, eliminate all prompt printing so we only see
202 # output from script execution
202 # output from script execution
203 prompt_opts = [ '--InteractiveShell.prompt_in1=""',
203 prompt_opts = [ '--InteractiveShell.prompt_in1=""',
204 '--InteractiveShell.prompt_in2=""',
204 '--InteractiveShell.prompt_in2=""',
205 '--InteractiveShell.prompt_out=""'
205 '--InteractiveShell.prompt_out=""'
206 ]
206 ]
207 cmdargs = ' '.join(default_argv() + prompt_opts + options)
207 cmdargs = ' '.join(default_argv() + prompt_opts + options)
208
208
209 _ip = get_ipython()
209 _ip = get_ipython()
210 test_dir = os.path.dirname(__file__)
210 test_dir = os.path.dirname(__file__)
211
211
212 ipython_cmd = find_cmd('ipython')
212 ipython_cmd = find_cmd('ipython')
213 # Absolute path for filename
213 # Absolute path for filename
214 full_fname = os.path.join(test_dir, fname)
214 full_fname = os.path.join(test_dir, fname)
215 full_cmd = '%s %s %s' % (ipython_cmd, cmdargs, full_fname)
215 full_cmd = '%s %s %s' % (ipython_cmd, cmdargs, full_fname)
216 #print >> sys.stderr, 'FULL CMD:', full_cmd # dbg
216 #print >> sys.stderr, 'FULL CMD:', full_cmd # dbg
217 out = getoutputerror(full_cmd)
217 out = getoutputerror(full_cmd)
218 # `import readline` causes 'ESC[?1034h' to be the first output sometimes,
218 # `import readline` causes 'ESC[?1034h' to be the first output sometimes,
219 # so strip that off the front of the first line if it is found
219 # so strip that off the front of the first line if it is found
220 if out:
220 if out:
221 first = out[0]
221 first = out[0]
222 m = re.match(r'\x1b\[[^h]+h', first)
222 m = re.match(r'\x1b\[[^h]+h', first)
223 if m:
223 if m:
224 # strip initial readline escape
224 # strip initial readline escape
225 out = list(out)
225 out = list(out)
226 out[0] = first[len(m.group()):]
226 out[0] = first[len(m.group()):]
227 out = tuple(out)
227 out = tuple(out)
228 return out
228 return out
229
229
230
230
231 def ipexec_validate(fname, expected_out, expected_err='',
231 def ipexec_validate(fname, expected_out, expected_err='',
232 options=None):
232 options=None):
233 """Utility to call 'ipython filename' and validate output/error.
233 """Utility to call 'ipython filename' and validate output/error.
234
234
235 This function raises an AssertionError if the validation fails.
235 This function raises an AssertionError if the validation fails.
236
236
237 Note that this starts IPython in a subprocess!
237 Note that this starts IPython in a subprocess!
238
238
239 Parameters
239 Parameters
240 ----------
240 ----------
241 fname : str
241 fname : str
242 Name of the file to be executed (should have .py or .ipy extension).
242 Name of the file to be executed (should have .py or .ipy extension).
243
243
244 expected_out : str
244 expected_out : str
245 Expected stdout of the process.
245 Expected stdout of the process.
246
246
247 expected_err : optional, str
247 expected_err : optional, str
248 Expected stderr of the process.
248 Expected stderr of the process.
249
249
250 options : optional, list
250 options : optional, list
251 Extra command-line flags to be passed to IPython.
251 Extra command-line flags to be passed to IPython.
252
252
253 Returns
253 Returns
254 -------
254 -------
255 None
255 None
256 """
256 """
257
257
258 import nose.tools as nt
258 import nose.tools as nt
259
259
260 out, err = ipexec(fname)
260 out, err = ipexec(fname)
261 #print 'OUT', out # dbg
261 #print 'OUT', out # dbg
262 #print 'ERR', err # dbg
262 #print 'ERR', err # dbg
263 # If there are any errors, we must check those befor stdout, as they may be
263 # If there are any errors, we must check those befor stdout, as they may be
264 # more informative than simply having an empty stdout.
264 # more informative than simply having an empty stdout.
265 if err:
265 if err:
266 if expected_err:
266 if expected_err:
267 nt.assert_equals(err.strip(), expected_err.strip())
267 nt.assert_equals(err.strip(), expected_err.strip())
268 else:
268 else:
269 raise ValueError('Running file %r produced error: %r' %
269 raise ValueError('Running file %r produced error: %r' %
270 (fname, err))
270 (fname, err))
271 # If no errors or output on stderr was expected, match stdout
271 # If no errors or output on stderr was expected, match stdout
272 nt.assert_equals(out.strip(), expected_out.strip())
272 nt.assert_equals(out.strip(), expected_out.strip())
273
273
274
274
275 class TempFileMixin(object):
275 class TempFileMixin(object):
276 """Utility class to create temporary Python/IPython files.
276 """Utility class to create temporary Python/IPython files.
277
277
278 Meant as a mixin class for test cases."""
278 Meant as a mixin class for test cases."""
279
279
280 def mktmp(self, src, ext='.py'):
280 def mktmp(self, src, ext='.py'):
281 """Make a valid python temp file."""
281 """Make a valid python temp file."""
282 fname, f = temp_pyfile(src, ext)
282 fname, f = temp_pyfile(src, ext)
283 self.tmpfile = f
283 self.tmpfile = f
284 self.fname = fname
284 self.fname = fname
285
285
286 def tearDown(self):
286 def tearDown(self):
287 if hasattr(self, 'tmpfile'):
287 if hasattr(self, 'tmpfile'):
288 # If the tmpfile wasn't made because of skipped tests, like in
288 # If the tmpfile wasn't made because of skipped tests, like in
289 # win32, there's nothing to cleanup.
289 # win32, there's nothing to cleanup.
290 self.tmpfile.close()
290 self.tmpfile.close()
291 try:
291 try:
292 os.unlink(self.fname)
292 os.unlink(self.fname)
293 except:
293 except:
294 # On Windows, even though we close the file, we still can't
294 # On Windows, even though we close the file, we still can't
295 # delete it. I have no clue why
295 # delete it. I have no clue why
296 pass
296 pass
297
297
298 pair_fail_msg = ("Testing function {0}\n\n"
298 pair_fail_msg = ("Testing {0}\n\n"
299 "In:\n"
299 "In:\n"
300 " {1!r}\n"
300 " {1!r}\n"
301 "Expected:\n"
301 "Expected:\n"
302 " {2!r}\n"
302 " {2!r}\n"
303 "Got:\n"
303 "Got:\n"
304 " {3!r}\n")
304 " {3!r}\n")
305 def check_pairs(func, pairs):
305 def check_pairs(func, pairs):
306 """Utility function for the common case of checking a function with a
306 """Utility function for the common case of checking a function with a
307 sequence of input/output pairs.
307 sequence of input/output pairs.
308
308
309 Parameters
309 Parameters
310 ----------
310 ----------
311 func : callable
311 func : callable
312 The function to be tested. Should accept a single argument.
312 The function to be tested. Should accept a single argument.
313 pairs : iterable
313 pairs : iterable
314 A list of (input, expected_output) tuples.
314 A list of (input, expected_output) tuples.
315
315
316 Returns
316 Returns
317 -------
317 -------
318 None. Raises an AssertionError if any output does not match the expected
318 None. Raises an AssertionError if any output does not match the expected
319 value.
319 value.
320 """
320 """
321 name = getattr(func, "func_name", getattr(func, "__name__", "<unknown>"))
321 for inp, expected in pairs:
322 for inp, expected in pairs:
322 out = func(inp)
323 out = func(inp)
323 assert out == expected, pair_fail_msg.format(func.func_name, inp, expected, out)
324 assert out == expected, pair_fail_msg.format(name, inp, expected, out)
324
325
325 @contextmanager
326 @contextmanager
326 def mute_warn():
327 def mute_warn():
327 from IPython.utils import warn
328 from IPython.utils import warn
328 save_warn = warn.warn
329 save_warn = warn.warn
329 warn.warn = lambda *a, **kw: None
330 warn.warn = lambda *a, **kw: None
330 try:
331 try:
331 yield
332 yield
332 finally:
333 finally:
333 warn.warn = save_warn
334 warn.warn = save_warn
334
335
335 @contextmanager
336 @contextmanager
336 def make_tempfile(name):
337 def make_tempfile(name):
337 """ Create an empty, named, temporary file for the duration of the context.
338 """ Create an empty, named, temporary file for the duration of the context.
338 """
339 """
339 f = open(name, 'w')
340 f = open(name, 'w')
340 f.close()
341 f.close()
341 try:
342 try:
342 yield
343 yield
343 finally:
344 finally:
344 os.unlink(name)
345 os.unlink(name)
345
General Comments 0
You need to be logged in to leave comments. Login now