##// END OF EJS Templates
Merge pull request #2299 from takluyver/remove-duplicate-input-transforms...
Fernando Perez -
r8219:06a7a574 merge
parent child Browse files
Show More
@@ -1,956 +1,757 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-2011 The IPython Development Team
17 # Copyright (C) 2008-2011 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.inputsplitter import (
34 from IPython.core.inputsplitter import (
35 ESC_SHELL,
35 ESC_SHELL,
36 ESC_SH_CAP,
36 ESC_SH_CAP,
37 ESC_HELP,
37 ESC_HELP,
38 ESC_MAGIC,
38 ESC_MAGIC,
39 ESC_MAGIC2,
39 ESC_MAGIC2,
40 ESC_QUOTE,
40 ESC_QUOTE,
41 ESC_QUOTE2,
41 ESC_QUOTE2,
42 ESC_PAREN,
42 ESC_PAREN,
43 )
43 )
44 from IPython.core.macro import Macro
44 from IPython.core.macro import Macro
45 from IPython.core.splitinput import split_user_input, LineInfo
45 from IPython.core.splitinput import split_user_input, LineInfo
46 from IPython.core import page
46 from IPython.core import page
47
47
48 from IPython.utils.traitlets import (
48 from IPython.utils.traitlets import (
49 List, Integer, Any, Unicode, CBool, Bool, Instance, CRegExp
49 List, Integer, Any, Unicode, CBool, Bool, Instance, CRegExp
50 )
50 )
51 from IPython.utils.autoattr import auto_attr
51 from IPython.utils.autoattr import auto_attr
52
52
53 #-----------------------------------------------------------------------------
53 #-----------------------------------------------------------------------------
54 # Global utilities, errors and constants
54 # Global utilities, errors and constants
55 #-----------------------------------------------------------------------------
55 #-----------------------------------------------------------------------------
56
56
57
57
58 class PrefilterError(Exception):
58 class PrefilterError(Exception):
59 pass
59 pass
60
60
61
61
62 # RegExp to identify potential function names
62 # RegExp to identify potential function names
63 re_fun_name = re.compile(r'[a-zA-Z_]([a-zA-Z0-9_.]*) *$')
63 re_fun_name = re.compile(r'[a-zA-Z_]([a-zA-Z0-9_.]*) *$')
64
64
65 # RegExp to exclude strings with this start from autocalling. In
65 # RegExp to exclude strings with this start from autocalling. In
66 # particular, all binary operators should be excluded, so that if foo is
66 # particular, all binary operators should be excluded, so that if foo is
67 # callable, foo OP bar doesn't become foo(OP bar), which is invalid. The
67 # callable, foo OP bar doesn't become foo(OP bar), which is invalid. The
68 # characters '!=()' don't need to be checked for, as the checkPythonChars
68 # characters '!=()' don't need to be checked for, as the checkPythonChars
69 # routine explicitely does so, to catch direct calls and rebindings of
69 # routine explicitely does so, to catch direct calls and rebindings of
70 # existing names.
70 # existing names.
71
71
72 # Warning: the '-' HAS TO BE AT THE END of the first group, otherwise
72 # Warning: the '-' HAS TO BE AT THE END of the first group, otherwise
73 # it affects the rest of the group in square brackets.
73 # it affects the rest of the group in square brackets.
74 re_exclude_auto = re.compile(r'^[,&^\|\*/\+-]'
74 re_exclude_auto = re.compile(r'^[,&^\|\*/\+-]'
75 r'|^is |^not |^in |^and |^or ')
75 r'|^is |^not |^in |^and |^or ')
76
76
77 # try to catch also methods for stuff in lists/tuples/dicts: off
77 # try to catch also methods for stuff in lists/tuples/dicts: off
78 # (experimental). For this to work, the line_split regexp would need
78 # (experimental). For this to work, the line_split regexp would need
79 # to be modified so it wouldn't break things at '['. That line is
79 # to be modified so it wouldn't break things at '['. That line is
80 # nasty enough that I shouldn't change it until I can test it _well_.
80 # nasty enough that I shouldn't change it until I can test it _well_.
81 #self.re_fun_name = re.compile (r'[a-zA-Z_]([a-zA-Z0-9_.\[\]]*) ?$')
81 #self.re_fun_name = re.compile (r'[a-zA-Z_]([a-zA-Z0-9_.\[\]]*) ?$')
82
82
83
83
84 # Handler Check Utilities
84 # Handler Check Utilities
85 def is_shadowed(identifier, ip):
85 def is_shadowed(identifier, ip):
86 """Is the given identifier defined in one of the namespaces which shadow
86 """Is the given identifier defined in one of the namespaces which shadow
87 the alias and magic namespaces? Note that an identifier is different
87 the alias and magic namespaces? Note that an identifier is different
88 than ifun, because it can not contain a '.' character."""
88 than ifun, because it can not contain a '.' character."""
89 # This is much safer than calling ofind, which can change state
89 # This is much safer than calling ofind, which can change state
90 return (identifier in ip.user_ns \
90 return (identifier in ip.user_ns \
91 or identifier in ip.user_global_ns \
91 or identifier in ip.user_global_ns \
92 or identifier in ip.ns_table['builtin'])
92 or identifier in ip.ns_table['builtin'])
93
93
94
94
95 #-----------------------------------------------------------------------------
95 #-----------------------------------------------------------------------------
96 # Main Prefilter manager
96 # Main Prefilter manager
97 #-----------------------------------------------------------------------------
97 #-----------------------------------------------------------------------------
98
98
99
99
100 class PrefilterManager(Configurable):
100 class PrefilterManager(Configurable):
101 """Main prefilter component.
101 """Main prefilter component.
102
102
103 The IPython prefilter is run on all user input before it is run. The
103 The IPython prefilter is run on all user input before it is run. The
104 prefilter consumes lines of input and produces transformed lines of
104 prefilter consumes lines of input and produces transformed lines of
105 input.
105 input.
106
106
107 The iplementation consists of two phases:
107 The iplementation consists of two phases:
108
108
109 1. Transformers
109 1. Transformers
110 2. Checkers and handlers
110 2. Checkers and handlers
111
111
112 Over time, we plan on deprecating the checkers and handlers and doing
112 Over time, we plan on deprecating the checkers and handlers and doing
113 everything in the transformers.
113 everything in the transformers.
114
114
115 The transformers are instances of :class:`PrefilterTransformer` and have
115 The transformers are instances of :class:`PrefilterTransformer` and have
116 a single method :meth:`transform` that takes a line and returns a
116 a single method :meth:`transform` that takes a line and returns a
117 transformed line. The transformation can be accomplished using any
117 transformed line. The transformation can be accomplished using any
118 tool, but our current ones use regular expressions for speed.
118 tool, but our current ones use regular expressions for speed.
119
119
120 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,
121 which are instances of :class:`PrefilterChecker`. The line is passed to
121 which are instances of :class:`PrefilterChecker`. The line is passed to
122 the :meth:`check` method, which either returns `None` or a
122 the :meth:`check` method, which either returns `None` or a
123 :class:`PrefilterHandler` instance. If `None` is returned, the other
123 :class:`PrefilterHandler` instance. If `None` is returned, the other
124 checkers are tried. If an :class:`PrefilterHandler` instance is returned,
124 checkers are tried. If an :class:`PrefilterHandler` instance is returned,
125 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
126 handler and no further checkers are tried.
126 handler and no further checkers are tried.
127
127
128 Both transformers and checkers have a `priority` attribute, that determines
128 Both transformers and checkers have a `priority` attribute, that determines
129 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.
130
130
131 Both transformers and checkers also have `enabled` attribute, which is
131 Both transformers and checkers also have `enabled` attribute, which is
132 a boolean that determines if the instance is used.
132 a boolean that determines if the instance is used.
133
133
134 Users or developers can change the priority or enabled attribute of
134 Users or developers can change the priority or enabled attribute of
135 transformers or checkers, but they must call the :meth:`sort_checkers`
135 transformers or checkers, but they must call the :meth:`sort_checkers`
136 or :meth:`sort_transformers` method after changing the priority.
136 or :meth:`sort_transformers` method after changing the priority.
137 """
137 """
138
138
139 multi_line_specials = CBool(True, config=True)
139 multi_line_specials = CBool(True, config=True)
140 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
140 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
141
141
142 def __init__(self, shell=None, config=None):
142 def __init__(self, shell=None, config=None):
143 super(PrefilterManager, self).__init__(shell=shell, config=config)
143 super(PrefilterManager, self).__init__(shell=shell, config=config)
144 self.shell = shell
144 self.shell = shell
145 self.init_transformers()
145 self.init_transformers()
146 self.init_handlers()
146 self.init_handlers()
147 self.init_checkers()
147 self.init_checkers()
148
148
149 #-------------------------------------------------------------------------
149 #-------------------------------------------------------------------------
150 # API for managing transformers
150 # API for managing transformers
151 #-------------------------------------------------------------------------
151 #-------------------------------------------------------------------------
152
152
153 def init_transformers(self):
153 def init_transformers(self):
154 """Create the default transformers."""
154 """Create the default transformers."""
155 self._transformers = []
155 self._transformers = []
156 for transformer_cls in _default_transformers:
156 for transformer_cls in _default_transformers:
157 transformer_cls(
157 transformer_cls(
158 shell=self.shell, prefilter_manager=self, config=self.config
158 shell=self.shell, prefilter_manager=self, config=self.config
159 )
159 )
160
160
161 def sort_transformers(self):
161 def sort_transformers(self):
162 """Sort the transformers by priority.
162 """Sort the transformers by priority.
163
163
164 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.
165 The :meth:`register_transformer` method calls this automatically.
165 The :meth:`register_transformer` method calls this automatically.
166 """
166 """
167 self._transformers.sort(key=lambda x: x.priority)
167 self._transformers.sort(key=lambda x: x.priority)
168
168
169 @property
169 @property
170 def transformers(self):
170 def transformers(self):
171 """Return a list of checkers, sorted by priority."""
171 """Return a list of checkers, sorted by priority."""
172 return self._transformers
172 return self._transformers
173
173
174 def register_transformer(self, transformer):
174 def register_transformer(self, transformer):
175 """Register a transformer instance."""
175 """Register a transformer instance."""
176 if transformer not in self._transformers:
176 if transformer not in self._transformers:
177 self._transformers.append(transformer)
177 self._transformers.append(transformer)
178 self.sort_transformers()
178 self.sort_transformers()
179
179
180 def unregister_transformer(self, transformer):
180 def unregister_transformer(self, transformer):
181 """Unregister a transformer instance."""
181 """Unregister a transformer instance."""
182 if transformer in self._transformers:
182 if transformer in self._transformers:
183 self._transformers.remove(transformer)
183 self._transformers.remove(transformer)
184
184
185 #-------------------------------------------------------------------------
185 #-------------------------------------------------------------------------
186 # API for managing checkers
186 # API for managing checkers
187 #-------------------------------------------------------------------------
187 #-------------------------------------------------------------------------
188
188
189 def init_checkers(self):
189 def init_checkers(self):
190 """Create the default checkers."""
190 """Create the default checkers."""
191 self._checkers = []
191 self._checkers = []
192 for checker in _default_checkers:
192 for checker in _default_checkers:
193 checker(
193 checker(
194 shell=self.shell, prefilter_manager=self, config=self.config
194 shell=self.shell, prefilter_manager=self, config=self.config
195 )
195 )
196
196
197 def sort_checkers(self):
197 def sort_checkers(self):
198 """Sort the checkers by priority.
198 """Sort the checkers by priority.
199
199
200 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.
201 The :meth:`register_checker` method calls this automatically.
201 The :meth:`register_checker` method calls this automatically.
202 """
202 """
203 self._checkers.sort(key=lambda x: x.priority)
203 self._checkers.sort(key=lambda x: x.priority)
204
204
205 @property
205 @property
206 def checkers(self):
206 def checkers(self):
207 """Return a list of checkers, sorted by priority."""
207 """Return a list of checkers, sorted by priority."""
208 return self._checkers
208 return self._checkers
209
209
210 def register_checker(self, checker):
210 def register_checker(self, checker):
211 """Register a checker instance."""
211 """Register a checker instance."""
212 if checker not in self._checkers:
212 if checker not in self._checkers:
213 self._checkers.append(checker)
213 self._checkers.append(checker)
214 self.sort_checkers()
214 self.sort_checkers()
215
215
216 def unregister_checker(self, checker):
216 def unregister_checker(self, checker):
217 """Unregister a checker instance."""
217 """Unregister a checker instance."""
218 if checker in self._checkers:
218 if checker in self._checkers:
219 self._checkers.remove(checker)
219 self._checkers.remove(checker)
220
220
221 #-------------------------------------------------------------------------
221 #-------------------------------------------------------------------------
222 # API for managing checkers
222 # API for managing checkers
223 #-------------------------------------------------------------------------
223 #-------------------------------------------------------------------------
224
224
225 def init_handlers(self):
225 def init_handlers(self):
226 """Create the default handlers."""
226 """Create the default handlers."""
227 self._handlers = {}
227 self._handlers = {}
228 self._esc_handlers = {}
228 self._esc_handlers = {}
229 for handler in _default_handlers:
229 for handler in _default_handlers:
230 handler(
230 handler(
231 shell=self.shell, prefilter_manager=self, config=self.config
231 shell=self.shell, prefilter_manager=self, config=self.config
232 )
232 )
233
233
234 @property
234 @property
235 def handlers(self):
235 def handlers(self):
236 """Return a dict of all the handlers."""
236 """Return a dict of all the handlers."""
237 return self._handlers
237 return self._handlers
238
238
239 def register_handler(self, name, handler, esc_strings):
239 def register_handler(self, name, handler, esc_strings):
240 """Register a handler instance by name with esc_strings."""
240 """Register a handler instance by name with esc_strings."""
241 self._handlers[name] = handler
241 self._handlers[name] = handler
242 for esc_str in esc_strings:
242 for esc_str in esc_strings:
243 self._esc_handlers[esc_str] = handler
243 self._esc_handlers[esc_str] = handler
244
244
245 def unregister_handler(self, name, handler, esc_strings):
245 def unregister_handler(self, name, handler, esc_strings):
246 """Unregister a handler instance by name with esc_strings."""
246 """Unregister a handler instance by name with esc_strings."""
247 try:
247 try:
248 del self._handlers[name]
248 del self._handlers[name]
249 except KeyError:
249 except KeyError:
250 pass
250 pass
251 for esc_str in esc_strings:
251 for esc_str in esc_strings:
252 h = self._esc_handlers.get(esc_str)
252 h = self._esc_handlers.get(esc_str)
253 if h is handler:
253 if h is handler:
254 del self._esc_handlers[esc_str]
254 del self._esc_handlers[esc_str]
255
255
256 def get_handler_by_name(self, name):
256 def get_handler_by_name(self, name):
257 """Get a handler by its name."""
257 """Get a handler by its name."""
258 return self._handlers.get(name)
258 return self._handlers.get(name)
259
259
260 def get_handler_by_esc(self, esc_str):
260 def get_handler_by_esc(self, esc_str):
261 """Get a handler by its escape string."""
261 """Get a handler by its escape string."""
262 return self._esc_handlers.get(esc_str)
262 return self._esc_handlers.get(esc_str)
263
263
264 #-------------------------------------------------------------------------
264 #-------------------------------------------------------------------------
265 # Main prefiltering API
265 # Main prefiltering API
266 #-------------------------------------------------------------------------
266 #-------------------------------------------------------------------------
267
267
268 def prefilter_line_info(self, line_info):
268 def prefilter_line_info(self, line_info):
269 """Prefilter a line that has been converted to a LineInfo object.
269 """Prefilter a line that has been converted to a LineInfo object.
270
270
271 This implements the checker/handler part of the prefilter pipe.
271 This implements the checker/handler part of the prefilter pipe.
272 """
272 """
273 # print "prefilter_line_info: ", line_info
273 # print "prefilter_line_info: ", line_info
274 handler = self.find_handler(line_info)
274 handler = self.find_handler(line_info)
275 return handler.handle(line_info)
275 return handler.handle(line_info)
276
276
277 def find_handler(self, line_info):
277 def find_handler(self, line_info):
278 """Find a handler for the line_info by trying checkers."""
278 """Find a handler for the line_info by trying checkers."""
279 for checker in self.checkers:
279 for checker in self.checkers:
280 if checker.enabled:
280 if checker.enabled:
281 handler = checker.check(line_info)
281 handler = checker.check(line_info)
282 if handler:
282 if handler:
283 return handler
283 return handler
284 return self.get_handler_by_name('normal')
284 return self.get_handler_by_name('normal')
285
285
286 def transform_line(self, line, continue_prompt):
286 def transform_line(self, line, continue_prompt):
287 """Calls the enabled transformers in order of increasing priority."""
287 """Calls the enabled transformers in order of increasing priority."""
288 for transformer in self.transformers:
288 for transformer in self.transformers:
289 if transformer.enabled:
289 if transformer.enabled:
290 line = transformer.transform(line, continue_prompt)
290 line = transformer.transform(line, continue_prompt)
291 return line
291 return line
292
292
293 def prefilter_line(self, line, continue_prompt=False):
293 def prefilter_line(self, line, continue_prompt=False):
294 """Prefilter a single input line as text.
294 """Prefilter a single input line as text.
295
295
296 This method prefilters a single line of text by calling the
296 This method prefilters a single line of text by calling the
297 transformers and then the checkers/handlers.
297 transformers and then the checkers/handlers.
298 """
298 """
299
299
300 # print "prefilter_line: ", line, continue_prompt
300 # print "prefilter_line: ", line, continue_prompt
301 # All handlers *must* return a value, even if it's blank ('').
301 # All handlers *must* return a value, even if it's blank ('').
302
302
303 # 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
304 # record it
304 # record it
305 self.shell._last_input_line = line
305 self.shell._last_input_line = line
306
306
307 if not line:
307 if not line:
308 # Return immediately on purely empty lines, so that if the user
308 # Return immediately on purely empty lines, so that if the user
309 # previously typed some whitespace that started a continuation
309 # previously typed some whitespace that started a continuation
310 # 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.
311 # This is how the default python prompt works.
311 # This is how the default python prompt works.
312 return ''
312 return ''
313
313
314 # At this point, we invoke our transformers.
314 # At this point, we invoke our transformers.
315 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):
316 line = self.transform_line(line, continue_prompt)
316 line = self.transform_line(line, continue_prompt)
317
317
318 # Now we compute line_info for the checkers and handlers
318 # Now we compute line_info for the checkers and handlers
319 line_info = LineInfo(line, continue_prompt)
319 line_info = LineInfo(line, continue_prompt)
320
320
321 # the input history needs to track even empty lines
321 # the input history needs to track even empty lines
322 stripped = line.strip()
322 stripped = line.strip()
323
323
324 normal_handler = self.get_handler_by_name('normal')
324 normal_handler = self.get_handler_by_name('normal')
325 if not stripped:
325 if not stripped:
326 if not continue_prompt:
326 if not continue_prompt:
327 self.shell.displayhook.prompt_count -= 1
327 self.shell.displayhook.prompt_count -= 1
328
328
329 return normal_handler.handle(line_info)
329 return normal_handler.handle(line_info)
330
330
331 # special handlers are only allowed for single line statements
331 # special handlers are only allowed for single line statements
332 if continue_prompt and not self.multi_line_specials:
332 if continue_prompt and not self.multi_line_specials:
333 return normal_handler.handle(line_info)
333 return normal_handler.handle(line_info)
334
334
335 prefiltered = self.prefilter_line_info(line_info)
335 prefiltered = self.prefilter_line_info(line_info)
336 # print "prefiltered line: %r" % prefiltered
336 # print "prefiltered line: %r" % prefiltered
337 return prefiltered
337 return prefiltered
338
338
339 def prefilter_lines(self, lines, continue_prompt=False):
339 def prefilter_lines(self, lines, continue_prompt=False):
340 """Prefilter multiple input lines of text.
340 """Prefilter multiple input lines of text.
341
341
342 This is the main entry point for prefiltering multiple lines of
342 This is the main entry point for prefiltering multiple lines of
343 input. This simply calls :meth:`prefilter_line` for each line of
343 input. This simply calls :meth:`prefilter_line` for each line of
344 input.
344 input.
345
345
346 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,
347 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
348 entry and presses enter.
348 entry and presses enter.
349 """
349 """
350 llines = lines.rstrip('\n').split('\n')
350 llines = lines.rstrip('\n').split('\n')
351 # 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'
352 # into one line, in cases like recalling from the readline history
352 # into one line, in cases like recalling from the readline history
353 # 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
354 # communicate downstream which line is first and which are continuation
354 # communicate downstream which line is first and which are continuation
355 # ones.
355 # ones.
356 if len(llines) > 1:
356 if len(llines) > 1:
357 out = '\n'.join([self.prefilter_line(line, lnum>0)
357 out = '\n'.join([self.prefilter_line(line, lnum>0)
358 for lnum, line in enumerate(llines) ])
358 for lnum, line in enumerate(llines) ])
359 else:
359 else:
360 out = self.prefilter_line(llines[0], continue_prompt)
360 out = self.prefilter_line(llines[0], continue_prompt)
361
361
362 return out
362 return out
363
363
364 #-----------------------------------------------------------------------------
364 #-----------------------------------------------------------------------------
365 # Prefilter transformers
365 # Prefilter transformers
366 #-----------------------------------------------------------------------------
366 #-----------------------------------------------------------------------------
367
367
368
368
369 class PrefilterTransformer(Configurable):
369 class PrefilterTransformer(Configurable):
370 """Transform a line of user input."""
370 """Transform a line of user input."""
371
371
372 priority = Integer(100, config=True)
372 priority = Integer(100, config=True)
373 # 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
374 # move away from checkers and handlers, they will need them.
374 # move away from checkers and handlers, they will need them.
375 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
375 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
376 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
376 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
377 enabled = Bool(True, config=True)
377 enabled = Bool(True, config=True)
378
378
379 def __init__(self, shell=None, prefilter_manager=None, config=None):
379 def __init__(self, shell=None, prefilter_manager=None, config=None):
380 super(PrefilterTransformer, self).__init__(
380 super(PrefilterTransformer, self).__init__(
381 shell=shell, prefilter_manager=prefilter_manager, config=config
381 shell=shell, prefilter_manager=prefilter_manager, config=config
382 )
382 )
383 self.prefilter_manager.register_transformer(self)
383 self.prefilter_manager.register_transformer(self)
384
384
385 def transform(self, line, continue_prompt):
385 def transform(self, line, continue_prompt):
386 """Transform a line, returning the new one."""
386 """Transform a line, returning the new one."""
387 return None
387 return None
388
388
389 def __repr__(self):
389 def __repr__(self):
390 return "<%s(priority=%r, enabled=%r)>" % (
390 return "<%s(priority=%r, enabled=%r)>" % (
391 self.__class__.__name__, self.priority, self.enabled)
391 self.__class__.__name__, self.priority, self.enabled)
392
392
393
393
394 _assign_system_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
395 r'\s*=\s*!(?P<cmd>.*)')
396
397
398 class AssignSystemTransformer(PrefilterTransformer):
399 """Handle the `files = !ls` syntax."""
400
401 priority = Integer(100, config=True)
402
403 def transform(self, line, continue_prompt):
404 m = _assign_system_re.match(line)
405 if m is not None:
406 cmd = m.group('cmd')
407 lhs = m.group('lhs')
408 expr = "sc =%s" % cmd
409 new_line = '%s = get_ipython().magic(%r)' % (lhs, expr)
410 return new_line
411 return line
412
413
414 _assign_magic_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
415 r'\s*=\s*%(?P<cmd>.*)')
416
417 class AssignMagicTransformer(PrefilterTransformer):
418 """Handle the `a = %who` syntax."""
419
420 priority = Integer(200, config=True)
421
422 def transform(self, line, continue_prompt):
423 m = _assign_magic_re.match(line)
424 if m is not None:
425 cmd = m.group('cmd')
426 lhs = m.group('lhs')
427 new_line = '%s = get_ipython().magic(%r)' % (lhs, cmd)
428 return new_line
429 return line
430
431
432 _classic_prompt_re = re.compile(r'(^[ \t]*>>> |^[ \t]*\.\.\. )')
433
434 class PyPromptTransformer(PrefilterTransformer):
435 """Handle inputs that start with '>>> ' syntax."""
436
437 priority = Integer(50, config=True)
438
439 def transform(self, line, continue_prompt):
440
441 if not line or line.isspace() or line.strip() == '...':
442 # This allows us to recognize multiple input prompts separated by
443 # blank lines and pasted in a single chunk, very common when
444 # pasting doctests or long tutorial passages.
445 return ''
446 m = _classic_prompt_re.match(line)
447 if m:
448 return line[len(m.group(0)):]
449 else:
450 return line
451
452
453 _ipy_prompt_re = re.compile(r'(^[ \t]*In \[\d+\]: |^[ \t]*\ \ \ \.\.\.+: )')
454
455 class IPyPromptTransformer(PrefilterTransformer):
456 """Handle inputs that start classic IPython prompt syntax."""
457
458 priority = Integer(50, config=True)
459
460 def transform(self, line, continue_prompt):
461
462 if not line or line.isspace() or line.strip() == '...':
463 # This allows us to recognize multiple input prompts separated by
464 # blank lines and pasted in a single chunk, very common when
465 # pasting doctests or long tutorial passages.
466 return ''
467 m = _ipy_prompt_re.match(line)
468 if m:
469 return line[len(m.group(0)):]
470 else:
471 return line
472
473 #-----------------------------------------------------------------------------
394 #-----------------------------------------------------------------------------
474 # Prefilter checkers
395 # Prefilter checkers
475 #-----------------------------------------------------------------------------
396 #-----------------------------------------------------------------------------
476
397
477
398
478 class PrefilterChecker(Configurable):
399 class PrefilterChecker(Configurable):
479 """Inspect an input line and return a handler for that line."""
400 """Inspect an input line and return a handler for that line."""
480
401
481 priority = Integer(100, config=True)
402 priority = Integer(100, config=True)
482 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
403 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
483 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
404 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
484 enabled = Bool(True, config=True)
405 enabled = Bool(True, config=True)
485
406
486 def __init__(self, shell=None, prefilter_manager=None, config=None):
407 def __init__(self, shell=None, prefilter_manager=None, config=None):
487 super(PrefilterChecker, self).__init__(
408 super(PrefilterChecker, self).__init__(
488 shell=shell, prefilter_manager=prefilter_manager, config=config
409 shell=shell, prefilter_manager=prefilter_manager, config=config
489 )
410 )
490 self.prefilter_manager.register_checker(self)
411 self.prefilter_manager.register_checker(self)
491
412
492 def check(self, line_info):
413 def check(self, line_info):
493 """Inspect line_info and return a handler instance or None."""
414 """Inspect line_info and return a handler instance or None."""
494 return None
415 return None
495
416
496 def __repr__(self):
417 def __repr__(self):
497 return "<%s(priority=%r, enabled=%r)>" % (
418 return "<%s(priority=%r, enabled=%r)>" % (
498 self.__class__.__name__, self.priority, self.enabled)
419 self.__class__.__name__, self.priority, self.enabled)
499
420
500
421
501 class EmacsChecker(PrefilterChecker):
422 class EmacsChecker(PrefilterChecker):
502
423
503 priority = Integer(100, config=True)
424 priority = Integer(100, config=True)
504 enabled = Bool(False, config=True)
425 enabled = Bool(False, config=True)
505
426
506 def check(self, line_info):
427 def check(self, line_info):
507 "Emacs ipython-mode tags certain input lines."
428 "Emacs ipython-mode tags certain input lines."
508 if line_info.line.endswith('# PYTHON-MODE'):
429 if line_info.line.endswith('# PYTHON-MODE'):
509 return self.prefilter_manager.get_handler_by_name('emacs')
430 return self.prefilter_manager.get_handler_by_name('emacs')
510 else:
431 else:
511 return None
432 return None
512
433
513
434
514 class ShellEscapeChecker(PrefilterChecker):
515
516 priority = Integer(200, config=True)
517
518 def check(self, line_info):
519 if line_info.line.lstrip().startswith(ESC_SHELL):
520 return self.prefilter_manager.get_handler_by_name('shell')
521
522
523 class MacroChecker(PrefilterChecker):
435 class MacroChecker(PrefilterChecker):
524
436
525 priority = Integer(250, config=True)
437 priority = Integer(250, config=True)
526
438
527 def check(self, line_info):
439 def check(self, line_info):
528 obj = self.shell.user_ns.get(line_info.ifun)
440 obj = self.shell.user_ns.get(line_info.ifun)
529 if isinstance(obj, Macro):
441 if isinstance(obj, Macro):
530 return self.prefilter_manager.get_handler_by_name('macro')
442 return self.prefilter_manager.get_handler_by_name('macro')
531 else:
443 else:
532 return None
444 return None
533
445
534
446
535 class IPyAutocallChecker(PrefilterChecker):
447 class IPyAutocallChecker(PrefilterChecker):
536
448
537 priority = Integer(300, config=True)
449 priority = Integer(300, config=True)
538
450
539 def check(self, line_info):
451 def check(self, line_info):
540 "Instances of IPyAutocall in user_ns get autocalled immediately"
452 "Instances of IPyAutocall in user_ns get autocalled immediately"
541 obj = self.shell.user_ns.get(line_info.ifun, None)
453 obj = self.shell.user_ns.get(line_info.ifun, None)
542 if isinstance(obj, IPyAutocall):
454 if isinstance(obj, IPyAutocall):
543 obj.set_ip(self.shell)
455 obj.set_ip(self.shell)
544 return self.prefilter_manager.get_handler_by_name('auto')
456 return self.prefilter_manager.get_handler_by_name('auto')
545 else:
457 else:
546 return None
458 return None
547
459
548
460
549 class MultiLineMagicChecker(PrefilterChecker):
550
551 priority = Integer(400, config=True)
552
553 def check(self, line_info):
554 "Allow ! and !! in multi-line statements if multi_line_specials is on"
555 # Note that this one of the only places we check the first character of
556 # ifun and *not* the pre_char. Also note that the below test matches
557 # both ! and !!.
558 if line_info.continue_prompt \
559 and self.prefilter_manager.multi_line_specials:
560 if line_info.esc == ESC_MAGIC:
561 return self.prefilter_manager.get_handler_by_name('magic')
562 else:
563 return None
564
565
566 class EscCharsChecker(PrefilterChecker):
567
568 priority = Integer(500, config=True)
569
570 def check(self, line_info):
571 """Check for escape character and return either a handler to handle it,
572 or None if there is no escape char."""
573 if line_info.line[-1] == ESC_HELP \
574 and line_info.esc != ESC_SHELL \
575 and line_info.esc != ESC_SH_CAP:
576 # the ? can be at the end, but *not* for either kind of shell escape,
577 # because a ? can be a vaild final char in a shell cmd
578 return self.prefilter_manager.get_handler_by_name('help')
579 else:
580 if line_info.pre:
581 return None
582 # This returns None like it should if no handler exists
583 return self.prefilter_manager.get_handler_by_esc(line_info.esc)
584
585
586 class AssignmentChecker(PrefilterChecker):
461 class AssignmentChecker(PrefilterChecker):
587
462
588 priority = Integer(600, config=True)
463 priority = Integer(600, config=True)
589
464
590 def check(self, line_info):
465 def check(self, line_info):
591 """Check to see if user is assigning to a var for the first time, in
466 """Check to see if user is assigning to a var for the first time, in
592 which case we want to avoid any sort of automagic / autocall games.
467 which case we want to avoid any sort of automagic / autocall games.
593
468
594 This allows users to assign to either alias or magic names true python
469 This allows users to assign to either alias or magic names true python
595 variables (the magic/alias systems always take second seat to true
470 variables (the magic/alias systems always take second seat to true
596 python code). E.g. ls='hi', or ls,that=1,2"""
471 python code). E.g. ls='hi', or ls,that=1,2"""
597 if line_info.the_rest:
472 if line_info.the_rest:
598 if line_info.the_rest[0] in '=,':
473 if line_info.the_rest[0] in '=,':
599 return self.prefilter_manager.get_handler_by_name('normal')
474 return self.prefilter_manager.get_handler_by_name('normal')
600 else:
475 else:
601 return None
476 return None
602
477
603
478
604 class AutoMagicChecker(PrefilterChecker):
479 class AutoMagicChecker(PrefilterChecker):
605
480
606 priority = Integer(700, config=True)
481 priority = Integer(700, config=True)
607
482
608 def check(self, line_info):
483 def check(self, line_info):
609 """If the ifun is magic, and automagic is on, run it. Note: normal,
484 """If the ifun is magic, and automagic is on, run it. Note: normal,
610 non-auto magic would already have been triggered via '%' in
485 non-auto magic would already have been triggered via '%' in
611 check_esc_chars. This just checks for automagic. Also, before
486 check_esc_chars. This just checks for automagic. Also, before
612 triggering the magic handler, make sure that there is nothing in the
487 triggering the magic handler, make sure that there is nothing in the
613 user namespace which could shadow it."""
488 user namespace which could shadow it."""
614 if not self.shell.automagic or not self.shell.find_magic(line_info.ifun):
489 if not self.shell.automagic or not self.shell.find_magic(line_info.ifun):
615 return None
490 return None
616
491
617 # We have a likely magic method. Make sure we should actually call it.
492 # We have a likely magic method. Make sure we should actually call it.
618 if line_info.continue_prompt and not self.prefilter_manager.multi_line_specials:
493 if line_info.continue_prompt and not self.prefilter_manager.multi_line_specials:
619 return None
494 return None
620
495
621 head = line_info.ifun.split('.',1)[0]
496 head = line_info.ifun.split('.',1)[0]
622 if is_shadowed(head, self.shell):
497 if is_shadowed(head, self.shell):
623 return None
498 return None
624
499
625 return self.prefilter_manager.get_handler_by_name('magic')
500 return self.prefilter_manager.get_handler_by_name('magic')
626
501
627
502
628 class AliasChecker(PrefilterChecker):
503 class AliasChecker(PrefilterChecker):
629
504
630 priority = Integer(800, config=True)
505 priority = Integer(800, config=True)
631
506
632 def check(self, line_info):
507 def check(self, line_info):
633 "Check if the initital identifier on the line is an alias."
508 "Check if the initital identifier on the line is an alias."
634 # Note: aliases can not contain '.'
509 # Note: aliases can not contain '.'
635 head = line_info.ifun.split('.',1)[0]
510 head = line_info.ifun.split('.',1)[0]
636 if line_info.ifun not in self.shell.alias_manager \
511 if line_info.ifun not in self.shell.alias_manager \
637 or head not in self.shell.alias_manager \
512 or head not in self.shell.alias_manager \
638 or is_shadowed(head, self.shell):
513 or is_shadowed(head, self.shell):
639 return None
514 return None
640
515
641 return self.prefilter_manager.get_handler_by_name('alias')
516 return self.prefilter_manager.get_handler_by_name('alias')
642
517
643
518
644 class PythonOpsChecker(PrefilterChecker):
519 class PythonOpsChecker(PrefilterChecker):
645
520
646 priority = Integer(900, config=True)
521 priority = Integer(900, config=True)
647
522
648 def check(self, line_info):
523 def check(self, line_info):
649 """If the 'rest' of the line begins with a function call or pretty much
524 """If the 'rest' of the line begins with a function call or pretty much
650 any python operator, we should simply execute the line (regardless of
525 any python operator, we should simply execute the line (regardless of
651 whether or not there's a possible autocall expansion). This avoids
526 whether or not there's a possible autocall expansion). This avoids
652 spurious (and very confusing) geattr() accesses."""
527 spurious (and very confusing) geattr() accesses."""
653 if line_info.the_rest and line_info.the_rest[0] in '!=()<>,+*/%^&|':
528 if line_info.the_rest and line_info.the_rest[0] in '!=()<>,+*/%^&|':
654 return self.prefilter_manager.get_handler_by_name('normal')
529 return self.prefilter_manager.get_handler_by_name('normal')
655 else:
530 else:
656 return None
531 return None
657
532
658
533
659 class AutocallChecker(PrefilterChecker):
534 class AutocallChecker(PrefilterChecker):
660
535
661 priority = Integer(1000, config=True)
536 priority = Integer(1000, config=True)
662
537
663 function_name_regexp = CRegExp(re_fun_name, config=True,
538 function_name_regexp = CRegExp(re_fun_name, config=True,
664 help="RegExp to identify potential function names.")
539 help="RegExp to identify potential function names.")
665 exclude_regexp = CRegExp(re_exclude_auto, config=True,
540 exclude_regexp = CRegExp(re_exclude_auto, config=True,
666 help="RegExp to exclude strings with this start from autocalling.")
541 help="RegExp to exclude strings with this start from autocalling.")
667
542
668 def check(self, line_info):
543 def check(self, line_info):
669 "Check if the initial word/function is callable and autocall is on."
544 "Check if the initial word/function is callable and autocall is on."
670 if not self.shell.autocall:
545 if not self.shell.autocall:
671 return None
546 return None
672
547
673 oinfo = line_info.ofind(self.shell) # This can mutate state via getattr
548 oinfo = line_info.ofind(self.shell) # This can mutate state via getattr
674 if not oinfo['found']:
549 if not oinfo['found']:
675 return None
550 return None
676
551
677 if callable(oinfo['obj']) \
552 if callable(oinfo['obj']) \
678 and (not self.exclude_regexp.match(line_info.the_rest)) \
553 and (not self.exclude_regexp.match(line_info.the_rest)) \
679 and self.function_name_regexp.match(line_info.ifun):
554 and self.function_name_regexp.match(line_info.ifun):
680 return self.prefilter_manager.get_handler_by_name('auto')
555 return self.prefilter_manager.get_handler_by_name('auto')
681 else:
556 else:
682 return None
557 return None
683
558
684
559
685 #-----------------------------------------------------------------------------
560 #-----------------------------------------------------------------------------
686 # Prefilter handlers
561 # Prefilter handlers
687 #-----------------------------------------------------------------------------
562 #-----------------------------------------------------------------------------
688
563
689
564
690 class PrefilterHandler(Configurable):
565 class PrefilterHandler(Configurable):
691
566
692 handler_name = Unicode('normal')
567 handler_name = Unicode('normal')
693 esc_strings = List([])
568 esc_strings = List([])
694 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
569 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
695 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
570 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
696
571
697 def __init__(self, shell=None, prefilter_manager=None, config=None):
572 def __init__(self, shell=None, prefilter_manager=None, config=None):
698 super(PrefilterHandler, self).__init__(
573 super(PrefilterHandler, self).__init__(
699 shell=shell, prefilter_manager=prefilter_manager, config=config
574 shell=shell, prefilter_manager=prefilter_manager, config=config
700 )
575 )
701 self.prefilter_manager.register_handler(
576 self.prefilter_manager.register_handler(
702 self.handler_name,
577 self.handler_name,
703 self,
578 self,
704 self.esc_strings
579 self.esc_strings
705 )
580 )
706
581
707 def handle(self, line_info):
582 def handle(self, line_info):
708 # print "normal: ", line_info
583 # print "normal: ", line_info
709 """Handle normal input lines. Use as a template for handlers."""
584 """Handle normal input lines. Use as a template for handlers."""
710
585
711 # With autoindent on, we need some way to exit the input loop, and I
586 # With autoindent on, we need some way to exit the input loop, and I
712 # don't want to force the user to have to backspace all the way to
587 # don't want to force the user to have to backspace all the way to
713 # clear the line. The rule will be in this case, that either two
588 # clear the line. The rule will be in this case, that either two
714 # lines of pure whitespace in a row, or a line of pure whitespace but
589 # lines of pure whitespace in a row, or a line of pure whitespace but
715 # of a size different to the indent level, will exit the input loop.
590 # of a size different to the indent level, will exit the input loop.
716 line = line_info.line
591 line = line_info.line
717 continue_prompt = line_info.continue_prompt
592 continue_prompt = line_info.continue_prompt
718
593
719 if (continue_prompt and
594 if (continue_prompt and
720 self.shell.autoindent and
595 self.shell.autoindent and
721 line.isspace() and
596 line.isspace() and
722 0 < abs(len(line) - self.shell.indent_current_nsp) <= 2):
597 0 < abs(len(line) - self.shell.indent_current_nsp) <= 2):
723 line = ''
598 line = ''
724
599
725 return line
600 return line
726
601
727 def __str__(self):
602 def __str__(self):
728 return "<%s(name=%s)>" % (self.__class__.__name__, self.handler_name)
603 return "<%s(name=%s)>" % (self.__class__.__name__, self.handler_name)
729
604
730
605
731 class AliasHandler(PrefilterHandler):
606 class AliasHandler(PrefilterHandler):
732
607
733 handler_name = Unicode('alias')
608 handler_name = Unicode('alias')
734
609
735 def handle(self, line_info):
610 def handle(self, line_info):
736 """Handle alias input lines. """
611 """Handle alias input lines. """
737 transformed = self.shell.alias_manager.expand_aliases(line_info.ifun,line_info.the_rest)
612 transformed = self.shell.alias_manager.expand_aliases(line_info.ifun,line_info.the_rest)
738 # pre is needed, because it carries the leading whitespace. Otherwise
613 # pre is needed, because it carries the leading whitespace. Otherwise
739 # aliases won't work in indented sections.
614 # aliases won't work in indented sections.
740 line_out = '%sget_ipython().system(%r)' % (line_info.pre_whitespace, transformed)
615 line_out = '%sget_ipython().system(%r)' % (line_info.pre_whitespace, transformed)
741
616
742 return line_out
617 return line_out
743
618
744
619
745 class ShellEscapeHandler(PrefilterHandler):
746
747 handler_name = Unicode('shell')
748 esc_strings = List([ESC_SHELL, ESC_SH_CAP])
749
750 def handle(self, line_info):
751 """Execute the line in a shell, empty return value"""
752 magic_handler = self.prefilter_manager.get_handler_by_name('magic')
753
754 line = line_info.line
755 if line.lstrip().startswith(ESC_SH_CAP):
756 # rewrite LineInfo's line, ifun and the_rest to properly hold the
757 # call to %sx and the actual command to be executed, so
758 # handle_magic can work correctly. Note that this works even if
759 # the line is indented, so it handles multi_line_specials
760 # properly.
761 new_rest = line.lstrip()[2:]
762 line_info.line = '%ssx %s' % (ESC_MAGIC, new_rest)
763 line_info.ifun = 'sx'
764 line_info.the_rest = new_rest
765 return magic_handler.handle(line_info)
766 else:
767 cmd = line.lstrip().lstrip(ESC_SHELL)
768 line_out = '%sget_ipython().system(%r)' % (line_info.pre_whitespace, cmd)
769 return line_out
770
771
772 class MacroHandler(PrefilterHandler):
620 class MacroHandler(PrefilterHandler):
773 handler_name = Unicode("macro")
621 handler_name = Unicode("macro")
774
622
775 def handle(self, line_info):
623 def handle(self, line_info):
776 obj = self.shell.user_ns.get(line_info.ifun)
624 obj = self.shell.user_ns.get(line_info.ifun)
777 pre_space = line_info.pre_whitespace
625 pre_space = line_info.pre_whitespace
778 line_sep = "\n" + pre_space
626 line_sep = "\n" + pre_space
779 return pre_space + line_sep.join(obj.value.splitlines())
627 return pre_space + line_sep.join(obj.value.splitlines())
780
628
781
629
782 class MagicHandler(PrefilterHandler):
630 class MagicHandler(PrefilterHandler):
783
631
784 handler_name = Unicode('magic')
632 handler_name = Unicode('magic')
785 esc_strings = List([ESC_MAGIC])
633 esc_strings = List([ESC_MAGIC])
786
634
787 def handle(self, line_info):
635 def handle(self, line_info):
788 """Execute magic functions."""
636 """Execute magic functions."""
789 ifun = line_info.ifun
637 ifun = line_info.ifun
790 the_rest = line_info.the_rest
638 the_rest = line_info.the_rest
791 cmd = '%sget_ipython().magic(%r)' % (line_info.pre_whitespace,
639 cmd = '%sget_ipython().magic(%r)' % (line_info.pre_whitespace,
792 (ifun + " " + the_rest))
640 (ifun + " " + the_rest))
793 return cmd
641 return cmd
794
642
795
643
796 class AutoHandler(PrefilterHandler):
644 class AutoHandler(PrefilterHandler):
797
645
798 handler_name = Unicode('auto')
646 handler_name = Unicode('auto')
799 esc_strings = List([ESC_PAREN, ESC_QUOTE, ESC_QUOTE2])
647 esc_strings = List([ESC_PAREN, ESC_QUOTE, ESC_QUOTE2])
800
648
801 def handle(self, line_info):
649 def handle(self, line_info):
802 """Handle lines which can be auto-executed, quoting if requested."""
650 """Handle lines which can be auto-executed, quoting if requested."""
803 line = line_info.line
651 line = line_info.line
804 ifun = line_info.ifun
652 ifun = line_info.ifun
805 the_rest = line_info.the_rest
653 the_rest = line_info.the_rest
806 pre = line_info.pre
654 pre = line_info.pre
807 esc = line_info.esc
655 esc = line_info.esc
808 continue_prompt = line_info.continue_prompt
656 continue_prompt = line_info.continue_prompt
809 obj = line_info.ofind(self.shell)['obj']
657 obj = line_info.ofind(self.shell)['obj']
810 #print 'pre <%s> ifun <%s> rest <%s>' % (pre,ifun,the_rest) # dbg
658 #print 'pre <%s> ifun <%s> rest <%s>' % (pre,ifun,the_rest) # dbg
811
659
812 # This should only be active for single-line input!
660 # This should only be active for single-line input!
813 if continue_prompt:
661 if continue_prompt:
814 return line
662 return line
815
663
816 force_auto = isinstance(obj, IPyAutocall)
664 force_auto = isinstance(obj, IPyAutocall)
817
665
818 # User objects sometimes raise exceptions on attribute access other
666 # User objects sometimes raise exceptions on attribute access other
819 # than AttributeError (we've seen it in the past), so it's safest to be
667 # than AttributeError (we've seen it in the past), so it's safest to be
820 # ultra-conservative here and catch all.
668 # ultra-conservative here and catch all.
821 try:
669 try:
822 auto_rewrite = obj.rewrite
670 auto_rewrite = obj.rewrite
823 except Exception:
671 except Exception:
824 auto_rewrite = True
672 auto_rewrite = True
825
673
826 if esc == ESC_QUOTE:
674 if esc == ESC_QUOTE:
827 # Auto-quote splitting on whitespace
675 # Auto-quote splitting on whitespace
828 newcmd = '%s("%s")' % (ifun,'", "'.join(the_rest.split()) )
676 newcmd = '%s("%s")' % (ifun,'", "'.join(the_rest.split()) )
829 elif esc == ESC_QUOTE2:
677 elif esc == ESC_QUOTE2:
830 # Auto-quote whole string
678 # Auto-quote whole string
831 newcmd = '%s("%s")' % (ifun,the_rest)
679 newcmd = '%s("%s")' % (ifun,the_rest)
832 elif esc == ESC_PAREN:
680 elif esc == ESC_PAREN:
833 newcmd = '%s(%s)' % (ifun,",".join(the_rest.split()))
681 newcmd = '%s(%s)' % (ifun,",".join(the_rest.split()))
834 else:
682 else:
835 # Auto-paren.
683 # Auto-paren.
836 if force_auto:
684 if force_auto:
837 # Don't rewrite if it is already a call.
685 # Don't rewrite if it is already a call.
838 do_rewrite = not the_rest.startswith('(')
686 do_rewrite = not the_rest.startswith('(')
839 else:
687 else:
840 if not the_rest:
688 if not the_rest:
841 # We only apply it to argument-less calls if the autocall
689 # We only apply it to argument-less calls if the autocall
842 # parameter is set to 2.
690 # parameter is set to 2.
843 do_rewrite = (self.shell.autocall >= 2)
691 do_rewrite = (self.shell.autocall >= 2)
844 elif the_rest.startswith('[') and hasattr(obj, '__getitem__'):
692 elif the_rest.startswith('[') and hasattr(obj, '__getitem__'):
845 # Don't autocall in this case: item access for an object
693 # Don't autocall in this case: item access for an object
846 # which is BOTH callable and implements __getitem__.
694 # which is BOTH callable and implements __getitem__.
847 do_rewrite = False
695 do_rewrite = False
848 else:
696 else:
849 do_rewrite = True
697 do_rewrite = True
850
698
851 # Figure out the rewritten command
699 # Figure out the rewritten command
852 if do_rewrite:
700 if do_rewrite:
853 if the_rest.endswith(';'):
701 if the_rest.endswith(';'):
854 newcmd = '%s(%s);' % (ifun.rstrip(),the_rest[:-1])
702 newcmd = '%s(%s);' % (ifun.rstrip(),the_rest[:-1])
855 else:
703 else:
856 newcmd = '%s(%s)' % (ifun.rstrip(), the_rest)
704 newcmd = '%s(%s)' % (ifun.rstrip(), the_rest)
857 else:
705 else:
858 normal_handler = self.prefilter_manager.get_handler_by_name('normal')
706 normal_handler = self.prefilter_manager.get_handler_by_name('normal')
859 return normal_handler.handle(line_info)
707 return normal_handler.handle(line_info)
860
708
861 # Display the rewritten call
709 # Display the rewritten call
862 if auto_rewrite:
710 if auto_rewrite:
863 self.shell.auto_rewrite_input(newcmd)
711 self.shell.auto_rewrite_input(newcmd)
864
712
865 return newcmd
713 return newcmd
866
714
867
715
868 class HelpHandler(PrefilterHandler):
869
870 handler_name = Unicode('help')
871 esc_strings = List([ESC_HELP])
872
873 def handle(self, line_info):
874 """Try to get some help for the object.
875
876 obj? or ?obj -> basic information.
877 obj?? or ??obj -> more details.
878 """
879 normal_handler = self.prefilter_manager.get_handler_by_name('normal')
880 line = line_info.line
881 # We need to make sure that we don't process lines which would be
882 # otherwise valid python, such as "x=1 # what?"
883 try:
884 codeop.compile_command(line)
885 except SyntaxError:
886 # We should only handle as help stuff which is NOT valid syntax
887 if line[0]==ESC_HELP:
888 line = line[1:]
889 elif line[-1]==ESC_HELP:
890 line = line[:-1]
891 if line:
892 #print 'line:<%r>' % line # dbg
893 self.shell.magic('pinfo %s' % line_info.ifun)
894 else:
895 self.shell.show_usage()
896 return '' # Empty string is needed here!
897 except:
898 raise
899 # Pass any other exceptions through to the normal handler
900 return normal_handler.handle(line_info)
901 else:
902 # If the code compiles ok, we should handle it normally
903 return normal_handler.handle(line_info)
904
905
906 class EmacsHandler(PrefilterHandler):
716 class EmacsHandler(PrefilterHandler):
907
717
908 handler_name = Unicode('emacs')
718 handler_name = Unicode('emacs')
909 esc_strings = List([])
719 esc_strings = List([])
910
720
911 def handle(self, line_info):
721 def handle(self, line_info):
912 """Handle input lines marked by python-mode."""
722 """Handle input lines marked by python-mode."""
913
723
914 # Currently, nothing is done. Later more functionality can be added
724 # Currently, nothing is done. Later more functionality can be added
915 # here if needed.
725 # here if needed.
916
726
917 # The input cache shouldn't be updated
727 # The input cache shouldn't be updated
918 return line_info.line
728 return line_info.line
919
729
920
730
921 #-----------------------------------------------------------------------------
731 #-----------------------------------------------------------------------------
922 # Defaults
732 # Defaults
923 #-----------------------------------------------------------------------------
733 #-----------------------------------------------------------------------------
924
734
925
735
926 _default_transformers = [
736 _default_transformers = [
927 AssignSystemTransformer,
928 AssignMagicTransformer,
929 PyPromptTransformer,
930 IPyPromptTransformer,
931 ]
737 ]
932
738
933 _default_checkers = [
739 _default_checkers = [
934 EmacsChecker,
740 EmacsChecker,
935 ShellEscapeChecker,
936 MacroChecker,
741 MacroChecker,
937 IPyAutocallChecker,
742 IPyAutocallChecker,
938 MultiLineMagicChecker,
939 EscCharsChecker,
940 AssignmentChecker,
743 AssignmentChecker,
941 AutoMagicChecker,
744 AutoMagicChecker,
942 AliasChecker,
745 AliasChecker,
943 PythonOpsChecker,
746 PythonOpsChecker,
944 AutocallChecker
747 AutocallChecker
945 ]
748 ]
946
749
947 _default_handlers = [
750 _default_handlers = [
948 PrefilterHandler,
751 PrefilterHandler,
949 AliasHandler,
752 AliasHandler,
950 ShellEscapeHandler,
951 MacroHandler,
753 MacroHandler,
952 MagicHandler,
754 MagicHandler,
953 AutoHandler,
755 AutoHandler,
954 HelpHandler,
955 EmacsHandler
756 EmacsHandler
956 ]
757 ]
@@ -1,169 +1,119 b''
1 """Tests for input handlers.
1 """Tests for input handlers.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Module imports
4 # Module imports
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6
6
7 # third party
7 # third party
8 import nose.tools as nt
8 import nose.tools as nt
9
9
10 # our own packages
10 # our own packages
11 from IPython.core import autocall
11 from IPython.core import autocall
12 from IPython.testing import tools as tt
12 from IPython.testing import tools as tt
13 from IPython.testing.globalipapp import get_ipython
13 from IPython.testing.globalipapp import get_ipython
14 from IPython.utils import py3compat
14 from IPython.utils import py3compat
15
15
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 # Globals
17 # Globals
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19
19
20 # Get the public instance of IPython
20 # Get the public instance of IPython
21 ip = get_ipython()
21 ip = get_ipython()
22
22
23 failures = []
23 failures = []
24 num_tests = 0
24 num_tests = 0
25
25
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 # Test functions
27 # Test functions
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29
29
30 class CallableIndexable(object):
30 class CallableIndexable(object):
31 def __getitem__(self, idx): return True
31 def __getitem__(self, idx): return True
32 def __call__(self, *args, **kws): return True
32 def __call__(self, *args, **kws): return True
33
33
34
34
35 class Autocallable(autocall.IPyAutocall):
35 class Autocallable(autocall.IPyAutocall):
36 def __call__(self):
36 def __call__(self):
37 return "called"
37 return "called"
38
38
39
39
40 def run(tests):
40 def run(tests):
41 """Loop through a list of (pre, post) inputs, where pre is the string
41 """Loop through a list of (pre, post) inputs, where pre is the string
42 handed to ipython, and post is how that string looks after it's been
42 handed to ipython, and post is how that string looks after it's been
43 transformed (i.e. ipython's notion of _i)"""
43 transformed (i.e. ipython's notion of _i)"""
44 tt.check_pairs(ip.prefilter_manager.prefilter_lines, tests)
44 tt.check_pairs(ip.prefilter_manager.prefilter_lines, tests)
45
45
46
46
47 def test_handlers():
47 def test_handlers():
48 # alias expansion
48 # alias expansion
49
49
50 # We're using 'true' as our syscall of choice because it doesn't
50 # We're using 'true' as our syscall of choice because it doesn't
51 # write anything to stdout.
51 # write anything to stdout.
52
52
53 # Turn off actual execution of aliases, because it's noisy
53 # Turn off actual execution of aliases, because it's noisy
54 old_system_cmd = ip.system
54 old_system_cmd = ip.system
55 ip.system = lambda cmd: None
55 ip.system = lambda cmd: None
56
56
57
57
58 ip.alias_manager.alias_table['an_alias'] = (0, 'true')
58 ip.alias_manager.alias_table['an_alias'] = (0, 'true')
59 # These are useful for checking a particular recursive alias issue
59 # These are useful for checking a particular recursive alias issue
60 ip.alias_manager.alias_table['top'] = (0, 'd:/cygwin/top')
60 ip.alias_manager.alias_table['top'] = (0, 'd:/cygwin/top')
61 ip.alias_manager.alias_table['d'] = (0, 'true')
61 ip.alias_manager.alias_table['d'] = (0, 'true')
62 run([(i,py3compat.u_format(o)) for i,o in \
62 run([(i,py3compat.u_format(o)) for i,o in \
63 [("an_alias", "get_ipython().system({u}'true ')"), # alias
63 [("an_alias", "get_ipython().system({u}'true ')"), # alias
64 # Below: recursive aliases should expand whitespace-surrounded
64 # Below: recursive aliases should expand whitespace-surrounded
65 # chars, *not* initial chars which happen to be aliases:
65 # chars, *not* initial chars which happen to be aliases:
66 ("top", "get_ipython().system({u}'d:/cygwin/top ')"),
66 ("top", "get_ipython().system({u}'d:/cygwin/top ')"),
67 ]])
67 ]])
68 ip.system = old_system_cmd
68 ip.system = old_system_cmd
69
69
70 call_idx = CallableIndexable()
70 call_idx = CallableIndexable()
71 ip.user_ns['call_idx'] = call_idx
71 ip.user_ns['call_idx'] = call_idx
72
72
73 # For many of the below, we're also checking that leading whitespace
73 # For many of the below, we're also checking that leading whitespace
74 # turns off the esc char, which it should unless there is a continuation
74 # turns off the esc char, which it should unless there is a continuation
75 # line.
75 # line.
76 run([(i,py3compat.u_format(o)) for i,o in \
76 run([(i,py3compat.u_format(o)) for i,o in \
77 [('"no change"', '"no change"'), # normal
77 [('"no change"', '"no change"'), # normal
78 (u"!true", "get_ipython().system({u}'true')"), # shell_escapes
79 (u"!! true", "get_ipython().magic({u}'sx true')"), # shell_escapes + magic
80 (u"!!true", "get_ipython().magic({u}'sx true')"), # shell_escapes + magic
81 (u"%lsmagic", "get_ipython().magic({u}'lsmagic ')"), # magic
82 (u"lsmagic", "get_ipython().magic({u}'lsmagic ')"), # magic
78 (u"lsmagic", "get_ipython().magic({u}'lsmagic ')"), # magic
83 #("a = b # PYTHON-MODE", '_i'), # emacs -- avoids _in cache
79 #("a = b # PYTHON-MODE", '_i'), # emacs -- avoids _in cache
84
85 # post-esc-char whitespace goes inside
86 (u"! true", "get_ipython().system({u}' true')"),
87
88 # handle_help
89
90 # These are weak tests -- just looking at what the help handlers
91 # logs, which is not how it really does its work. But it still
92 # lets us check the key paths through the handler.
93
94 ("x=1 # what?", "x=1 # what?"), # no help if valid python
95 ]])
96
97 # multi_line_specials
98 ip.prefilter_manager.multi_line_specials = False
99 # W/ multi_line_specials off, leading ws kills esc chars/autoexpansion
100 run([
101 (u'if 1:\n !true', u'if 1:\n !true'),
102 (u'if 1:\n lsmagic', u'if 1:\n lsmagic'),
103 (u'if 1:\n an_alias', u'if 1:\n an_alias'),
104 ])
105
106 ip.prefilter_manager.multi_line_specials = True
107 # initial indents must be preserved.
108 run([(i,py3compat.u_format(o)) for i,o in \
109 [(u'if 1:\n !true', "if 1:\n get_ipython().system({u}'true')"),
110 (u'if 2:\n lsmagic', "if 2:\n get_ipython().magic({u}'lsmagic ')"),
111 (u'if 1:\n an_alias', "if 1:\n get_ipython().system({u}'true ')"),
112 # Weird one
113 (u'if 1:\n !!true', "if 1:\n get_ipython().magic({u}'sx true')"),
114
115 # Even with m_l_s on, autocall is off even with special chars
116 ('if 1:\n /fun 1 2', 'if 1:\n /fun 1 2'),
117 ('if 1:\n ;fun 1 2', 'if 1:\n ;fun 1 2'),
118 ('if 1:\n ,fun 1 2', 'if 1:\n ,fun 1 2'),
119 ('if 1:\n ?fun 1 2', 'if 1:\n ?fun 1 2'),
120 # What about !!
121 ]])
80 ]])
122
81
123 # Objects which are instances of IPyAutocall are *always* autocalled
82 # Objects which are instances of IPyAutocall are *always* autocalled
124 autocallable = Autocallable()
83 autocallable = Autocallable()
125 ip.user_ns['autocallable'] = autocallable
84 ip.user_ns['autocallable'] = autocallable
126
85
127 # auto
86 # auto
128 ip.magic('autocall 0')
87 ip.magic('autocall 0')
129 # Only explicit escapes or instances of IPyAutocallable should get
88 # Only explicit escapes or instances of IPyAutocallable should get
130 # expanded
89 # expanded
131 run([
90 run([
132 ('len "abc"', 'len "abc"'),
91 ('len "abc"', 'len "abc"'),
133 ('autocallable', 'autocallable()'),
92 ('autocallable', 'autocallable()'),
134 # Don't add extra brackets (gh-1117)
93 # Don't add extra brackets (gh-1117)
135 ('autocallable()', 'autocallable()'),
94 ('autocallable()', 'autocallable()'),
136 (",list 1 2 3", 'list("1", "2", "3")'),
137 (";list 1 2 3", 'list("1 2 3")'),
138 ("/len range(1,4)", 'len(range(1,4))'),
139 ])
95 ])
140 ip.magic('autocall 1')
96 ip.magic('autocall 1')
141 run([
97 run([
142 (",list 1 2 3", 'list("1", "2", "3")'),
143 (";list 1 2 3", 'list("1 2 3")'),
144 ("/len range(1,4)", 'len(range(1,4))'),
145 ('len "abc"', 'len("abc")'),
98 ('len "abc"', 'len("abc")'),
146 ('len "abc";', 'len("abc");'), # ; is special -- moves out of parens
99 ('len "abc";', 'len("abc");'), # ; is special -- moves out of parens
147 # Autocall is turned off if first arg is [] and the object
100 # Autocall is turned off if first arg is [] and the object
148 # is both callable and indexable. Like so:
101 # is both callable and indexable. Like so:
149 ('len [1,2]', 'len([1,2])'), # len doesn't support __getitem__...
102 ('len [1,2]', 'len([1,2])'), # len doesn't support __getitem__...
150 ('call_idx [1]', 'call_idx [1]'), # call_idx *does*..
103 ('call_idx [1]', 'call_idx [1]'), # call_idx *does*..
151 ('call_idx 1', 'call_idx(1)'),
104 ('call_idx 1', 'call_idx(1)'),
152 ('len', 'len'), # only at 2 does it auto-call on single args
105 ('len', 'len'), # only at 2 does it auto-call on single args
153 ])
106 ])
154 ip.magic('autocall 2')
107 ip.magic('autocall 2')
155 run([
108 run([
156 (",list 1 2 3", 'list("1", "2", "3")'),
157 (";list 1 2 3", 'list("1 2 3")'),
158 ("/len range(1,4)", 'len(range(1,4))'),
159 ('len "abc"', 'len("abc")'),
109 ('len "abc"', 'len("abc")'),
160 ('len "abc";', 'len("abc");'),
110 ('len "abc";', 'len("abc");'),
161 ('len [1,2]', 'len([1,2])'),
111 ('len [1,2]', 'len([1,2])'),
162 ('call_idx [1]', 'call_idx [1]'),
112 ('call_idx [1]', 'call_idx [1]'),
163 ('call_idx 1', 'call_idx(1)'),
113 ('call_idx 1', 'call_idx(1)'),
164 # This is what's different:
114 # This is what's different:
165 ('len', 'len()'), # only at 2 does it auto-call on single args
115 ('len', 'len()'), # only at 2 does it auto-call on single args
166 ])
116 ])
167 ip.magic('autocall 1')
117 ip.magic('autocall 1')
168
118
169 nt.assert_equal(failures, [])
119 nt.assert_equal(failures, [])
@@ -1,798 +1,794 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tests for various magic functions.
2 """Tests for various magic functions.
3
3
4 Needs to be run by nose (to make ipython session available).
4 Needs to be run by nose (to make ipython session available).
5 """
5 """
6 from __future__ import absolute_import
6 from __future__ import absolute_import
7
7
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Imports
9 # Imports
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11
11
12 import io
12 import io
13 import os
13 import os
14 import sys
14 import sys
15 from StringIO import StringIO
15 from StringIO import StringIO
16 from unittest import TestCase
16 from unittest import TestCase
17
17
18 try:
18 try:
19 from importlib import invalidate_caches # Required from Python 3.3
19 from importlib import invalidate_caches # Required from Python 3.3
20 except ImportError:
20 except ImportError:
21 def invalidate_caches():
21 def invalidate_caches():
22 pass
22 pass
23
23
24 import nose.tools as nt
24 import nose.tools as nt
25
25
26 from IPython.core import magic
26 from IPython.core import magic
27 from IPython.core.magic import (Magics, magics_class, line_magic,
27 from IPython.core.magic import (Magics, magics_class, line_magic,
28 cell_magic, line_cell_magic,
28 cell_magic, line_cell_magic,
29 register_line_magic, register_cell_magic,
29 register_line_magic, register_cell_magic,
30 register_line_cell_magic)
30 register_line_cell_magic)
31 from IPython.core.magics import execution, script
31 from IPython.core.magics import execution, script
32 from IPython.nbformat.v3.tests.nbexamples import nb0
32 from IPython.nbformat.v3.tests.nbexamples import nb0
33 from IPython.nbformat import current
33 from IPython.nbformat import current
34 from IPython.testing import decorators as dec
34 from IPython.testing import decorators as dec
35 from IPython.testing import tools as tt
35 from IPython.testing import tools as tt
36 from IPython.utils import py3compat
36 from IPython.utils import py3compat
37 from IPython.utils.tempdir import TemporaryDirectory
37 from IPython.utils.tempdir import TemporaryDirectory
38 from IPython.utils.process import find_cmd
38 from IPython.utils.process import find_cmd
39
39
40 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
41 # Test functions begin
41 # Test functions begin
42 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
43
43
44 @magic.magics_class
44 @magic.magics_class
45 class DummyMagics(magic.Magics): pass
45 class DummyMagics(magic.Magics): pass
46
46
47 def test_rehashx():
47 def test_rehashx():
48 # clear up everything
48 # clear up everything
49 _ip = get_ipython()
49 _ip = get_ipython()
50 _ip.alias_manager.alias_table.clear()
50 _ip.alias_manager.alias_table.clear()
51 del _ip.db['syscmdlist']
51 del _ip.db['syscmdlist']
52
52
53 _ip.magic('rehashx')
53 _ip.magic('rehashx')
54 # Practically ALL ipython development systems will have more than 10 aliases
54 # Practically ALL ipython development systems will have more than 10 aliases
55
55
56 yield (nt.assert_true, len(_ip.alias_manager.alias_table) > 10)
56 yield (nt.assert_true, len(_ip.alias_manager.alias_table) > 10)
57 for key, val in _ip.alias_manager.alias_table.iteritems():
57 for key, val in _ip.alias_manager.alias_table.iteritems():
58 # we must strip dots from alias names
58 # we must strip dots from alias names
59 nt.assert_true('.' not in key)
59 nt.assert_true('.' not in key)
60
60
61 # rehashx must fill up syscmdlist
61 # rehashx must fill up syscmdlist
62 scoms = _ip.db['syscmdlist']
62 scoms = _ip.db['syscmdlist']
63 yield (nt.assert_true, len(scoms) > 10)
63 yield (nt.assert_true, len(scoms) > 10)
64
64
65
65
66 def test_magic_parse_options():
66 def test_magic_parse_options():
67 """Test that we don't mangle paths when parsing magic options."""
67 """Test that we don't mangle paths when parsing magic options."""
68 ip = get_ipython()
68 ip = get_ipython()
69 path = 'c:\\x'
69 path = 'c:\\x'
70 m = DummyMagics(ip)
70 m = DummyMagics(ip)
71 opts = m.parse_options('-f %s' % path,'f:')[0]
71 opts = m.parse_options('-f %s' % path,'f:')[0]
72 # argv splitting is os-dependent
72 # argv splitting is os-dependent
73 if os.name == 'posix':
73 if os.name == 'posix':
74 expected = 'c:x'
74 expected = 'c:x'
75 else:
75 else:
76 expected = path
76 expected = path
77 nt.assert_equal(opts['f'], expected)
77 nt.assert_equal(opts['f'], expected)
78
78
79 def test_magic_parse_long_options():
79 def test_magic_parse_long_options():
80 """Magic.parse_options can handle --foo=bar long options"""
80 """Magic.parse_options can handle --foo=bar long options"""
81 ip = get_ipython()
81 ip = get_ipython()
82 m = DummyMagics(ip)
82 m = DummyMagics(ip)
83 opts, _ = m.parse_options('--foo --bar=bubble', 'a', 'foo', 'bar=')
83 opts, _ = m.parse_options('--foo --bar=bubble', 'a', 'foo', 'bar=')
84 nt.assert_true('foo' in opts)
84 nt.assert_true('foo' in opts)
85 nt.assert_true('bar' in opts)
85 nt.assert_true('bar' in opts)
86 nt.assert_true(opts['bar'], "bubble")
86 nt.assert_true(opts['bar'], "bubble")
87
87
88
88
89 @dec.skip_without('sqlite3')
89 @dec.skip_without('sqlite3')
90 def doctest_hist_f():
90 def doctest_hist_f():
91 """Test %hist -f with temporary filename.
91 """Test %hist -f with temporary filename.
92
92
93 In [9]: import tempfile
93 In [9]: import tempfile
94
94
95 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
95 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
96
96
97 In [11]: %hist -nl -f $tfile 3
97 In [11]: %hist -nl -f $tfile 3
98
98
99 In [13]: import os; os.unlink(tfile)
99 In [13]: import os; os.unlink(tfile)
100 """
100 """
101
101
102
102
103 @dec.skip_without('sqlite3')
103 @dec.skip_without('sqlite3')
104 def doctest_hist_r():
104 def doctest_hist_r():
105 """Test %hist -r
105 """Test %hist -r
106
106
107 XXX - This test is not recording the output correctly. For some reason, in
107 XXX - This test is not recording the output correctly. For some reason, in
108 testing mode the raw history isn't getting populated. No idea why.
108 testing mode the raw history isn't getting populated. No idea why.
109 Disabling the output checking for now, though at least we do run it.
109 Disabling the output checking for now, though at least we do run it.
110
110
111 In [1]: 'hist' in _ip.lsmagic()
111 In [1]: 'hist' in _ip.lsmagic()
112 Out[1]: True
112 Out[1]: True
113
113
114 In [2]: x=1
114 In [2]: x=1
115
115
116 In [3]: %hist -rl 2
116 In [3]: %hist -rl 2
117 x=1 # random
117 x=1 # random
118 %hist -r 2
118 %hist -r 2
119 """
119 """
120
120
121
121
122 @dec.skip_without('sqlite3')
122 @dec.skip_without('sqlite3')
123 def doctest_hist_op():
123 def doctest_hist_op():
124 """Test %hist -op
124 """Test %hist -op
125
125
126 In [1]: class b(float):
126 In [1]: class b(float):
127 ...: pass
127 ...: pass
128 ...:
128 ...:
129
129
130 In [2]: class s(object):
130 In [2]: class s(object):
131 ...: def __str__(self):
131 ...: def __str__(self):
132 ...: return 's'
132 ...: return 's'
133 ...:
133 ...:
134
134
135 In [3]:
135 In [3]:
136
136
137 In [4]: class r(b):
137 In [4]: class r(b):
138 ...: def __repr__(self):
138 ...: def __repr__(self):
139 ...: return 'r'
139 ...: return 'r'
140 ...:
140 ...:
141
141
142 In [5]: class sr(s,r): pass
142 In [5]: class sr(s,r): pass
143 ...:
143 ...:
144
144
145 In [6]:
145 In [6]:
146
146
147 In [7]: bb=b()
147 In [7]: bb=b()
148
148
149 In [8]: ss=s()
149 In [8]: ss=s()
150
150
151 In [9]: rr=r()
151 In [9]: rr=r()
152
152
153 In [10]: ssrr=sr()
153 In [10]: ssrr=sr()
154
154
155 In [11]: 4.5
155 In [11]: 4.5
156 Out[11]: 4.5
156 Out[11]: 4.5
157
157
158 In [12]: str(ss)
158 In [12]: str(ss)
159 Out[12]: 's'
159 Out[12]: 's'
160
160
161 In [13]:
161 In [13]:
162
162
163 In [14]: %hist -op
163 In [14]: %hist -op
164 >>> class b:
164 >>> class b:
165 ... pass
165 ... pass
166 ...
166 ...
167 >>> class s(b):
167 >>> class s(b):
168 ... def __str__(self):
168 ... def __str__(self):
169 ... return 's'
169 ... return 's'
170 ...
170 ...
171 >>>
171 >>>
172 >>> class r(b):
172 >>> class r(b):
173 ... def __repr__(self):
173 ... def __repr__(self):
174 ... return 'r'
174 ... return 'r'
175 ...
175 ...
176 >>> class sr(s,r): pass
176 >>> class sr(s,r): pass
177 >>>
177 >>>
178 >>> bb=b()
178 >>> bb=b()
179 >>> ss=s()
179 >>> ss=s()
180 >>> rr=r()
180 >>> rr=r()
181 >>> ssrr=sr()
181 >>> ssrr=sr()
182 >>> 4.5
182 >>> 4.5
183 4.5
183 4.5
184 >>> str(ss)
184 >>> str(ss)
185 's'
185 's'
186 >>>
186 >>>
187 """
187 """
188
188
189
189
190 @dec.skip_without('sqlite3')
190 @dec.skip_without('sqlite3')
191 def test_macro():
191 def test_macro():
192 ip = get_ipython()
192 ip = get_ipython()
193 ip.history_manager.reset() # Clear any existing history.
193 ip.history_manager.reset() # Clear any existing history.
194 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
194 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
195 for i, cmd in enumerate(cmds, start=1):
195 for i, cmd in enumerate(cmds, start=1):
196 ip.history_manager.store_inputs(i, cmd)
196 ip.history_manager.store_inputs(i, cmd)
197 ip.magic("macro test 1-3")
197 ip.magic("macro test 1-3")
198 nt.assert_equal(ip.user_ns["test"].value, "\n".join(cmds)+"\n")
198 nt.assert_equal(ip.user_ns["test"].value, "\n".join(cmds)+"\n")
199
199
200 # List macros.
200 # List macros.
201 assert "test" in ip.magic("macro")
201 assert "test" in ip.magic("macro")
202
202
203
203
204 @dec.skip_without('sqlite3')
204 @dec.skip_without('sqlite3')
205 def test_macro_run():
205 def test_macro_run():
206 """Test that we can run a multi-line macro successfully."""
206 """Test that we can run a multi-line macro successfully."""
207 ip = get_ipython()
207 ip = get_ipython()
208 ip.history_manager.reset()
208 ip.history_manager.reset()
209 cmds = ["a=10", "a+=1", py3compat.doctest_refactor_print("print a"),
209 cmds = ["a=10", "a+=1", py3compat.doctest_refactor_print("print a"),
210 "%macro test 2-3"]
210 "%macro test 2-3"]
211 for cmd in cmds:
211 for cmd in cmds:
212 ip.run_cell(cmd, store_history=True)
212 ip.run_cell(cmd, store_history=True)
213 nt.assert_equal(ip.user_ns["test"].value,
213 nt.assert_equal(ip.user_ns["test"].value,
214 py3compat.doctest_refactor_print("a+=1\nprint a\n"))
214 py3compat.doctest_refactor_print("a+=1\nprint a\n"))
215 with tt.AssertPrints("12"):
215 with tt.AssertPrints("12"):
216 ip.run_cell("test")
216 ip.run_cell("test")
217 with tt.AssertPrints("13"):
217 with tt.AssertPrints("13"):
218 ip.run_cell("test")
218 ip.run_cell("test")
219
219
220
220
221 @dec.skipif_not_numpy
221 @dec.skipif_not_numpy
222 def test_numpy_reset_array_undec():
222 def test_numpy_reset_array_undec():
223 "Test '%reset array' functionality"
223 "Test '%reset array' functionality"
224 _ip.ex('import numpy as np')
224 _ip.ex('import numpy as np')
225 _ip.ex('a = np.empty(2)')
225 _ip.ex('a = np.empty(2)')
226 yield (nt.assert_true, 'a' in _ip.user_ns)
226 yield (nt.assert_true, 'a' in _ip.user_ns)
227 _ip.magic('reset -f array')
227 _ip.magic('reset -f array')
228 yield (nt.assert_false, 'a' in _ip.user_ns)
228 yield (nt.assert_false, 'a' in _ip.user_ns)
229
229
230 def test_reset_out():
230 def test_reset_out():
231 "Test '%reset out' magic"
231 "Test '%reset out' magic"
232 _ip.run_cell("parrot = 'dead'", store_history=True)
232 _ip.run_cell("parrot = 'dead'", store_history=True)
233 # test '%reset -f out', make an Out prompt
233 # test '%reset -f out', make an Out prompt
234 _ip.run_cell("parrot", store_history=True)
234 _ip.run_cell("parrot", store_history=True)
235 nt.assert_true('dead' in [_ip.user_ns[x] for x in '_','__','___'])
235 nt.assert_true('dead' in [_ip.user_ns[x] for x in '_','__','___'])
236 _ip.magic('reset -f out')
236 _ip.magic('reset -f out')
237 nt.assert_false('dead' in [_ip.user_ns[x] for x in '_','__','___'])
237 nt.assert_false('dead' in [_ip.user_ns[x] for x in '_','__','___'])
238 nt.assert_true(len(_ip.user_ns['Out']) == 0)
238 nt.assert_true(len(_ip.user_ns['Out']) == 0)
239
239
240 def test_reset_in():
240 def test_reset_in():
241 "Test '%reset in' magic"
241 "Test '%reset in' magic"
242 # test '%reset -f in'
242 # test '%reset -f in'
243 _ip.run_cell("parrot", store_history=True)
243 _ip.run_cell("parrot", store_history=True)
244 nt.assert_true('parrot' in [_ip.user_ns[x] for x in '_i','_ii','_iii'])
244 nt.assert_true('parrot' in [_ip.user_ns[x] for x in '_i','_ii','_iii'])
245 _ip.magic('%reset -f in')
245 _ip.magic('%reset -f in')
246 nt.assert_false('parrot' in [_ip.user_ns[x] for x in '_i','_ii','_iii'])
246 nt.assert_false('parrot' in [_ip.user_ns[x] for x in '_i','_ii','_iii'])
247 nt.assert_true(len(set(_ip.user_ns['In'])) == 1)
247 nt.assert_true(len(set(_ip.user_ns['In'])) == 1)
248
248
249 def test_reset_dhist():
249 def test_reset_dhist():
250 "Test '%reset dhist' magic"
250 "Test '%reset dhist' magic"
251 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
251 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
252 _ip.magic('cd ' + os.path.dirname(nt.__file__))
252 _ip.magic('cd ' + os.path.dirname(nt.__file__))
253 _ip.magic('cd -')
253 _ip.magic('cd -')
254 nt.assert_true(len(_ip.user_ns['_dh']) > 0)
254 nt.assert_true(len(_ip.user_ns['_dh']) > 0)
255 _ip.magic('reset -f dhist')
255 _ip.magic('reset -f dhist')
256 nt.assert_true(len(_ip.user_ns['_dh']) == 0)
256 nt.assert_true(len(_ip.user_ns['_dh']) == 0)
257 _ip.run_cell("_dh = [d for d in tmp]") #restore
257 _ip.run_cell("_dh = [d for d in tmp]") #restore
258
258
259 def test_reset_in_length():
259 def test_reset_in_length():
260 "Test that '%reset in' preserves In[] length"
260 "Test that '%reset in' preserves In[] length"
261 _ip.run_cell("print 'foo'")
261 _ip.run_cell("print 'foo'")
262 _ip.run_cell("reset -f in")
262 _ip.run_cell("reset -f in")
263 nt.assert_true(len(_ip.user_ns['In']) == _ip.displayhook.prompt_count+1)
263 nt.assert_true(len(_ip.user_ns['In']) == _ip.displayhook.prompt_count+1)
264
264
265 def test_time():
265 def test_time():
266 _ip.magic('time None')
266 _ip.magic('time None')
267
267
268 def test_tb_syntaxerror():
268 def test_tb_syntaxerror():
269 """test %tb after a SyntaxError"""
269 """test %tb after a SyntaxError"""
270 ip = get_ipython()
270 ip = get_ipython()
271 ip.run_cell("for")
271 ip.run_cell("for")
272
272
273 # trap and validate stdout
273 # trap and validate stdout
274 save_stdout = sys.stdout
274 save_stdout = sys.stdout
275 try:
275 try:
276 sys.stdout = StringIO()
276 sys.stdout = StringIO()
277 ip.run_cell("%tb")
277 ip.run_cell("%tb")
278 out = sys.stdout.getvalue()
278 out = sys.stdout.getvalue()
279 finally:
279 finally:
280 sys.stdout = save_stdout
280 sys.stdout = save_stdout
281 # trim output, and only check the last line
281 # trim output, and only check the last line
282 last_line = out.rstrip().splitlines()[-1].strip()
282 last_line = out.rstrip().splitlines()[-1].strip()
283 nt.assert_equal(last_line, "SyntaxError: invalid syntax")
283 nt.assert_equal(last_line, "SyntaxError: invalid syntax")
284
284
285
285
286 @py3compat.doctest_refactor_print
286 def test_time():
287 def doctest_time():
287 ip = get_ipython()
288 """
289 In [10]: %time None
290 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
291 Wall time: 0.00 s
292
288
293 In [11]: def f(kmjy):
289 with tt.AssertPrints("CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s"):
294 ....: %time print 2*kmjy
290 ip.run_cell("%time None")
295
291
296 In [12]: f(3)
292 ip.run_cell("def f(kmjy):\n"
297 6
293 " %time print (2*kmjy)")
298 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
294
299 Wall time: 0.00 s
295 with tt.AssertPrints("CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s"):
300 """
296 with tt.AssertPrints("hihi", suppress=False):
301
297 ip.run_cell("f('hi')")
302
298
303 def test_doctest_mode():
299 def test_doctest_mode():
304 "Toggle doctest_mode twice, it should be a no-op and run without error"
300 "Toggle doctest_mode twice, it should be a no-op and run without error"
305 _ip.magic('doctest_mode')
301 _ip.magic('doctest_mode')
306 _ip.magic('doctest_mode')
302 _ip.magic('doctest_mode')
307
303
308
304
309 def test_parse_options():
305 def test_parse_options():
310 """Tests for basic options parsing in magics."""
306 """Tests for basic options parsing in magics."""
311 # These are only the most minimal of tests, more should be added later. At
307 # These are only the most minimal of tests, more should be added later. At
312 # the very least we check that basic text/unicode calls work OK.
308 # the very least we check that basic text/unicode calls work OK.
313 m = DummyMagics(_ip)
309 m = DummyMagics(_ip)
314 nt.assert_equal(m.parse_options('foo', '')[1], 'foo')
310 nt.assert_equal(m.parse_options('foo', '')[1], 'foo')
315 nt.assert_equal(m.parse_options(u'foo', '')[1], u'foo')
311 nt.assert_equal(m.parse_options(u'foo', '')[1], u'foo')
316
312
317
313
318 def test_dirops():
314 def test_dirops():
319 """Test various directory handling operations."""
315 """Test various directory handling operations."""
320 # curpath = lambda :os.path.splitdrive(os.getcwdu())[1].replace('\\','/')
316 # curpath = lambda :os.path.splitdrive(os.getcwdu())[1].replace('\\','/')
321 curpath = os.getcwdu
317 curpath = os.getcwdu
322 startdir = os.getcwdu()
318 startdir = os.getcwdu()
323 ipdir = os.path.realpath(_ip.ipython_dir)
319 ipdir = os.path.realpath(_ip.ipython_dir)
324 try:
320 try:
325 _ip.magic('cd "%s"' % ipdir)
321 _ip.magic('cd "%s"' % ipdir)
326 nt.assert_equal(curpath(), ipdir)
322 nt.assert_equal(curpath(), ipdir)
327 _ip.magic('cd -')
323 _ip.magic('cd -')
328 nt.assert_equal(curpath(), startdir)
324 nt.assert_equal(curpath(), startdir)
329 _ip.magic('pushd "%s"' % ipdir)
325 _ip.magic('pushd "%s"' % ipdir)
330 nt.assert_equal(curpath(), ipdir)
326 nt.assert_equal(curpath(), ipdir)
331 _ip.magic('popd')
327 _ip.magic('popd')
332 nt.assert_equal(curpath(), startdir)
328 nt.assert_equal(curpath(), startdir)
333 finally:
329 finally:
334 os.chdir(startdir)
330 os.chdir(startdir)
335
331
336
332
337 def test_xmode():
333 def test_xmode():
338 # Calling xmode three times should be a no-op
334 # Calling xmode three times should be a no-op
339 xmode = _ip.InteractiveTB.mode
335 xmode = _ip.InteractiveTB.mode
340 for i in range(3):
336 for i in range(3):
341 _ip.magic("xmode")
337 _ip.magic("xmode")
342 nt.assert_equal(_ip.InteractiveTB.mode, xmode)
338 nt.assert_equal(_ip.InteractiveTB.mode, xmode)
343
339
344 def test_reset_hard():
340 def test_reset_hard():
345 monitor = []
341 monitor = []
346 class A(object):
342 class A(object):
347 def __del__(self):
343 def __del__(self):
348 monitor.append(1)
344 monitor.append(1)
349 def __repr__(self):
345 def __repr__(self):
350 return "<A instance>"
346 return "<A instance>"
351
347
352 _ip.user_ns["a"] = A()
348 _ip.user_ns["a"] = A()
353 _ip.run_cell("a")
349 _ip.run_cell("a")
354
350
355 nt.assert_equal(monitor, [])
351 nt.assert_equal(monitor, [])
356 _ip.magic("reset -f")
352 _ip.magic("reset -f")
357 nt.assert_equal(monitor, [1])
353 nt.assert_equal(monitor, [1])
358
354
359 class TestXdel(tt.TempFileMixin):
355 class TestXdel(tt.TempFileMixin):
360 def test_xdel(self):
356 def test_xdel(self):
361 """Test that references from %run are cleared by xdel."""
357 """Test that references from %run are cleared by xdel."""
362 src = ("class A(object):\n"
358 src = ("class A(object):\n"
363 " monitor = []\n"
359 " monitor = []\n"
364 " def __del__(self):\n"
360 " def __del__(self):\n"
365 " self.monitor.append(1)\n"
361 " self.monitor.append(1)\n"
366 "a = A()\n")
362 "a = A()\n")
367 self.mktmp(src)
363 self.mktmp(src)
368 # %run creates some hidden references...
364 # %run creates some hidden references...
369 _ip.magic("run %s" % self.fname)
365 _ip.magic("run %s" % self.fname)
370 # ... as does the displayhook.
366 # ... as does the displayhook.
371 _ip.run_cell("a")
367 _ip.run_cell("a")
372
368
373 monitor = _ip.user_ns["A"].monitor
369 monitor = _ip.user_ns["A"].monitor
374 nt.assert_equal(monitor, [])
370 nt.assert_equal(monitor, [])
375
371
376 _ip.magic("xdel a")
372 _ip.magic("xdel a")
377
373
378 # Check that a's __del__ method has been called.
374 # Check that a's __del__ method has been called.
379 nt.assert_equal(monitor, [1])
375 nt.assert_equal(monitor, [1])
380
376
381 def doctest_who():
377 def doctest_who():
382 """doctest for %who
378 """doctest for %who
383
379
384 In [1]: %reset -f
380 In [1]: %reset -f
385
381
386 In [2]: alpha = 123
382 In [2]: alpha = 123
387
383
388 In [3]: beta = 'beta'
384 In [3]: beta = 'beta'
389
385
390 In [4]: %who int
386 In [4]: %who int
391 alpha
387 alpha
392
388
393 In [5]: %who str
389 In [5]: %who str
394 beta
390 beta
395
391
396 In [6]: %whos
392 In [6]: %whos
397 Variable Type Data/Info
393 Variable Type Data/Info
398 ----------------------------
394 ----------------------------
399 alpha int 123
395 alpha int 123
400 beta str beta
396 beta str beta
401
397
402 In [7]: %who_ls
398 In [7]: %who_ls
403 Out[7]: ['alpha', 'beta']
399 Out[7]: ['alpha', 'beta']
404 """
400 """
405
401
406 def test_whos():
402 def test_whos():
407 """Check that whos is protected against objects where repr() fails."""
403 """Check that whos is protected against objects where repr() fails."""
408 class A(object):
404 class A(object):
409 def __repr__(self):
405 def __repr__(self):
410 raise Exception()
406 raise Exception()
411 _ip.user_ns['a'] = A()
407 _ip.user_ns['a'] = A()
412 _ip.magic("whos")
408 _ip.magic("whos")
413
409
414 @py3compat.u_format
410 @py3compat.u_format
415 def doctest_precision():
411 def doctest_precision():
416 """doctest for %precision
412 """doctest for %precision
417
413
418 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
414 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
419
415
420 In [2]: %precision 5
416 In [2]: %precision 5
421 Out[2]: {u}'%.5f'
417 Out[2]: {u}'%.5f'
422
418
423 In [3]: f.float_format
419 In [3]: f.float_format
424 Out[3]: {u}'%.5f'
420 Out[3]: {u}'%.5f'
425
421
426 In [4]: %precision %e
422 In [4]: %precision %e
427 Out[4]: {u}'%e'
423 Out[4]: {u}'%e'
428
424
429 In [5]: f(3.1415927)
425 In [5]: f(3.1415927)
430 Out[5]: {u}'3.141593e+00'
426 Out[5]: {u}'3.141593e+00'
431 """
427 """
432
428
433 def test_psearch():
429 def test_psearch():
434 with tt.AssertPrints("dict.fromkeys"):
430 with tt.AssertPrints("dict.fromkeys"):
435 _ip.run_cell("dict.fr*?")
431 _ip.run_cell("dict.fr*?")
436
432
437 def test_timeit_shlex():
433 def test_timeit_shlex():
438 """test shlex issues with timeit (#1109)"""
434 """test shlex issues with timeit (#1109)"""
439 _ip.ex("def f(*a,**kw): pass")
435 _ip.ex("def f(*a,**kw): pass")
440 _ip.magic('timeit -n1 "this is a bug".count(" ")')
436 _ip.magic('timeit -n1 "this is a bug".count(" ")')
441 _ip.magic('timeit -r1 -n1 f(" ", 1)')
437 _ip.magic('timeit -r1 -n1 f(" ", 1)')
442 _ip.magic('timeit -r1 -n1 f(" ", 1, " ", 2, " ")')
438 _ip.magic('timeit -r1 -n1 f(" ", 1, " ", 2, " ")')
443 _ip.magic('timeit -r1 -n1 ("a " + "b")')
439 _ip.magic('timeit -r1 -n1 ("a " + "b")')
444 _ip.magic('timeit -r1 -n1 f("a " + "b")')
440 _ip.magic('timeit -r1 -n1 f("a " + "b")')
445 _ip.magic('timeit -r1 -n1 f("a " + "b ")')
441 _ip.magic('timeit -r1 -n1 f("a " + "b ")')
446
442
447
443
448 def test_timeit_arguments():
444 def test_timeit_arguments():
449 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
445 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
450 _ip.magic("timeit ('#')")
446 _ip.magic("timeit ('#')")
451
447
452
448
453 def test_timeit_special_syntax():
449 def test_timeit_special_syntax():
454 "Test %%timeit with IPython special syntax"
450 "Test %%timeit with IPython special syntax"
455 from IPython.core.magic import register_line_magic
451 from IPython.core.magic import register_line_magic
456
452
457 @register_line_magic
453 @register_line_magic
458 def lmagic(line):
454 def lmagic(line):
459 ip = get_ipython()
455 ip = get_ipython()
460 ip.user_ns['lmagic_out'] = line
456 ip.user_ns['lmagic_out'] = line
461
457
462 # line mode test
458 # line mode test
463 _ip.run_line_magic('timeit', '-n1 -r1 %lmagic my line')
459 _ip.run_line_magic('timeit', '-n1 -r1 %lmagic my line')
464 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
460 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
465 # cell mode test
461 # cell mode test
466 _ip.run_cell_magic('timeit', '-n1 -r1', '%lmagic my line2')
462 _ip.run_cell_magic('timeit', '-n1 -r1', '%lmagic my line2')
467 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
463 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
468
464
469
465
470 @dec.skipif(execution.profile is None)
466 @dec.skipif(execution.profile is None)
471 def test_prun_quotes():
467 def test_prun_quotes():
472 "Test that prun does not clobber string escapes (GH #1302)"
468 "Test that prun does not clobber string escapes (GH #1302)"
473 _ip.magic(r"prun -q x = '\t'")
469 _ip.magic(r"prun -q x = '\t'")
474 nt.assert_equal(_ip.user_ns['x'], '\t')
470 nt.assert_equal(_ip.user_ns['x'], '\t')
475
471
476 def test_extension():
472 def test_extension():
477 tmpdir = TemporaryDirectory()
473 tmpdir = TemporaryDirectory()
478 orig_ipython_dir = _ip.ipython_dir
474 orig_ipython_dir = _ip.ipython_dir
479 try:
475 try:
480 _ip.ipython_dir = tmpdir.name
476 _ip.ipython_dir = tmpdir.name
481 nt.assert_raises(ImportError, _ip.magic, "load_ext daft_extension")
477 nt.assert_raises(ImportError, _ip.magic, "load_ext daft_extension")
482 url = os.path.join(os.path.dirname(__file__), "daft_extension.py")
478 url = os.path.join(os.path.dirname(__file__), "daft_extension.py")
483 _ip.magic("install_ext %s" % url)
479 _ip.magic("install_ext %s" % url)
484 _ip.user_ns.pop('arq', None)
480 _ip.user_ns.pop('arq', None)
485 invalidate_caches() # Clear import caches
481 invalidate_caches() # Clear import caches
486 _ip.magic("load_ext daft_extension")
482 _ip.magic("load_ext daft_extension")
487 nt.assert_equal(_ip.user_ns['arq'], 185)
483 nt.assert_equal(_ip.user_ns['arq'], 185)
488 _ip.magic("unload_ext daft_extension")
484 _ip.magic("unload_ext daft_extension")
489 assert 'arq' not in _ip.user_ns
485 assert 'arq' not in _ip.user_ns
490 finally:
486 finally:
491 _ip.ipython_dir = orig_ipython_dir
487 _ip.ipython_dir = orig_ipython_dir
492 tmpdir.cleanup()
488 tmpdir.cleanup()
493
489
494 def test_notebook_export_json():
490 def test_notebook_export_json():
495 with TemporaryDirectory() as td:
491 with TemporaryDirectory() as td:
496 outfile = os.path.join(td, "nb.ipynb")
492 outfile = os.path.join(td, "nb.ipynb")
497 _ip.ex(py3compat.u_format(u"u = {u}'héllo'"))
493 _ip.ex(py3compat.u_format(u"u = {u}'héllo'"))
498 _ip.magic("notebook -e %s" % outfile)
494 _ip.magic("notebook -e %s" % outfile)
499
495
500 def test_notebook_export_py():
496 def test_notebook_export_py():
501 with TemporaryDirectory() as td:
497 with TemporaryDirectory() as td:
502 outfile = os.path.join(td, "nb.py")
498 outfile = os.path.join(td, "nb.py")
503 _ip.ex(py3compat.u_format(u"u = {u}'héllo'"))
499 _ip.ex(py3compat.u_format(u"u = {u}'héllo'"))
504 _ip.magic("notebook -e %s" % outfile)
500 _ip.magic("notebook -e %s" % outfile)
505
501
506 def test_notebook_reformat_py():
502 def test_notebook_reformat_py():
507 with TemporaryDirectory() as td:
503 with TemporaryDirectory() as td:
508 infile = os.path.join(td, "nb.ipynb")
504 infile = os.path.join(td, "nb.ipynb")
509 with io.open(infile, 'w', encoding='utf-8') as f:
505 with io.open(infile, 'w', encoding='utf-8') as f:
510 current.write(nb0, f, 'json')
506 current.write(nb0, f, 'json')
511
507
512 _ip.ex(py3compat.u_format(u"u = {u}'héllo'"))
508 _ip.ex(py3compat.u_format(u"u = {u}'héllo'"))
513 _ip.magic("notebook -f py %s" % infile)
509 _ip.magic("notebook -f py %s" % infile)
514
510
515 def test_notebook_reformat_json():
511 def test_notebook_reformat_json():
516 with TemporaryDirectory() as td:
512 with TemporaryDirectory() as td:
517 infile = os.path.join(td, "nb.py")
513 infile = os.path.join(td, "nb.py")
518 with io.open(infile, 'w', encoding='utf-8') as f:
514 with io.open(infile, 'w', encoding='utf-8') as f:
519 current.write(nb0, f, 'py')
515 current.write(nb0, f, 'py')
520
516
521 _ip.ex(py3compat.u_format(u"u = {u}'héllo'"))
517 _ip.ex(py3compat.u_format(u"u = {u}'héllo'"))
522 _ip.magic("notebook -f ipynb %s" % infile)
518 _ip.magic("notebook -f ipynb %s" % infile)
523 _ip.magic("notebook -f json %s" % infile)
519 _ip.magic("notebook -f json %s" % infile)
524
520
525 def test_env():
521 def test_env():
526 env = _ip.magic("env")
522 env = _ip.magic("env")
527 assert isinstance(env, dict), type(env)
523 assert isinstance(env, dict), type(env)
528
524
529
525
530 class CellMagicTestCase(TestCase):
526 class CellMagicTestCase(TestCase):
531
527
532 def check_ident(self, magic):
528 def check_ident(self, magic):
533 # Manually called, we get the result
529 # Manually called, we get the result
534 out = _ip.run_cell_magic(magic, 'a', 'b')
530 out = _ip.run_cell_magic(magic, 'a', 'b')
535 nt.assert_equal(out, ('a','b'))
531 nt.assert_equal(out, ('a','b'))
536 # Via run_cell, it goes into the user's namespace via displayhook
532 # Via run_cell, it goes into the user's namespace via displayhook
537 _ip.run_cell('%%' + magic +' c\nd')
533 _ip.run_cell('%%' + magic +' c\nd')
538 nt.assert_equal(_ip.user_ns['_'], ('c','d'))
534 nt.assert_equal(_ip.user_ns['_'], ('c','d'))
539
535
540 def test_cell_magic_func_deco(self):
536 def test_cell_magic_func_deco(self):
541 "Cell magic using simple decorator"
537 "Cell magic using simple decorator"
542 @register_cell_magic
538 @register_cell_magic
543 def cellm(line, cell):
539 def cellm(line, cell):
544 return line, cell
540 return line, cell
545
541
546 self.check_ident('cellm')
542 self.check_ident('cellm')
547
543
548 def test_cell_magic_reg(self):
544 def test_cell_magic_reg(self):
549 "Cell magic manually registered"
545 "Cell magic manually registered"
550 def cellm(line, cell):
546 def cellm(line, cell):
551 return line, cell
547 return line, cell
552
548
553 _ip.register_magic_function(cellm, 'cell', 'cellm2')
549 _ip.register_magic_function(cellm, 'cell', 'cellm2')
554 self.check_ident('cellm2')
550 self.check_ident('cellm2')
555
551
556 def test_cell_magic_class(self):
552 def test_cell_magic_class(self):
557 "Cell magics declared via a class"
553 "Cell magics declared via a class"
558 @magics_class
554 @magics_class
559 class MyMagics(Magics):
555 class MyMagics(Magics):
560
556
561 @cell_magic
557 @cell_magic
562 def cellm3(self, line, cell):
558 def cellm3(self, line, cell):
563 return line, cell
559 return line, cell
564
560
565 _ip.register_magics(MyMagics)
561 _ip.register_magics(MyMagics)
566 self.check_ident('cellm3')
562 self.check_ident('cellm3')
567
563
568 def test_cell_magic_class2(self):
564 def test_cell_magic_class2(self):
569 "Cell magics declared via a class, #2"
565 "Cell magics declared via a class, #2"
570 @magics_class
566 @magics_class
571 class MyMagics2(Magics):
567 class MyMagics2(Magics):
572
568
573 @cell_magic('cellm4')
569 @cell_magic('cellm4')
574 def cellm33(self, line, cell):
570 def cellm33(self, line, cell):
575 return line, cell
571 return line, cell
576
572
577 _ip.register_magics(MyMagics2)
573 _ip.register_magics(MyMagics2)
578 self.check_ident('cellm4')
574 self.check_ident('cellm4')
579 # Check that nothing is registered as 'cellm33'
575 # Check that nothing is registered as 'cellm33'
580 c33 = _ip.find_cell_magic('cellm33')
576 c33 = _ip.find_cell_magic('cellm33')
581 nt.assert_equal(c33, None)
577 nt.assert_equal(c33, None)
582
578
583 def test_file():
579 def test_file():
584 """Basic %%file"""
580 """Basic %%file"""
585 ip = get_ipython()
581 ip = get_ipython()
586 with TemporaryDirectory() as td:
582 with TemporaryDirectory() as td:
587 fname = os.path.join(td, 'file1')
583 fname = os.path.join(td, 'file1')
588 ip.run_cell_magic("file", fname, u'\n'.join([
584 ip.run_cell_magic("file", fname, u'\n'.join([
589 'line1',
585 'line1',
590 'line2',
586 'line2',
591 ]))
587 ]))
592 with open(fname) as f:
588 with open(fname) as f:
593 s = f.read()
589 s = f.read()
594 nt.assert_in('line1\n', s)
590 nt.assert_in('line1\n', s)
595 nt.assert_in('line2', s)
591 nt.assert_in('line2', s)
596
592
597 def test_file_var_expand():
593 def test_file_var_expand():
598 """%%file $filename"""
594 """%%file $filename"""
599 ip = get_ipython()
595 ip = get_ipython()
600 with TemporaryDirectory() as td:
596 with TemporaryDirectory() as td:
601 fname = os.path.join(td, 'file1')
597 fname = os.path.join(td, 'file1')
602 ip.user_ns['filename'] = fname
598 ip.user_ns['filename'] = fname
603 ip.run_cell_magic("file", '$filename', u'\n'.join([
599 ip.run_cell_magic("file", '$filename', u'\n'.join([
604 'line1',
600 'line1',
605 'line2',
601 'line2',
606 ]))
602 ]))
607 with open(fname) as f:
603 with open(fname) as f:
608 s = f.read()
604 s = f.read()
609 nt.assert_in('line1\n', s)
605 nt.assert_in('line1\n', s)
610 nt.assert_in('line2', s)
606 nt.assert_in('line2', s)
611
607
612 def test_file_unicode():
608 def test_file_unicode():
613 """%%file with unicode cell"""
609 """%%file with unicode cell"""
614 ip = get_ipython()
610 ip = get_ipython()
615 with TemporaryDirectory() as td:
611 with TemporaryDirectory() as td:
616 fname = os.path.join(td, 'file1')
612 fname = os.path.join(td, 'file1')
617 ip.run_cell_magic("file", fname, u'\n'.join([
613 ip.run_cell_magic("file", fname, u'\n'.join([
618 u'liné1',
614 u'liné1',
619 u'liné2',
615 u'liné2',
620 ]))
616 ]))
621 with io.open(fname, encoding='utf-8') as f:
617 with io.open(fname, encoding='utf-8') as f:
622 s = f.read()
618 s = f.read()
623 nt.assert_in(u'liné1\n', s)
619 nt.assert_in(u'liné1\n', s)
624 nt.assert_in(u'liné2', s)
620 nt.assert_in(u'liné2', s)
625
621
626 def test_file_amend():
622 def test_file_amend():
627 """%%file -a amends files"""
623 """%%file -a amends files"""
628 ip = get_ipython()
624 ip = get_ipython()
629 with TemporaryDirectory() as td:
625 with TemporaryDirectory() as td:
630 fname = os.path.join(td, 'file2')
626 fname = os.path.join(td, 'file2')
631 ip.run_cell_magic("file", fname, u'\n'.join([
627 ip.run_cell_magic("file", fname, u'\n'.join([
632 'line1',
628 'line1',
633 'line2',
629 'line2',
634 ]))
630 ]))
635 ip.run_cell_magic("file", "-a %s" % fname, u'\n'.join([
631 ip.run_cell_magic("file", "-a %s" % fname, u'\n'.join([
636 'line3',
632 'line3',
637 'line4',
633 'line4',
638 ]))
634 ]))
639 with open(fname) as f:
635 with open(fname) as f:
640 s = f.read()
636 s = f.read()
641 nt.assert_in('line1\n', s)
637 nt.assert_in('line1\n', s)
642 nt.assert_in('line3\n', s)
638 nt.assert_in('line3\n', s)
643
639
644
640
645 def test_script_config():
641 def test_script_config():
646 ip = get_ipython()
642 ip = get_ipython()
647 ip.config.ScriptMagics.script_magics = ['whoda']
643 ip.config.ScriptMagics.script_magics = ['whoda']
648 sm = script.ScriptMagics(shell=ip)
644 sm = script.ScriptMagics(shell=ip)
649 nt.assert_in('whoda', sm.magics['cell'])
645 nt.assert_in('whoda', sm.magics['cell'])
650
646
651 @dec.skip_win32
647 @dec.skip_win32
652 def test_script_out():
648 def test_script_out():
653 ip = get_ipython()
649 ip = get_ipython()
654 ip.run_cell_magic("script", "--out output sh", "echo 'hi'")
650 ip.run_cell_magic("script", "--out output sh", "echo 'hi'")
655 nt.assert_equal(ip.user_ns['output'], 'hi\n')
651 nt.assert_equal(ip.user_ns['output'], 'hi\n')
656
652
657 @dec.skip_win32
653 @dec.skip_win32
658 def test_script_err():
654 def test_script_err():
659 ip = get_ipython()
655 ip = get_ipython()
660 ip.run_cell_magic("script", "--err error sh", "echo 'hello' >&2")
656 ip.run_cell_magic("script", "--err error sh", "echo 'hello' >&2")
661 nt.assert_equal(ip.user_ns['error'], 'hello\n')
657 nt.assert_equal(ip.user_ns['error'], 'hello\n')
662
658
663 @dec.skip_win32
659 @dec.skip_win32
664 def test_script_out_err():
660 def test_script_out_err():
665 ip = get_ipython()
661 ip = get_ipython()
666 ip.run_cell_magic("script", "--out output --err error sh", "echo 'hi'\necho 'hello' >&2")
662 ip.run_cell_magic("script", "--out output --err error sh", "echo 'hi'\necho 'hello' >&2")
667 nt.assert_equal(ip.user_ns['output'], 'hi\n')
663 nt.assert_equal(ip.user_ns['output'], 'hi\n')
668 nt.assert_equal(ip.user_ns['error'], 'hello\n')
664 nt.assert_equal(ip.user_ns['error'], 'hello\n')
669
665
670 @dec.skip_win32
666 @dec.skip_win32
671 def test_script_bg_out():
667 def test_script_bg_out():
672 ip = get_ipython()
668 ip = get_ipython()
673 ip.run_cell_magic("script", "--bg --out output sh", "echo 'hi'")
669 ip.run_cell_magic("script", "--bg --out output sh", "echo 'hi'")
674 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
670 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
675
671
676 @dec.skip_win32
672 @dec.skip_win32
677 def test_script_bg_err():
673 def test_script_bg_err():
678 ip = get_ipython()
674 ip = get_ipython()
679 ip.run_cell_magic("script", "--bg --err error sh", "echo 'hello' >&2")
675 ip.run_cell_magic("script", "--bg --err error sh", "echo 'hello' >&2")
680 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
676 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
681
677
682 @dec.skip_win32
678 @dec.skip_win32
683 def test_script_bg_out_err():
679 def test_script_bg_out_err():
684 ip = get_ipython()
680 ip = get_ipython()
685 ip.run_cell_magic("script", "--bg --out output --err error sh", "echo 'hi'\necho 'hello' >&2")
681 ip.run_cell_magic("script", "--bg --out output --err error sh", "echo 'hi'\necho 'hello' >&2")
686 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
682 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
687 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
683 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
688
684
689 def test_script_defaults():
685 def test_script_defaults():
690 ip = get_ipython()
686 ip = get_ipython()
691 for cmd in ['sh', 'bash', 'perl', 'ruby']:
687 for cmd in ['sh', 'bash', 'perl', 'ruby']:
692 try:
688 try:
693 find_cmd(cmd)
689 find_cmd(cmd)
694 except Exception:
690 except Exception:
695 pass
691 pass
696 else:
692 else:
697 nt.assert_in(cmd, ip.magics_manager.magics['cell'])
693 nt.assert_in(cmd, ip.magics_manager.magics['cell'])
698
694
699
695
700 @magics_class
696 @magics_class
701 class FooFoo(Magics):
697 class FooFoo(Magics):
702 """class with both %foo and %%foo magics"""
698 """class with both %foo and %%foo magics"""
703 @line_magic('foo')
699 @line_magic('foo')
704 def line_foo(self, line):
700 def line_foo(self, line):
705 "I am line foo"
701 "I am line foo"
706 pass
702 pass
707
703
708 @cell_magic("foo")
704 @cell_magic("foo")
709 def cell_foo(self, line, cell):
705 def cell_foo(self, line, cell):
710 "I am cell foo, not line foo"
706 "I am cell foo, not line foo"
711 pass
707 pass
712
708
713 def test_line_cell_info():
709 def test_line_cell_info():
714 """%%foo and %foo magics are distinguishable to inspect"""
710 """%%foo and %foo magics are distinguishable to inspect"""
715 ip = get_ipython()
711 ip = get_ipython()
716 ip.magics_manager.register(FooFoo)
712 ip.magics_manager.register(FooFoo)
717 oinfo = ip.object_inspect('foo')
713 oinfo = ip.object_inspect('foo')
718 nt.assert_true(oinfo['found'])
714 nt.assert_true(oinfo['found'])
719 nt.assert_true(oinfo['ismagic'])
715 nt.assert_true(oinfo['ismagic'])
720
716
721 oinfo = ip.object_inspect('%%foo')
717 oinfo = ip.object_inspect('%%foo')
722 nt.assert_true(oinfo['found'])
718 nt.assert_true(oinfo['found'])
723 nt.assert_true(oinfo['ismagic'])
719 nt.assert_true(oinfo['ismagic'])
724 nt.assert_equal(oinfo['docstring'], FooFoo.cell_foo.__doc__)
720 nt.assert_equal(oinfo['docstring'], FooFoo.cell_foo.__doc__)
725
721
726 oinfo = ip.object_inspect('%foo')
722 oinfo = ip.object_inspect('%foo')
727 nt.assert_true(oinfo['found'])
723 nt.assert_true(oinfo['found'])
728 nt.assert_true(oinfo['ismagic'])
724 nt.assert_true(oinfo['ismagic'])
729 nt.assert_equal(oinfo['docstring'], FooFoo.line_foo.__doc__)
725 nt.assert_equal(oinfo['docstring'], FooFoo.line_foo.__doc__)
730
726
731 def test_multiple_magics():
727 def test_multiple_magics():
732 ip = get_ipython()
728 ip = get_ipython()
733 foo1 = FooFoo(ip)
729 foo1 = FooFoo(ip)
734 foo2 = FooFoo(ip)
730 foo2 = FooFoo(ip)
735 mm = ip.magics_manager
731 mm = ip.magics_manager
736 mm.register(foo1)
732 mm.register(foo1)
737 nt.assert_true(mm.magics['line']['foo'].im_self is foo1)
733 nt.assert_true(mm.magics['line']['foo'].im_self is foo1)
738 mm.register(foo2)
734 mm.register(foo2)
739 nt.assert_true(mm.magics['line']['foo'].im_self is foo2)
735 nt.assert_true(mm.magics['line']['foo'].im_self is foo2)
740
736
741 def test_alias_magic():
737 def test_alias_magic():
742 """Test %alias_magic."""
738 """Test %alias_magic."""
743 ip = get_ipython()
739 ip = get_ipython()
744 mm = ip.magics_manager
740 mm = ip.magics_manager
745
741
746 # Basic operation: both cell and line magics are created, if possible.
742 # Basic operation: both cell and line magics are created, if possible.
747 ip.run_line_magic('alias_magic', 'timeit_alias timeit')
743 ip.run_line_magic('alias_magic', 'timeit_alias timeit')
748 nt.assert_true('timeit_alias' in mm.magics['line'])
744 nt.assert_true('timeit_alias' in mm.magics['line'])
749 nt.assert_true('timeit_alias' in mm.magics['cell'])
745 nt.assert_true('timeit_alias' in mm.magics['cell'])
750
746
751 # --cell is specified, line magic not created.
747 # --cell is specified, line magic not created.
752 ip.run_line_magic('alias_magic', '--cell timeit_cell_alias timeit')
748 ip.run_line_magic('alias_magic', '--cell timeit_cell_alias timeit')
753 nt.assert_false('timeit_cell_alias' in mm.magics['line'])
749 nt.assert_false('timeit_cell_alias' in mm.magics['line'])
754 nt.assert_true('timeit_cell_alias' in mm.magics['cell'])
750 nt.assert_true('timeit_cell_alias' in mm.magics['cell'])
755
751
756 # Test that line alias is created successfully.
752 # Test that line alias is created successfully.
757 ip.run_line_magic('alias_magic', '--line env_alias env')
753 ip.run_line_magic('alias_magic', '--line env_alias env')
758 nt.assert_equal(ip.run_line_magic('env', ''),
754 nt.assert_equal(ip.run_line_magic('env', ''),
759 ip.run_line_magic('env_alias', ''))
755 ip.run_line_magic('env_alias', ''))
760
756
761 def test_save():
757 def test_save():
762 """Test %save."""
758 """Test %save."""
763 ip = get_ipython()
759 ip = get_ipython()
764 ip.history_manager.reset() # Clear any existing history.
760 ip.history_manager.reset() # Clear any existing history.
765 cmds = [u"a=1", u"def b():\n return a**2", u"print(a, b())"]
761 cmds = [u"a=1", u"def b():\n return a**2", u"print(a, b())"]
766 for i, cmd in enumerate(cmds, start=1):
762 for i, cmd in enumerate(cmds, start=1):
767 ip.history_manager.store_inputs(i, cmd)
763 ip.history_manager.store_inputs(i, cmd)
768 with TemporaryDirectory() as tmpdir:
764 with TemporaryDirectory() as tmpdir:
769 file = os.path.join(tmpdir, "testsave.py")
765 file = os.path.join(tmpdir, "testsave.py")
770 ip.run_line_magic("save", "%s 1-10" % file)
766 ip.run_line_magic("save", "%s 1-10" % file)
771 with open(file) as f:
767 with open(file) as f:
772 content = f.read()
768 content = f.read()
773 nt.assert_equal(content.count(cmds[0]), 1)
769 nt.assert_equal(content.count(cmds[0]), 1)
774 nt.assert_true('coding: utf-8' in content)
770 nt.assert_true('coding: utf-8' in content)
775 ip.run_line_magic("save", "-a %s 1-10" % file)
771 ip.run_line_magic("save", "-a %s 1-10" % file)
776 with open(file) as f:
772 with open(file) as f:
777 content = f.read()
773 content = f.read()
778 nt.assert_equal(content.count(cmds[0]), 2)
774 nt.assert_equal(content.count(cmds[0]), 2)
779 nt.assert_true('coding: utf-8' in content)
775 nt.assert_true('coding: utf-8' in content)
780
776
781
777
782 def test_store():
778 def test_store():
783 """Test %store."""
779 """Test %store."""
784 ip = get_ipython()
780 ip = get_ipython()
785 ip.run_line_magic('load_ext', 'storemagic')
781 ip.run_line_magic('load_ext', 'storemagic')
786
782
787 # make sure the storage is empty
783 # make sure the storage is empty
788 ip.run_line_magic('store', '-z')
784 ip.run_line_magic('store', '-z')
789 ip.user_ns['var'] = 42
785 ip.user_ns['var'] = 42
790 ip.run_line_magic('store', 'var')
786 ip.run_line_magic('store', 'var')
791 ip.user_ns['var'] = 39
787 ip.user_ns['var'] = 39
792 ip.run_line_magic('store', '-r')
788 ip.run_line_magic('store', '-r')
793 nt.assert_equal(ip.user_ns['var'], 42)
789 nt.assert_equal(ip.user_ns['var'], 42)
794
790
795 ip.run_line_magic('store', '-d var')
791 ip.run_line_magic('store', '-d var')
796 ip.user_ns['var'] = 39
792 ip.user_ns['var'] = 39
797 ip.run_line_magic('store' , '-r')
793 ip.run_line_magic('store' , '-r')
798 nt.assert_equal(ip.user_ns['var'], 39)
794 nt.assert_equal(ip.user_ns['var'], 39)
@@ -1,110 +1,99 b''
1 """Tests for input manipulation machinery."""
1 """Tests for input manipulation machinery."""
2
2
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Imports
4 # Imports
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 import nose.tools as nt
6 import nose.tools as nt
7
7
8 from IPython.core.prefilter import AutocallChecker
8 from IPython.core.prefilter import AutocallChecker
9 from IPython.testing import tools as tt, decorators as dec
9 from IPython.testing import tools as tt, decorators as dec
10 from IPython.testing.globalipapp import get_ipython
10 from IPython.testing.globalipapp import get_ipython
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Tests
13 # Tests
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 ip = get_ipython()
15 ip = get_ipython()
16
16
17 @dec.parametric
17 @dec.parametric
18 def test_prefilter():
18 def test_prefilter():
19 """Test user input conversions"""
19 """Test user input conversions"""
20
20
21 # pairs of (raw, expected correct) input
21 # pairs of (raw, expected correct) input
22 pairs = [ ('2+2','2+2'),
22 pairs = [ ('2+2','2+2'),
23 ('>>> 2+2','2+2'),
24 ('>>> # This is a comment\n'
25 '... 2+2',
26 '# This is a comment\n'
27 '2+2'),
28 # Some IPython input
29 ('In [1]: 1', '1'),
30 ('In [2]: for i in range(5):\n'
31 ' ...: print i,',
32 'for i in range(5):\n'
33 ' print i,'),
34 ]
23 ]
35
24
36 for raw, correct in pairs:
25 for raw, correct in pairs:
37 yield nt.assert_equal(ip.prefilter(raw), correct)
26 yield nt.assert_equal(ip.prefilter(raw), correct)
38
27
39
28
40 @dec.parametric
29 @dec.parametric
41 def test_autocall_binops():
30 def test_autocall_binops():
42 """See https://github.com/ipython/ipython/issues/81"""
31 """See https://github.com/ipython/ipython/issues/81"""
43 ip.magic('autocall 2')
32 ip.magic('autocall 2')
44 f = lambda x: x
33 f = lambda x: x
45 ip.user_ns['f'] = f
34 ip.user_ns['f'] = f
46 try:
35 try:
47 yield nt.assert_equal(ip.prefilter('f 1'),'f(1)')
36 yield nt.assert_equal(ip.prefilter('f 1'),'f(1)')
48 for t in ['f +1', 'f -1']:
37 for t in ['f +1', 'f -1']:
49 yield nt.assert_equal(ip.prefilter(t), t)
38 yield nt.assert_equal(ip.prefilter(t), t)
50
39
51 # Run tests again with a more permissive exclude_regexp, which will
40 # Run tests again with a more permissive exclude_regexp, which will
52 # allow transformation of binary operations ('f -1' -> 'f(-1)').
41 # allow transformation of binary operations ('f -1' -> 'f(-1)').
53 pm = ip.prefilter_manager
42 pm = ip.prefilter_manager
54 ac = AutocallChecker(shell=pm.shell, prefilter_manager=pm,
43 ac = AutocallChecker(shell=pm.shell, prefilter_manager=pm,
55 config=pm.config)
44 config=pm.config)
56 try:
45 try:
57 ac.priority = 1
46 ac.priority = 1
58 ac.exclude_regexp = r'^[,&^\|\*/]|^is |^not |^in |^and |^or '
47 ac.exclude_regexp = r'^[,&^\|\*/]|^is |^not |^in |^and |^or '
59 pm.sort_checkers()
48 pm.sort_checkers()
60
49
61 yield nt.assert_equal(ip.prefilter('f -1'), 'f(-1)')
50 yield nt.assert_equal(ip.prefilter('f -1'), 'f(-1)')
62 yield nt.assert_equal(ip.prefilter('f +1'), 'f(+1)')
51 yield nt.assert_equal(ip.prefilter('f +1'), 'f(+1)')
63 finally:
52 finally:
64 pm.unregister_checker(ac)
53 pm.unregister_checker(ac)
65 finally:
54 finally:
66 ip.magic('autocall 0')
55 ip.magic('autocall 0')
67 del ip.user_ns['f']
56 del ip.user_ns['f']
68
57
69
58
70 @dec.parametric
59 @dec.parametric
71 def test_issue_114():
60 def test_issue_114():
72 """Check that multiline string literals don't expand as magic
61 """Check that multiline string literals don't expand as magic
73 see http://github.com/ipython/ipython/issues/114"""
62 see http://github.com/ipython/ipython/issues/114"""
74
63
75 template = '"""\n%s\n"""'
64 template = '"""\n%s\n"""'
76 # Store the current value of multi_line_specials and turn it off before
65 # Store the current value of multi_line_specials and turn it off before
77 # running test, since it could be true (case in which the test doesn't make
66 # running test, since it could be true (case in which the test doesn't make
78 # sense, as multiline string literals *will* expand as magic in that case).
67 # sense, as multiline string literals *will* expand as magic in that case).
79 msp = ip.prefilter_manager.multi_line_specials
68 msp = ip.prefilter_manager.multi_line_specials
80 ip.prefilter_manager.multi_line_specials = False
69 ip.prefilter_manager.multi_line_specials = False
81 try:
70 try:
82 for mgk in ip.magics_manager.lsmagic()['line']:
71 for mgk in ip.magics_manager.lsmagic()['line']:
83 raw = template % mgk
72 raw = template % mgk
84 yield nt.assert_equal(ip.prefilter(raw), raw)
73 yield nt.assert_equal(ip.prefilter(raw), raw)
85 finally:
74 finally:
86 ip.prefilter_manager.multi_line_specials = msp
75 ip.prefilter_manager.multi_line_specials = msp
87
76
88
77
89 def test_prefilter_attribute_errors():
78 def test_prefilter_attribute_errors():
90 """Capture exceptions thrown by user objects on attribute access.
79 """Capture exceptions thrown by user objects on attribute access.
91
80
92 See http://github.com/ipython/ipython/issues/988."""
81 See http://github.com/ipython/ipython/issues/988."""
93
82
94 class X(object):
83 class X(object):
95 def __getattr__(self, k):
84 def __getattr__(self, k):
96 raise ValueError('broken object')
85 raise ValueError('broken object')
97 def __call__(self, x):
86 def __call__(self, x):
98 return x
87 return x
99
88
100 # Create a callable broken object
89 # Create a callable broken object
101 ip.user_ns['x'] = X()
90 ip.user_ns['x'] = X()
102 ip.magic('autocall 2')
91 ip.magic('autocall 2')
103 try:
92 try:
104 # Even if x throws an attribute error when looking at its rewrite
93 # Even if x throws an attribute error when looking at its rewrite
105 # attribute, we should not crash. So the test here is simply making
94 # attribute, we should not crash. So the test here is simply making
106 # the prefilter call and not having an exception.
95 # the prefilter call and not having an exception.
107 ip.prefilter('x 1')
96 ip.prefilter('x 1')
108 finally:
97 finally:
109 del ip.user_ns['x']
98 del ip.user_ns['x']
110 ip.magic('autocall 0')
99 ip.magic('autocall 0')
@@ -1,811 +1,807 b''
1 """Nose Plugin that supports IPython doctests.
1 """Nose Plugin that supports IPython doctests.
2
2
3 Limitations:
3 Limitations:
4
4
5 - When generating examples for use as doctests, make sure that you have
5 - When generating examples for use as doctests, make sure that you have
6 pretty-printing OFF. This can be done either by setting the
6 pretty-printing OFF. This can be done either by setting the
7 ``PlainTextFormatter.pprint`` option in your configuration file to False, or
7 ``PlainTextFormatter.pprint`` option in your configuration file to False, or
8 by interactively disabling it with %Pprint. This is required so that IPython
8 by interactively disabling it with %Pprint. This is required so that IPython
9 output matches that of normal Python, which is used by doctest for internal
9 output matches that of normal Python, which is used by doctest for internal
10 execution.
10 execution.
11
11
12 - Do not rely on specific prompt numbers for results (such as using
12 - Do not rely on specific prompt numbers for results (such as using
13 '_34==True', for example). For IPython tests run via an external process the
13 '_34==True', for example). For IPython tests run via an external process the
14 prompt numbers may be different, and IPython tests run as normal python code
14 prompt numbers may be different, and IPython tests run as normal python code
15 won't even have these special _NN variables set at all.
15 won't even have these special _NN variables set at all.
16 """
16 """
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Module imports
19 # Module imports
20
20
21 # From the standard library
21 # From the standard library
22 import __builtin__ as builtin_mod
22 import __builtin__ as builtin_mod
23 import commands
23 import commands
24 import doctest
24 import doctest
25 import inspect
25 import inspect
26 import logging
26 import logging
27 import os
27 import os
28 import re
28 import re
29 import sys
29 import sys
30 import traceback
30 import traceback
31 import unittest
31 import unittest
32
32
33 from inspect import getmodule
33 from inspect import getmodule
34 from StringIO import StringIO
34 from StringIO import StringIO
35
35
36 # We are overriding the default doctest runner, so we need to import a few
36 # We are overriding the default doctest runner, so we need to import a few
37 # things from doctest directly
37 # things from doctest directly
38 from doctest import (REPORTING_FLAGS, REPORT_ONLY_FIRST_FAILURE,
38 from doctest import (REPORTING_FLAGS, REPORT_ONLY_FIRST_FAILURE,
39 _unittest_reportflags, DocTestRunner,
39 _unittest_reportflags, DocTestRunner,
40 _extract_future_flags, pdb, _OutputRedirectingPdb,
40 _extract_future_flags, pdb, _OutputRedirectingPdb,
41 _exception_traceback,
41 _exception_traceback,
42 linecache)
42 linecache)
43
43
44 # Third-party modules
44 # Third-party modules
45 import nose.core
45 import nose.core
46
46
47 from nose.plugins import doctests, Plugin
47 from nose.plugins import doctests, Plugin
48 from nose.util import anyp, getpackage, test_address, resolve_name, tolist
48 from nose.util import anyp, getpackage, test_address, resolve_name, tolist
49
49
50 # Our own imports
51
52 # We're temporarily using TerminalMagics.cleanup_input() until the functionality
53 # is moved into core.
54 from IPython.frontend.terminal.interactiveshell import TerminalMagics
55
50 #-----------------------------------------------------------------------------
56 #-----------------------------------------------------------------------------
51 # Module globals and other constants
57 # Module globals and other constants
52 #-----------------------------------------------------------------------------
58 #-----------------------------------------------------------------------------
53
59
54 log = logging.getLogger(__name__)
60 log = logging.getLogger(__name__)
55
61
56
62
57 #-----------------------------------------------------------------------------
63 #-----------------------------------------------------------------------------
58 # Classes and functions
64 # Classes and functions
59 #-----------------------------------------------------------------------------
65 #-----------------------------------------------------------------------------
60
66
61 def is_extension_module(filename):
67 def is_extension_module(filename):
62 """Return whether the given filename is an extension module.
68 """Return whether the given filename is an extension module.
63
69
64 This simply checks that the extension is either .so or .pyd.
70 This simply checks that the extension is either .so or .pyd.
65 """
71 """
66 return os.path.splitext(filename)[1].lower() in ('.so','.pyd')
72 return os.path.splitext(filename)[1].lower() in ('.so','.pyd')
67
73
68
74
69 class DocTestSkip(object):
75 class DocTestSkip(object):
70 """Object wrapper for doctests to be skipped."""
76 """Object wrapper for doctests to be skipped."""
71
77
72 ds_skip = """Doctest to skip.
78 ds_skip = """Doctest to skip.
73 >>> 1 #doctest: +SKIP
79 >>> 1 #doctest: +SKIP
74 """
80 """
75
81
76 def __init__(self,obj):
82 def __init__(self,obj):
77 self.obj = obj
83 self.obj = obj
78
84
79 def __getattribute__(self,key):
85 def __getattribute__(self,key):
80 if key == '__doc__':
86 if key == '__doc__':
81 return DocTestSkip.ds_skip
87 return DocTestSkip.ds_skip
82 else:
88 else:
83 return getattr(object.__getattribute__(self,'obj'),key)
89 return getattr(object.__getattribute__(self,'obj'),key)
84
90
85 # Modified version of the one in the stdlib, that fixes a python bug (doctests
91 # Modified version of the one in the stdlib, that fixes a python bug (doctests
86 # not found in extension modules, http://bugs.python.org/issue3158)
92 # not found in extension modules, http://bugs.python.org/issue3158)
87 class DocTestFinder(doctest.DocTestFinder):
93 class DocTestFinder(doctest.DocTestFinder):
88
94
89 def _from_module(self, module, object):
95 def _from_module(self, module, object):
90 """
96 """
91 Return true if the given object is defined in the given
97 Return true if the given object is defined in the given
92 module.
98 module.
93 """
99 """
94 if module is None:
100 if module is None:
95 return True
101 return True
96 elif inspect.isfunction(object):
102 elif inspect.isfunction(object):
97 return module.__dict__ is object.func_globals
103 return module.__dict__ is object.func_globals
98 elif inspect.isbuiltin(object):
104 elif inspect.isbuiltin(object):
99 return module.__name__ == object.__module__
105 return module.__name__ == object.__module__
100 elif inspect.isclass(object):
106 elif inspect.isclass(object):
101 return module.__name__ == object.__module__
107 return module.__name__ == object.__module__
102 elif inspect.ismethod(object):
108 elif inspect.ismethod(object):
103 # This one may be a bug in cython that fails to correctly set the
109 # This one may be a bug in cython that fails to correctly set the
104 # __module__ attribute of methods, but since the same error is easy
110 # __module__ attribute of methods, but since the same error is easy
105 # to make by extension code writers, having this safety in place
111 # to make by extension code writers, having this safety in place
106 # isn't such a bad idea
112 # isn't such a bad idea
107 return module.__name__ == object.im_class.__module__
113 return module.__name__ == object.im_class.__module__
108 elif inspect.getmodule(object) is not None:
114 elif inspect.getmodule(object) is not None:
109 return module is inspect.getmodule(object)
115 return module is inspect.getmodule(object)
110 elif hasattr(object, '__module__'):
116 elif hasattr(object, '__module__'):
111 return module.__name__ == object.__module__
117 return module.__name__ == object.__module__
112 elif isinstance(object, property):
118 elif isinstance(object, property):
113 return True # [XX] no way not be sure.
119 return True # [XX] no way not be sure.
114 else:
120 else:
115 raise ValueError("object must be a class or function")
121 raise ValueError("object must be a class or function")
116
122
117 def _find(self, tests, obj, name, module, source_lines, globs, seen):
123 def _find(self, tests, obj, name, module, source_lines, globs, seen):
118 """
124 """
119 Find tests for the given object and any contained objects, and
125 Find tests for the given object and any contained objects, and
120 add them to `tests`.
126 add them to `tests`.
121 """
127 """
122 #print '_find for:', obj, name, module # dbg
128 #print '_find for:', obj, name, module # dbg
123 if hasattr(obj,"skip_doctest"):
129 if hasattr(obj,"skip_doctest"):
124 #print 'SKIPPING DOCTEST FOR:',obj # dbg
130 #print 'SKIPPING DOCTEST FOR:',obj # dbg
125 obj = DocTestSkip(obj)
131 obj = DocTestSkip(obj)
126
132
127 doctest.DocTestFinder._find(self,tests, obj, name, module,
133 doctest.DocTestFinder._find(self,tests, obj, name, module,
128 source_lines, globs, seen)
134 source_lines, globs, seen)
129
135
130 # Below we re-run pieces of the above method with manual modifications,
136 # Below we re-run pieces of the above method with manual modifications,
131 # because the original code is buggy and fails to correctly identify
137 # because the original code is buggy and fails to correctly identify
132 # doctests in extension modules.
138 # doctests in extension modules.
133
139
134 # Local shorthands
140 # Local shorthands
135 from inspect import isroutine, isclass, ismodule
141 from inspect import isroutine, isclass, ismodule
136
142
137 # Look for tests in a module's contained objects.
143 # Look for tests in a module's contained objects.
138 if inspect.ismodule(obj) and self._recurse:
144 if inspect.ismodule(obj) and self._recurse:
139 for valname, val in obj.__dict__.items():
145 for valname, val in obj.__dict__.items():
140 valname1 = '%s.%s' % (name, valname)
146 valname1 = '%s.%s' % (name, valname)
141 if ( (isroutine(val) or isclass(val))
147 if ( (isroutine(val) or isclass(val))
142 and self._from_module(module, val) ):
148 and self._from_module(module, val) ):
143
149
144 self._find(tests, val, valname1, module, source_lines,
150 self._find(tests, val, valname1, module, source_lines,
145 globs, seen)
151 globs, seen)
146
152
147 # Look for tests in a class's contained objects.
153 # Look for tests in a class's contained objects.
148 if inspect.isclass(obj) and self._recurse:
154 if inspect.isclass(obj) and self._recurse:
149 #print 'RECURSE into class:',obj # dbg
155 #print 'RECURSE into class:',obj # dbg
150 for valname, val in obj.__dict__.items():
156 for valname, val in obj.__dict__.items():
151 # Special handling for staticmethod/classmethod.
157 # Special handling for staticmethod/classmethod.
152 if isinstance(val, staticmethod):
158 if isinstance(val, staticmethod):
153 val = getattr(obj, valname)
159 val = getattr(obj, valname)
154 if isinstance(val, classmethod):
160 if isinstance(val, classmethod):
155 val = getattr(obj, valname).im_func
161 val = getattr(obj, valname).im_func
156
162
157 # Recurse to methods, properties, and nested classes.
163 # Recurse to methods, properties, and nested classes.
158 if ((inspect.isfunction(val) or inspect.isclass(val) or
164 if ((inspect.isfunction(val) or inspect.isclass(val) or
159 inspect.ismethod(val) or
165 inspect.ismethod(val) or
160 isinstance(val, property)) and
166 isinstance(val, property)) and
161 self._from_module(module, val)):
167 self._from_module(module, val)):
162 valname = '%s.%s' % (name, valname)
168 valname = '%s.%s' % (name, valname)
163 self._find(tests, val, valname, module, source_lines,
169 self._find(tests, val, valname, module, source_lines,
164 globs, seen)
170 globs, seen)
165
171
166
172
167 class IPDoctestOutputChecker(doctest.OutputChecker):
173 class IPDoctestOutputChecker(doctest.OutputChecker):
168 """Second-chance checker with support for random tests.
174 """Second-chance checker with support for random tests.
169
175
170 If the default comparison doesn't pass, this checker looks in the expected
176 If the default comparison doesn't pass, this checker looks in the expected
171 output string for flags that tell us to ignore the output.
177 output string for flags that tell us to ignore the output.
172 """
178 """
173
179
174 random_re = re.compile(r'#\s*random\s+')
180 random_re = re.compile(r'#\s*random\s+')
175
181
176 def check_output(self, want, got, optionflags):
182 def check_output(self, want, got, optionflags):
177 """Check output, accepting special markers embedded in the output.
183 """Check output, accepting special markers embedded in the output.
178
184
179 If the output didn't pass the default validation but the special string
185 If the output didn't pass the default validation but the special string
180 '#random' is included, we accept it."""
186 '#random' is included, we accept it."""
181
187
182 # Let the original tester verify first, in case people have valid tests
188 # Let the original tester verify first, in case people have valid tests
183 # that happen to have a comment saying '#random' embedded in.
189 # that happen to have a comment saying '#random' embedded in.
184 ret = doctest.OutputChecker.check_output(self, want, got,
190 ret = doctest.OutputChecker.check_output(self, want, got,
185 optionflags)
191 optionflags)
186 if not ret and self.random_re.search(want):
192 if not ret and self.random_re.search(want):
187 #print >> sys.stderr, 'RANDOM OK:',want # dbg
193 #print >> sys.stderr, 'RANDOM OK:',want # dbg
188 return True
194 return True
189
195
190 return ret
196 return ret
191
197
192
198
193 class DocTestCase(doctests.DocTestCase):
199 class DocTestCase(doctests.DocTestCase):
194 """Proxy for DocTestCase: provides an address() method that
200 """Proxy for DocTestCase: provides an address() method that
195 returns the correct address for the doctest case. Otherwise
201 returns the correct address for the doctest case. Otherwise
196 acts as a proxy to the test case. To provide hints for address(),
202 acts as a proxy to the test case. To provide hints for address(),
197 an obj may also be passed -- this will be used as the test object
203 an obj may also be passed -- this will be used as the test object
198 for purposes of determining the test address, if it is provided.
204 for purposes of determining the test address, if it is provided.
199 """
205 """
200
206
201 # Note: this method was taken from numpy's nosetester module.
207 # Note: this method was taken from numpy's nosetester module.
202
208
203 # Subclass nose.plugins.doctests.DocTestCase to work around a bug in
209 # Subclass nose.plugins.doctests.DocTestCase to work around a bug in
204 # its constructor that blocks non-default arguments from being passed
210 # its constructor that blocks non-default arguments from being passed
205 # down into doctest.DocTestCase
211 # down into doctest.DocTestCase
206
212
207 def __init__(self, test, optionflags=0, setUp=None, tearDown=None,
213 def __init__(self, test, optionflags=0, setUp=None, tearDown=None,
208 checker=None, obj=None, result_var='_'):
214 checker=None, obj=None, result_var='_'):
209 self._result_var = result_var
215 self._result_var = result_var
210 doctests.DocTestCase.__init__(self, test,
216 doctests.DocTestCase.__init__(self, test,
211 optionflags=optionflags,
217 optionflags=optionflags,
212 setUp=setUp, tearDown=tearDown,
218 setUp=setUp, tearDown=tearDown,
213 checker=checker)
219 checker=checker)
214 # Now we must actually copy the original constructor from the stdlib
220 # Now we must actually copy the original constructor from the stdlib
215 # doctest class, because we can't call it directly and a bug in nose
221 # doctest class, because we can't call it directly and a bug in nose
216 # means it never gets passed the right arguments.
222 # means it never gets passed the right arguments.
217
223
218 self._dt_optionflags = optionflags
224 self._dt_optionflags = optionflags
219 self._dt_checker = checker
225 self._dt_checker = checker
220 self._dt_test = test
226 self._dt_test = test
221 self._dt_test_globs_ori = test.globs
227 self._dt_test_globs_ori = test.globs
222 self._dt_setUp = setUp
228 self._dt_setUp = setUp
223 self._dt_tearDown = tearDown
229 self._dt_tearDown = tearDown
224
230
225 # XXX - store this runner once in the object!
231 # XXX - store this runner once in the object!
226 runner = IPDocTestRunner(optionflags=optionflags,
232 runner = IPDocTestRunner(optionflags=optionflags,
227 checker=checker, verbose=False)
233 checker=checker, verbose=False)
228 self._dt_runner = runner
234 self._dt_runner = runner
229
235
230
236
231 # Each doctest should remember the directory it was loaded from, so
237 # Each doctest should remember the directory it was loaded from, so
232 # things like %run work without too many contortions
238 # things like %run work without too many contortions
233 self._ori_dir = os.path.dirname(test.filename)
239 self._ori_dir = os.path.dirname(test.filename)
234
240
235 # Modified runTest from the default stdlib
241 # Modified runTest from the default stdlib
236 def runTest(self):
242 def runTest(self):
237 test = self._dt_test
243 test = self._dt_test
238 runner = self._dt_runner
244 runner = self._dt_runner
239
245
240 old = sys.stdout
246 old = sys.stdout
241 new = StringIO()
247 new = StringIO()
242 optionflags = self._dt_optionflags
248 optionflags = self._dt_optionflags
243
249
244 if not (optionflags & REPORTING_FLAGS):
250 if not (optionflags & REPORTING_FLAGS):
245 # The option flags don't include any reporting flags,
251 # The option flags don't include any reporting flags,
246 # so add the default reporting flags
252 # so add the default reporting flags
247 optionflags |= _unittest_reportflags
253 optionflags |= _unittest_reportflags
248
254
249 try:
255 try:
250 # Save our current directory and switch out to the one where the
256 # Save our current directory and switch out to the one where the
251 # test was originally created, in case another doctest did a
257 # test was originally created, in case another doctest did a
252 # directory change. We'll restore this in the finally clause.
258 # directory change. We'll restore this in the finally clause.
253 curdir = os.getcwdu()
259 curdir = os.getcwdu()
254 #print 'runTest in dir:', self._ori_dir # dbg
260 #print 'runTest in dir:', self._ori_dir # dbg
255 os.chdir(self._ori_dir)
261 os.chdir(self._ori_dir)
256
262
257 runner.DIVIDER = "-"*70
263 runner.DIVIDER = "-"*70
258 failures, tries = runner.run(test,out=new.write,
264 failures, tries = runner.run(test,out=new.write,
259 clear_globs=False)
265 clear_globs=False)
260 finally:
266 finally:
261 sys.stdout = old
267 sys.stdout = old
262 os.chdir(curdir)
268 os.chdir(curdir)
263
269
264 if failures:
270 if failures:
265 raise self.failureException(self.format_failure(new.getvalue()))
271 raise self.failureException(self.format_failure(new.getvalue()))
266
272
267 def setUp(self):
273 def setUp(self):
268 """Modified test setup that syncs with ipython namespace"""
274 """Modified test setup that syncs with ipython namespace"""
269 #print "setUp test", self._dt_test.examples # dbg
275 #print "setUp test", self._dt_test.examples # dbg
270 if isinstance(self._dt_test.examples[0], IPExample):
276 if isinstance(self._dt_test.examples[0], IPExample):
271 # for IPython examples *only*, we swap the globals with the ipython
277 # for IPython examples *only*, we swap the globals with the ipython
272 # namespace, after updating it with the globals (which doctest
278 # namespace, after updating it with the globals (which doctest
273 # fills with the necessary info from the module being tested).
279 # fills with the necessary info from the module being tested).
274 self.user_ns_orig = {}
280 self.user_ns_orig = {}
275 self.user_ns_orig.update(_ip.user_ns)
281 self.user_ns_orig.update(_ip.user_ns)
276 _ip.user_ns.update(self._dt_test.globs)
282 _ip.user_ns.update(self._dt_test.globs)
277 # We must remove the _ key in the namespace, so that Python's
283 # We must remove the _ key in the namespace, so that Python's
278 # doctest code sets it naturally
284 # doctest code sets it naturally
279 _ip.user_ns.pop('_', None)
285 _ip.user_ns.pop('_', None)
280 _ip.user_ns['__builtins__'] = builtin_mod
286 _ip.user_ns['__builtins__'] = builtin_mod
281 self._dt_test.globs = _ip.user_ns
287 self._dt_test.globs = _ip.user_ns
282
288
283 super(DocTestCase, self).setUp()
289 super(DocTestCase, self).setUp()
284
290
285 def tearDown(self):
291 def tearDown(self):
286
292
287 # Undo the test.globs reassignment we made, so that the parent class
293 # Undo the test.globs reassignment we made, so that the parent class
288 # teardown doesn't destroy the ipython namespace
294 # teardown doesn't destroy the ipython namespace
289 if isinstance(self._dt_test.examples[0], IPExample):
295 if isinstance(self._dt_test.examples[0], IPExample):
290 self._dt_test.globs = self._dt_test_globs_ori
296 self._dt_test.globs = self._dt_test_globs_ori
291 _ip.user_ns.clear()
297 _ip.user_ns.clear()
292 _ip.user_ns.update(self.user_ns_orig)
298 _ip.user_ns.update(self.user_ns_orig)
293
299
294 # XXX - fperez: I am not sure if this is truly a bug in nose 0.11, but
300 # XXX - fperez: I am not sure if this is truly a bug in nose 0.11, but
295 # it does look like one to me: its tearDown method tries to run
301 # it does look like one to me: its tearDown method tries to run
296 #
302 #
297 # delattr(__builtin__, self._result_var)
303 # delattr(__builtin__, self._result_var)
298 #
304 #
299 # without checking that the attribute really is there; it implicitly
305 # without checking that the attribute really is there; it implicitly
300 # assumes it should have been set via displayhook. But if the
306 # assumes it should have been set via displayhook. But if the
301 # displayhook was never called, this doesn't necessarily happen. I
307 # displayhook was never called, this doesn't necessarily happen. I
302 # haven't been able to find a little self-contained example outside of
308 # haven't been able to find a little self-contained example outside of
303 # ipython that would show the problem so I can report it to the nose
309 # ipython that would show the problem so I can report it to the nose
304 # team, but it does happen a lot in our code.
310 # team, but it does happen a lot in our code.
305 #
311 #
306 # So here, we just protect as narrowly as possible by trapping an
312 # So here, we just protect as narrowly as possible by trapping an
307 # attribute error whose message would be the name of self._result_var,
313 # attribute error whose message would be the name of self._result_var,
308 # and letting any other error propagate.
314 # and letting any other error propagate.
309 try:
315 try:
310 super(DocTestCase, self).tearDown()
316 super(DocTestCase, self).tearDown()
311 except AttributeError as exc:
317 except AttributeError as exc:
312 if exc.args[0] != self._result_var:
318 if exc.args[0] != self._result_var:
313 raise
319 raise
314
320
315
321
316 # A simple subclassing of the original with a different class name, so we can
322 # A simple subclassing of the original with a different class name, so we can
317 # distinguish and treat differently IPython examples from pure python ones.
323 # distinguish and treat differently IPython examples from pure python ones.
318 class IPExample(doctest.Example): pass
324 class IPExample(doctest.Example): pass
319
325
320
326
321 class IPExternalExample(doctest.Example):
327 class IPExternalExample(doctest.Example):
322 """Doctest examples to be run in an external process."""
328 """Doctest examples to be run in an external process."""
323
329
324 def __init__(self, source, want, exc_msg=None, lineno=0, indent=0,
330 def __init__(self, source, want, exc_msg=None, lineno=0, indent=0,
325 options=None):
331 options=None):
326 # Parent constructor
332 # Parent constructor
327 doctest.Example.__init__(self,source,want,exc_msg,lineno,indent,options)
333 doctest.Example.__init__(self,source,want,exc_msg,lineno,indent,options)
328
334
329 # An EXTRA newline is needed to prevent pexpect hangs
335 # An EXTRA newline is needed to prevent pexpect hangs
330 self.source += '\n'
336 self.source += '\n'
331
337
332
338
333 class IPDocTestParser(doctest.DocTestParser):
339 class IPDocTestParser(doctest.DocTestParser):
334 """
340 """
335 A class used to parse strings containing doctest examples.
341 A class used to parse strings containing doctest examples.
336
342
337 Note: This is a version modified to properly recognize IPython input and
343 Note: This is a version modified to properly recognize IPython input and
338 convert any IPython examples into valid Python ones.
344 convert any IPython examples into valid Python ones.
339 """
345 """
340 # This regular expression is used to find doctest examples in a
346 # This regular expression is used to find doctest examples in a
341 # string. It defines three groups: `source` is the source code
347 # string. It defines three groups: `source` is the source code
342 # (including leading indentation and prompts); `indent` is the
348 # (including leading indentation and prompts); `indent` is the
343 # indentation of the first (PS1) line of the source code; and
349 # indentation of the first (PS1) line of the source code; and
344 # `want` is the expected output (including leading indentation).
350 # `want` is the expected output (including leading indentation).
345
351
346 # Classic Python prompts or default IPython ones
352 # Classic Python prompts or default IPython ones
347 _PS1_PY = r'>>>'
353 _PS1_PY = r'>>>'
348 _PS2_PY = r'\.\.\.'
354 _PS2_PY = r'\.\.\.'
349
355
350 _PS1_IP = r'In\ \[\d+\]:'
356 _PS1_IP = r'In\ \[\d+\]:'
351 _PS2_IP = r'\ \ \ \.\.\.+:'
357 _PS2_IP = r'\ \ \ \.\.\.+:'
352
358
353 _RE_TPL = r'''
359 _RE_TPL = r'''
354 # Source consists of a PS1 line followed by zero or more PS2 lines.
360 # Source consists of a PS1 line followed by zero or more PS2 lines.
355 (?P<source>
361 (?P<source>
356 (?:^(?P<indent> [ ]*) (?P<ps1> %s) .*) # PS1 line
362 (?:^(?P<indent> [ ]*) (?P<ps1> %s) .*) # PS1 line
357 (?:\n [ ]* (?P<ps2> %s) .*)*) # PS2 lines
363 (?:\n [ ]* (?P<ps2> %s) .*)*) # PS2 lines
358 \n? # a newline
364 \n? # a newline
359 # Want consists of any non-blank lines that do not start with PS1.
365 # Want consists of any non-blank lines that do not start with PS1.
360 (?P<want> (?:(?![ ]*$) # Not a blank line
366 (?P<want> (?:(?![ ]*$) # Not a blank line
361 (?![ ]*%s) # Not a line starting with PS1
367 (?![ ]*%s) # Not a line starting with PS1
362 (?![ ]*%s) # Not a line starting with PS2
368 (?![ ]*%s) # Not a line starting with PS2
363 .*$\n? # But any other line
369 .*$\n? # But any other line
364 )*)
370 )*)
365 '''
371 '''
366
372
367 _EXAMPLE_RE_PY = re.compile( _RE_TPL % (_PS1_PY,_PS2_PY,_PS1_PY,_PS2_PY),
373 _EXAMPLE_RE_PY = re.compile( _RE_TPL % (_PS1_PY,_PS2_PY,_PS1_PY,_PS2_PY),
368 re.MULTILINE | re.VERBOSE)
374 re.MULTILINE | re.VERBOSE)
369
375
370 _EXAMPLE_RE_IP = re.compile( _RE_TPL % (_PS1_IP,_PS2_IP,_PS1_IP,_PS2_IP),
376 _EXAMPLE_RE_IP = re.compile( _RE_TPL % (_PS1_IP,_PS2_IP,_PS1_IP,_PS2_IP),
371 re.MULTILINE | re.VERBOSE)
377 re.MULTILINE | re.VERBOSE)
372
378
373 # Mark a test as being fully random. In this case, we simply append the
379 # Mark a test as being fully random. In this case, we simply append the
374 # random marker ('#random') to each individual example's output. This way
380 # random marker ('#random') to each individual example's output. This way
375 # we don't need to modify any other code.
381 # we don't need to modify any other code.
376 _RANDOM_TEST = re.compile(r'#\s*all-random\s+')
382 _RANDOM_TEST = re.compile(r'#\s*all-random\s+')
377
383
378 # Mark tests to be executed in an external process - currently unsupported.
384 # Mark tests to be executed in an external process - currently unsupported.
379 _EXTERNAL_IP = re.compile(r'#\s*ipdoctest:\s*EXTERNAL')
385 _EXTERNAL_IP = re.compile(r'#\s*ipdoctest:\s*EXTERNAL')
380
386
381 def ip2py(self,source):
387 def ip2py(self,source):
382 """Convert input IPython source into valid Python."""
388 """Convert input IPython source into valid Python."""
383 out = []
389 return TerminalMagics(_ip).cleanup_input(source)
384 newline = out.append
385 #print 'IPSRC:\n',source,'\n###' # dbg
386 # The input source must be first stripped of all bracketing whitespace
387 # and turned into lines, so it looks to the parser like regular user
388 # input
389 for lnum,line in enumerate(source.strip().splitlines()):
390 newline(_ip.prefilter(line,lnum>0))
391 newline('') # ensure a closing newline, needed by doctest
392 #print "PYSRC:", '\n'.join(out) # dbg
393 return '\n'.join(out)
394
390
395 def parse(self, string, name='<string>'):
391 def parse(self, string, name='<string>'):
396 """
392 """
397 Divide the given string into examples and intervening text,
393 Divide the given string into examples and intervening text,
398 and return them as a list of alternating Examples and strings.
394 and return them as a list of alternating Examples and strings.
399 Line numbers for the Examples are 0-based. The optional
395 Line numbers for the Examples are 0-based. The optional
400 argument `name` is a name identifying this string, and is only
396 argument `name` is a name identifying this string, and is only
401 used for error messages.
397 used for error messages.
402 """
398 """
403
399
404 #print 'Parse string:\n',string # dbg
400 #print 'Parse string:\n',string # dbg
405
401
406 string = string.expandtabs()
402 string = string.expandtabs()
407 # If all lines begin with the same indentation, then strip it.
403 # If all lines begin with the same indentation, then strip it.
408 min_indent = self._min_indent(string)
404 min_indent = self._min_indent(string)
409 if min_indent > 0:
405 if min_indent > 0:
410 string = '\n'.join([l[min_indent:] for l in string.split('\n')])
406 string = '\n'.join([l[min_indent:] for l in string.split('\n')])
411
407
412 output = []
408 output = []
413 charno, lineno = 0, 0
409 charno, lineno = 0, 0
414
410
415 # We make 'all random' tests by adding the '# random' mark to every
411 # We make 'all random' tests by adding the '# random' mark to every
416 # block of output in the test.
412 # block of output in the test.
417 if self._RANDOM_TEST.search(string):
413 if self._RANDOM_TEST.search(string):
418 random_marker = '\n# random'
414 random_marker = '\n# random'
419 else:
415 else:
420 random_marker = ''
416 random_marker = ''
421
417
422 # Whether to convert the input from ipython to python syntax
418 # Whether to convert the input from ipython to python syntax
423 ip2py = False
419 ip2py = False
424 # Find all doctest examples in the string. First, try them as Python
420 # Find all doctest examples in the string. First, try them as Python
425 # examples, then as IPython ones
421 # examples, then as IPython ones
426 terms = list(self._EXAMPLE_RE_PY.finditer(string))
422 terms = list(self._EXAMPLE_RE_PY.finditer(string))
427 if terms:
423 if terms:
428 # Normal Python example
424 # Normal Python example
429 #print '-'*70 # dbg
425 #print '-'*70 # dbg
430 #print 'PyExample, Source:\n',string # dbg
426 #print 'PyExample, Source:\n',string # dbg
431 #print '-'*70 # dbg
427 #print '-'*70 # dbg
432 Example = doctest.Example
428 Example = doctest.Example
433 else:
429 else:
434 # It's an ipython example. Note that IPExamples are run
430 # It's an ipython example. Note that IPExamples are run
435 # in-process, so their syntax must be turned into valid python.
431 # in-process, so their syntax must be turned into valid python.
436 # IPExternalExamples are run out-of-process (via pexpect) so they
432 # IPExternalExamples are run out-of-process (via pexpect) so they
437 # don't need any filtering (a real ipython will be executing them).
433 # don't need any filtering (a real ipython will be executing them).
438 terms = list(self._EXAMPLE_RE_IP.finditer(string))
434 terms = list(self._EXAMPLE_RE_IP.finditer(string))
439 if self._EXTERNAL_IP.search(string):
435 if self._EXTERNAL_IP.search(string):
440 #print '-'*70 # dbg
436 #print '-'*70 # dbg
441 #print 'IPExternalExample, Source:\n',string # dbg
437 #print 'IPExternalExample, Source:\n',string # dbg
442 #print '-'*70 # dbg
438 #print '-'*70 # dbg
443 Example = IPExternalExample
439 Example = IPExternalExample
444 else:
440 else:
445 #print '-'*70 # dbg
441 #print '-'*70 # dbg
446 #print 'IPExample, Source:\n',string # dbg
442 #print 'IPExample, Source:\n',string # dbg
447 #print '-'*70 # dbg
443 #print '-'*70 # dbg
448 Example = IPExample
444 Example = IPExample
449 ip2py = True
445 ip2py = True
450
446
451 for m in terms:
447 for m in terms:
452 # Add the pre-example text to `output`.
448 # Add the pre-example text to `output`.
453 output.append(string[charno:m.start()])
449 output.append(string[charno:m.start()])
454 # Update lineno (lines before this example)
450 # Update lineno (lines before this example)
455 lineno += string.count('\n', charno, m.start())
451 lineno += string.count('\n', charno, m.start())
456 # Extract info from the regexp match.
452 # Extract info from the regexp match.
457 (source, options, want, exc_msg) = \
453 (source, options, want, exc_msg) = \
458 self._parse_example(m, name, lineno,ip2py)
454 self._parse_example(m, name, lineno,ip2py)
459
455
460 # Append the random-output marker (it defaults to empty in most
456 # Append the random-output marker (it defaults to empty in most
461 # cases, it's only non-empty for 'all-random' tests):
457 # cases, it's only non-empty for 'all-random' tests):
462 want += random_marker
458 want += random_marker
463
459
464 if Example is IPExternalExample:
460 if Example is IPExternalExample:
465 options[doctest.NORMALIZE_WHITESPACE] = True
461 options[doctest.NORMALIZE_WHITESPACE] = True
466 want += '\n'
462 want += '\n'
467
463
468 # Create an Example, and add it to the list.
464 # Create an Example, and add it to the list.
469 if not self._IS_BLANK_OR_COMMENT(source):
465 if not self._IS_BLANK_OR_COMMENT(source):
470 output.append(Example(source, want, exc_msg,
466 output.append(Example(source, want, exc_msg,
471 lineno=lineno,
467 lineno=lineno,
472 indent=min_indent+len(m.group('indent')),
468 indent=min_indent+len(m.group('indent')),
473 options=options))
469 options=options))
474 # Update lineno (lines inside this example)
470 # Update lineno (lines inside this example)
475 lineno += string.count('\n', m.start(), m.end())
471 lineno += string.count('\n', m.start(), m.end())
476 # Update charno.
472 # Update charno.
477 charno = m.end()
473 charno = m.end()
478 # Add any remaining post-example text to `output`.
474 # Add any remaining post-example text to `output`.
479 output.append(string[charno:])
475 output.append(string[charno:])
480 return output
476 return output
481
477
482 def _parse_example(self, m, name, lineno,ip2py=False):
478 def _parse_example(self, m, name, lineno,ip2py=False):
483 """
479 """
484 Given a regular expression match from `_EXAMPLE_RE` (`m`),
480 Given a regular expression match from `_EXAMPLE_RE` (`m`),
485 return a pair `(source, want)`, where `source` is the matched
481 return a pair `(source, want)`, where `source` is the matched
486 example's source code (with prompts and indentation stripped);
482 example's source code (with prompts and indentation stripped);
487 and `want` is the example's expected output (with indentation
483 and `want` is the example's expected output (with indentation
488 stripped).
484 stripped).
489
485
490 `name` is the string's name, and `lineno` is the line number
486 `name` is the string's name, and `lineno` is the line number
491 where the example starts; both are used for error messages.
487 where the example starts; both are used for error messages.
492
488
493 Optional:
489 Optional:
494 `ip2py`: if true, filter the input via IPython to convert the syntax
490 `ip2py`: if true, filter the input via IPython to convert the syntax
495 into valid python.
491 into valid python.
496 """
492 """
497
493
498 # Get the example's indentation level.
494 # Get the example's indentation level.
499 indent = len(m.group('indent'))
495 indent = len(m.group('indent'))
500
496
501 # Divide source into lines; check that they're properly
497 # Divide source into lines; check that they're properly
502 # indented; and then strip their indentation & prompts.
498 # indented; and then strip their indentation & prompts.
503 source_lines = m.group('source').split('\n')
499 source_lines = m.group('source').split('\n')
504
500
505 # We're using variable-length input prompts
501 # We're using variable-length input prompts
506 ps1 = m.group('ps1')
502 ps1 = m.group('ps1')
507 ps2 = m.group('ps2')
503 ps2 = m.group('ps2')
508 ps1_len = len(ps1)
504 ps1_len = len(ps1)
509
505
510 self._check_prompt_blank(source_lines, indent, name, lineno,ps1_len)
506 self._check_prompt_blank(source_lines, indent, name, lineno,ps1_len)
511 if ps2:
507 if ps2:
512 self._check_prefix(source_lines[1:], ' '*indent + ps2, name, lineno)
508 self._check_prefix(source_lines[1:], ' '*indent + ps2, name, lineno)
513
509
514 source = '\n'.join([sl[indent+ps1_len+1:] for sl in source_lines])
510 source = '\n'.join([sl[indent+ps1_len+1:] for sl in source_lines])
515
511
516 if ip2py:
512 if ip2py:
517 # Convert source input from IPython into valid Python syntax
513 # Convert source input from IPython into valid Python syntax
518 source = self.ip2py(source)
514 source = self.ip2py(source)
519
515
520 # Divide want into lines; check that it's properly indented; and
516 # Divide want into lines; check that it's properly indented; and
521 # then strip the indentation. Spaces before the last newline should
517 # then strip the indentation. Spaces before the last newline should
522 # be preserved, so plain rstrip() isn't good enough.
518 # be preserved, so plain rstrip() isn't good enough.
523 want = m.group('want')
519 want = m.group('want')
524 want_lines = want.split('\n')
520 want_lines = want.split('\n')
525 if len(want_lines) > 1 and re.match(r' *$', want_lines[-1]):
521 if len(want_lines) > 1 and re.match(r' *$', want_lines[-1]):
526 del want_lines[-1] # forget final newline & spaces after it
522 del want_lines[-1] # forget final newline & spaces after it
527 self._check_prefix(want_lines, ' '*indent, name,
523 self._check_prefix(want_lines, ' '*indent, name,
528 lineno + len(source_lines))
524 lineno + len(source_lines))
529
525
530 # Remove ipython output prompt that might be present in the first line
526 # Remove ipython output prompt that might be present in the first line
531 want_lines[0] = re.sub(r'Out\[\d+\]: \s*?\n?','',want_lines[0])
527 want_lines[0] = re.sub(r'Out\[\d+\]: \s*?\n?','',want_lines[0])
532
528
533 want = '\n'.join([wl[indent:] for wl in want_lines])
529 want = '\n'.join([wl[indent:] for wl in want_lines])
534
530
535 # If `want` contains a traceback message, then extract it.
531 # If `want` contains a traceback message, then extract it.
536 m = self._EXCEPTION_RE.match(want)
532 m = self._EXCEPTION_RE.match(want)
537 if m:
533 if m:
538 exc_msg = m.group('msg')
534 exc_msg = m.group('msg')
539 else:
535 else:
540 exc_msg = None
536 exc_msg = None
541
537
542 # Extract options from the source.
538 # Extract options from the source.
543 options = self._find_options(source, name, lineno)
539 options = self._find_options(source, name, lineno)
544
540
545 return source, options, want, exc_msg
541 return source, options, want, exc_msg
546
542
547 def _check_prompt_blank(self, lines, indent, name, lineno, ps1_len):
543 def _check_prompt_blank(self, lines, indent, name, lineno, ps1_len):
548 """
544 """
549 Given the lines of a source string (including prompts and
545 Given the lines of a source string (including prompts and
550 leading indentation), check to make sure that every prompt is
546 leading indentation), check to make sure that every prompt is
551 followed by a space character. If any line is not followed by
547 followed by a space character. If any line is not followed by
552 a space character, then raise ValueError.
548 a space character, then raise ValueError.
553
549
554 Note: IPython-modified version which takes the input prompt length as a
550 Note: IPython-modified version which takes the input prompt length as a
555 parameter, so that prompts of variable length can be dealt with.
551 parameter, so that prompts of variable length can be dealt with.
556 """
552 """
557 space_idx = indent+ps1_len
553 space_idx = indent+ps1_len
558 min_len = space_idx+1
554 min_len = space_idx+1
559 for i, line in enumerate(lines):
555 for i, line in enumerate(lines):
560 if len(line) >= min_len and line[space_idx] != ' ':
556 if len(line) >= min_len and line[space_idx] != ' ':
561 raise ValueError('line %r of the docstring for %s '
557 raise ValueError('line %r of the docstring for %s '
562 'lacks blank after %s: %r' %
558 'lacks blank after %s: %r' %
563 (lineno+i+1, name,
559 (lineno+i+1, name,
564 line[indent:space_idx], line))
560 line[indent:space_idx], line))
565
561
566
562
567 SKIP = doctest.register_optionflag('SKIP')
563 SKIP = doctest.register_optionflag('SKIP')
568
564
569
565
570 class IPDocTestRunner(doctest.DocTestRunner,object):
566 class IPDocTestRunner(doctest.DocTestRunner,object):
571 """Test runner that synchronizes the IPython namespace with test globals.
567 """Test runner that synchronizes the IPython namespace with test globals.
572 """
568 """
573
569
574 def run(self, test, compileflags=None, out=None, clear_globs=True):
570 def run(self, test, compileflags=None, out=None, clear_globs=True):
575
571
576 # Hack: ipython needs access to the execution context of the example,
572 # Hack: ipython needs access to the execution context of the example,
577 # so that it can propagate user variables loaded by %run into
573 # so that it can propagate user variables loaded by %run into
578 # test.globs. We put them here into our modified %run as a function
574 # test.globs. We put them here into our modified %run as a function
579 # attribute. Our new %run will then only make the namespace update
575 # attribute. Our new %run will then only make the namespace update
580 # when called (rather than unconconditionally updating test.globs here
576 # when called (rather than unconconditionally updating test.globs here
581 # for all examples, most of which won't be calling %run anyway).
577 # for all examples, most of which won't be calling %run anyway).
582 #_ip._ipdoctest_test_globs = test.globs
578 #_ip._ipdoctest_test_globs = test.globs
583 #_ip._ipdoctest_test_filename = test.filename
579 #_ip._ipdoctest_test_filename = test.filename
584
580
585 test.globs.update(_ip.user_ns)
581 test.globs.update(_ip.user_ns)
586
582
587 return super(IPDocTestRunner,self).run(test,
583 return super(IPDocTestRunner,self).run(test,
588 compileflags,out,clear_globs)
584 compileflags,out,clear_globs)
589
585
590
586
591 class DocFileCase(doctest.DocFileCase):
587 class DocFileCase(doctest.DocFileCase):
592 """Overrides to provide filename
588 """Overrides to provide filename
593 """
589 """
594 def address(self):
590 def address(self):
595 return (self._dt_test.filename, None, None)
591 return (self._dt_test.filename, None, None)
596
592
597
593
598 class ExtensionDoctest(doctests.Doctest):
594 class ExtensionDoctest(doctests.Doctest):
599 """Nose Plugin that supports doctests in extension modules.
595 """Nose Plugin that supports doctests in extension modules.
600 """
596 """
601 name = 'extdoctest' # call nosetests with --with-extdoctest
597 name = 'extdoctest' # call nosetests with --with-extdoctest
602 enabled = True
598 enabled = True
603
599
604 def __init__(self,exclude_patterns=None):
600 def __init__(self,exclude_patterns=None):
605 """Create a new ExtensionDoctest plugin.
601 """Create a new ExtensionDoctest plugin.
606
602
607 Parameters
603 Parameters
608 ----------
604 ----------
609
605
610 exclude_patterns : sequence of strings, optional
606 exclude_patterns : sequence of strings, optional
611 These patterns are compiled as regular expressions, subsequently used
607 These patterns are compiled as regular expressions, subsequently used
612 to exclude any filename which matches them from inclusion in the test
608 to exclude any filename which matches them from inclusion in the test
613 suite (using pattern.search(), NOT pattern.match() ).
609 suite (using pattern.search(), NOT pattern.match() ).
614 """
610 """
615
611
616 if exclude_patterns is None:
612 if exclude_patterns is None:
617 exclude_patterns = []
613 exclude_patterns = []
618 self.exclude_patterns = map(re.compile,exclude_patterns)
614 self.exclude_patterns = map(re.compile,exclude_patterns)
619 doctests.Doctest.__init__(self)
615 doctests.Doctest.__init__(self)
620
616
621 def options(self, parser, env=os.environ):
617 def options(self, parser, env=os.environ):
622 Plugin.options(self, parser, env)
618 Plugin.options(self, parser, env)
623 parser.add_option('--doctest-tests', action='store_true',
619 parser.add_option('--doctest-tests', action='store_true',
624 dest='doctest_tests',
620 dest='doctest_tests',
625 default=env.get('NOSE_DOCTEST_TESTS',True),
621 default=env.get('NOSE_DOCTEST_TESTS',True),
626 help="Also look for doctests in test modules. "
622 help="Also look for doctests in test modules. "
627 "Note that classes, methods and functions should "
623 "Note that classes, methods and functions should "
628 "have either doctests or non-doctest tests, "
624 "have either doctests or non-doctest tests, "
629 "not both. [NOSE_DOCTEST_TESTS]")
625 "not both. [NOSE_DOCTEST_TESTS]")
630 parser.add_option('--doctest-extension', action="append",
626 parser.add_option('--doctest-extension', action="append",
631 dest="doctestExtension",
627 dest="doctestExtension",
632 help="Also look for doctests in files with "
628 help="Also look for doctests in files with "
633 "this extension [NOSE_DOCTEST_EXTENSION]")
629 "this extension [NOSE_DOCTEST_EXTENSION]")
634 # Set the default as a list, if given in env; otherwise
630 # Set the default as a list, if given in env; otherwise
635 # an additional value set on the command line will cause
631 # an additional value set on the command line will cause
636 # an error.
632 # an error.
637 env_setting = env.get('NOSE_DOCTEST_EXTENSION')
633 env_setting = env.get('NOSE_DOCTEST_EXTENSION')
638 if env_setting is not None:
634 if env_setting is not None:
639 parser.set_defaults(doctestExtension=tolist(env_setting))
635 parser.set_defaults(doctestExtension=tolist(env_setting))
640
636
641
637
642 def configure(self, options, config):
638 def configure(self, options, config):
643 Plugin.configure(self, options, config)
639 Plugin.configure(self, options, config)
644 # Pull standard doctest plugin out of config; we will do doctesting
640 # Pull standard doctest plugin out of config; we will do doctesting
645 config.plugins.plugins = [p for p in config.plugins.plugins
641 config.plugins.plugins = [p for p in config.plugins.plugins
646 if p.name != 'doctest']
642 if p.name != 'doctest']
647 self.doctest_tests = options.doctest_tests
643 self.doctest_tests = options.doctest_tests
648 self.extension = tolist(options.doctestExtension)
644 self.extension = tolist(options.doctestExtension)
649
645
650 self.parser = doctest.DocTestParser()
646 self.parser = doctest.DocTestParser()
651 self.finder = DocTestFinder()
647 self.finder = DocTestFinder()
652 self.checker = IPDoctestOutputChecker()
648 self.checker = IPDoctestOutputChecker()
653 self.globs = None
649 self.globs = None
654 self.extraglobs = None
650 self.extraglobs = None
655
651
656
652
657 def loadTestsFromExtensionModule(self,filename):
653 def loadTestsFromExtensionModule(self,filename):
658 bpath,mod = os.path.split(filename)
654 bpath,mod = os.path.split(filename)
659 modname = os.path.splitext(mod)[0]
655 modname = os.path.splitext(mod)[0]
660 try:
656 try:
661 sys.path.append(bpath)
657 sys.path.append(bpath)
662 module = __import__(modname)
658 module = __import__(modname)
663 tests = list(self.loadTestsFromModule(module))
659 tests = list(self.loadTestsFromModule(module))
664 finally:
660 finally:
665 sys.path.pop()
661 sys.path.pop()
666 return tests
662 return tests
667
663
668 # NOTE: the method below is almost a copy of the original one in nose, with
664 # NOTE: the method below is almost a copy of the original one in nose, with
669 # a few modifications to control output checking.
665 # a few modifications to control output checking.
670
666
671 def loadTestsFromModule(self, module):
667 def loadTestsFromModule(self, module):
672 #print '*** ipdoctest - lTM',module # dbg
668 #print '*** ipdoctest - lTM',module # dbg
673
669
674 if not self.matches(module.__name__):
670 if not self.matches(module.__name__):
675 log.debug("Doctest doesn't want module %s", module)
671 log.debug("Doctest doesn't want module %s", module)
676 return
672 return
677
673
678 tests = self.finder.find(module,globs=self.globs,
674 tests = self.finder.find(module,globs=self.globs,
679 extraglobs=self.extraglobs)
675 extraglobs=self.extraglobs)
680 if not tests:
676 if not tests:
681 return
677 return
682
678
683 # always use whitespace and ellipsis options
679 # always use whitespace and ellipsis options
684 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
680 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
685
681
686 tests.sort()
682 tests.sort()
687 module_file = module.__file__
683 module_file = module.__file__
688 if module_file[-4:] in ('.pyc', '.pyo'):
684 if module_file[-4:] in ('.pyc', '.pyo'):
689 module_file = module_file[:-1]
685 module_file = module_file[:-1]
690 for test in tests:
686 for test in tests:
691 if not test.examples:
687 if not test.examples:
692 continue
688 continue
693 if not test.filename:
689 if not test.filename:
694 test.filename = module_file
690 test.filename = module_file
695
691
696 yield DocTestCase(test,
692 yield DocTestCase(test,
697 optionflags=optionflags,
693 optionflags=optionflags,
698 checker=self.checker)
694 checker=self.checker)
699
695
700
696
701 def loadTestsFromFile(self, filename):
697 def loadTestsFromFile(self, filename):
702 #print "ipdoctest - from file", filename # dbg
698 #print "ipdoctest - from file", filename # dbg
703 if is_extension_module(filename):
699 if is_extension_module(filename):
704 for t in self.loadTestsFromExtensionModule(filename):
700 for t in self.loadTestsFromExtensionModule(filename):
705 yield t
701 yield t
706 else:
702 else:
707 if self.extension and anyp(filename.endswith, self.extension):
703 if self.extension and anyp(filename.endswith, self.extension):
708 name = os.path.basename(filename)
704 name = os.path.basename(filename)
709 dh = open(filename)
705 dh = open(filename)
710 try:
706 try:
711 doc = dh.read()
707 doc = dh.read()
712 finally:
708 finally:
713 dh.close()
709 dh.close()
714 test = self.parser.get_doctest(
710 test = self.parser.get_doctest(
715 doc, globs={'__file__': filename}, name=name,
711 doc, globs={'__file__': filename}, name=name,
716 filename=filename, lineno=0)
712 filename=filename, lineno=0)
717 if test.examples:
713 if test.examples:
718 #print 'FileCase:',test.examples # dbg
714 #print 'FileCase:',test.examples # dbg
719 yield DocFileCase(test)
715 yield DocFileCase(test)
720 else:
716 else:
721 yield False # no tests to load
717 yield False # no tests to load
722
718
723 def wantFile(self,filename):
719 def wantFile(self,filename):
724 """Return whether the given filename should be scanned for tests.
720 """Return whether the given filename should be scanned for tests.
725
721
726 Modified version that accepts extension modules as valid containers for
722 Modified version that accepts extension modules as valid containers for
727 doctests.
723 doctests.
728 """
724 """
729 #print '*** ipdoctest- wantFile:',filename # dbg
725 #print '*** ipdoctest- wantFile:',filename # dbg
730
726
731 for pat in self.exclude_patterns:
727 for pat in self.exclude_patterns:
732 if pat.search(filename):
728 if pat.search(filename):
733 # print '###>>> SKIP:',filename # dbg
729 # print '###>>> SKIP:',filename # dbg
734 return False
730 return False
735
731
736 if is_extension_module(filename):
732 if is_extension_module(filename):
737 return True
733 return True
738 else:
734 else:
739 return doctests.Doctest.wantFile(self,filename)
735 return doctests.Doctest.wantFile(self,filename)
740
736
741 def wantDirectory(self, directory):
737 def wantDirectory(self, directory):
742 """Return whether the given directory should be scanned for tests.
738 """Return whether the given directory should be scanned for tests.
743
739
744 Modified version that supports exclusions.
740 Modified version that supports exclusions.
745 """
741 """
746
742
747 for pat in self.exclude_patterns:
743 for pat in self.exclude_patterns:
748 if pat.search(directory):
744 if pat.search(directory):
749 return False
745 return False
750 return True
746 return True
751
747
752
748
753 class IPythonDoctest(ExtensionDoctest):
749 class IPythonDoctest(ExtensionDoctest):
754 """Nose Plugin that supports doctests in extension modules.
750 """Nose Plugin that supports doctests in extension modules.
755 """
751 """
756 name = 'ipdoctest' # call nosetests with --with-ipdoctest
752 name = 'ipdoctest' # call nosetests with --with-ipdoctest
757 enabled = True
753 enabled = True
758
754
759 def makeTest(self, obj, parent):
755 def makeTest(self, obj, parent):
760 """Look for doctests in the given object, which will be a
756 """Look for doctests in the given object, which will be a
761 function, method or class.
757 function, method or class.
762 """
758 """
763 #print 'Plugin analyzing:', obj, parent # dbg
759 #print 'Plugin analyzing:', obj, parent # dbg
764 # always use whitespace and ellipsis options
760 # always use whitespace and ellipsis options
765 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
761 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
766
762
767 doctests = self.finder.find(obj, module=getmodule(parent))
763 doctests = self.finder.find(obj, module=getmodule(parent))
768 if doctests:
764 if doctests:
769 for test in doctests:
765 for test in doctests:
770 if len(test.examples) == 0:
766 if len(test.examples) == 0:
771 continue
767 continue
772
768
773 yield DocTestCase(test, obj=obj,
769 yield DocTestCase(test, obj=obj,
774 optionflags=optionflags,
770 optionflags=optionflags,
775 checker=self.checker)
771 checker=self.checker)
776
772
777 def options(self, parser, env=os.environ):
773 def options(self, parser, env=os.environ):
778 #print "Options for nose plugin:", self.name # dbg
774 #print "Options for nose plugin:", self.name # dbg
779 Plugin.options(self, parser, env)
775 Plugin.options(self, parser, env)
780 parser.add_option('--ipdoctest-tests', action='store_true',
776 parser.add_option('--ipdoctest-tests', action='store_true',
781 dest='ipdoctest_tests',
777 dest='ipdoctest_tests',
782 default=env.get('NOSE_IPDOCTEST_TESTS',True),
778 default=env.get('NOSE_IPDOCTEST_TESTS',True),
783 help="Also look for doctests in test modules. "
779 help="Also look for doctests in test modules. "
784 "Note that classes, methods and functions should "
780 "Note that classes, methods and functions should "
785 "have either doctests or non-doctest tests, "
781 "have either doctests or non-doctest tests, "
786 "not both. [NOSE_IPDOCTEST_TESTS]")
782 "not both. [NOSE_IPDOCTEST_TESTS]")
787 parser.add_option('--ipdoctest-extension', action="append",
783 parser.add_option('--ipdoctest-extension', action="append",
788 dest="ipdoctest_extension",
784 dest="ipdoctest_extension",
789 help="Also look for doctests in files with "
785 help="Also look for doctests in files with "
790 "this extension [NOSE_IPDOCTEST_EXTENSION]")
786 "this extension [NOSE_IPDOCTEST_EXTENSION]")
791 # Set the default as a list, if given in env; otherwise
787 # Set the default as a list, if given in env; otherwise
792 # an additional value set on the command line will cause
788 # an additional value set on the command line will cause
793 # an error.
789 # an error.
794 env_setting = env.get('NOSE_IPDOCTEST_EXTENSION')
790 env_setting = env.get('NOSE_IPDOCTEST_EXTENSION')
795 if env_setting is not None:
791 if env_setting is not None:
796 parser.set_defaults(ipdoctest_extension=tolist(env_setting))
792 parser.set_defaults(ipdoctest_extension=tolist(env_setting))
797
793
798 def configure(self, options, config):
794 def configure(self, options, config):
799 #print "Configuring nose plugin:", self.name # dbg
795 #print "Configuring nose plugin:", self.name # dbg
800 Plugin.configure(self, options, config)
796 Plugin.configure(self, options, config)
801 # Pull standard doctest plugin out of config; we will do doctesting
797 # Pull standard doctest plugin out of config; we will do doctesting
802 config.plugins.plugins = [p for p in config.plugins.plugins
798 config.plugins.plugins = [p for p in config.plugins.plugins
803 if p.name != 'doctest']
799 if p.name != 'doctest']
804 self.doctest_tests = options.ipdoctest_tests
800 self.doctest_tests = options.ipdoctest_tests
805 self.extension = tolist(options.ipdoctest_extension)
801 self.extension = tolist(options.ipdoctest_extension)
806
802
807 self.parser = IPDocTestParser()
803 self.parser = IPDocTestParser()
808 self.finder = DocTestFinder(parser=self.parser)
804 self.finder = DocTestFinder(parser=self.parser)
809 self.checker = IPDoctestOutputChecker()
805 self.checker = IPDoctestOutputChecker()
810 self.globs = None
806 self.globs = None
811 self.extraglobs = None
807 self.extraglobs = None
@@ -1,13 +1,23 b''
1 =====================
1 =====================
2 Development version
2 Development version
3 =====================
3 =====================
4
4
5 This document describes in-flight development work.
5 This document describes in-flight development work.
6
6
7 The CodeMirror js library has been updated fron 2.23 to 2.32
7 The CodeMirror js library has been updated fron 2.23 to 2.32
8 this might induce a few changes in behavior of keymaps in the notebook,
8 this might induce a few changes in behavior of keymaps in the notebook,
9 especially intenting/deindenting blocks that is now bound to Ctrl+] and ctr+[
9 especially intenting/deindenting blocks that is now bound to Ctrl+] and ctr+[
10
10
11 * Exception types can now be displayed with a custom traceback, by defining a
11 * Exception types can now be displayed with a custom traceback, by defining a
12 ``_render_traceback_()`` method which returns a list of strings, each
12 ``_render_traceback_()`` method which returns a list of strings, each
13 containing one line of the traceback.
13 containing one line of the traceback.
14
15 Backwards incompatible changes
16 ------------------------------
17
18 * Calling :meth:`InteractiveShell.prefilter` will no longer perform static
19 transformations - the processing of escaped commands such as ``%magic`` and
20 ``!system``, and stripping input prompts from code blocks. This functionality
21 was duplicated in :mod:`IPython.core.inputsplitter`, and the latter version
22 was already what IPython relied on. A new API to transform input will be ready
23 before release.
General Comments 0
You need to be logged in to leave comments. Login now