##// END OF EJS Templates
Keywords should shadow magic functions
Thomas Kluyver -
Show More
@@ -1,745 +1,747 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 from keyword import iskeyword
27 import re
28 import re
28
29
29 from IPython.core.autocall import IPyAutocall
30 from IPython.core.autocall import IPyAutocall
30 from IPython.config.configurable import Configurable
31 from IPython.config.configurable import Configurable
31 from IPython.core.inputsplitter import (
32 from IPython.core.inputsplitter import (
32 ESC_MAGIC,
33 ESC_MAGIC,
33 ESC_QUOTE,
34 ESC_QUOTE,
34 ESC_QUOTE2,
35 ESC_QUOTE2,
35 ESC_PAREN,
36 ESC_PAREN,
36 )
37 )
37 from IPython.core.macro import Macro
38 from IPython.core.macro import Macro
38 from IPython.core.splitinput import LineInfo
39 from IPython.core.splitinput import LineInfo
39
40
40 from IPython.utils.traitlets import (
41 from IPython.utils.traitlets import (
41 List, Integer, Unicode, CBool, Bool, Instance, CRegExp
42 List, Integer, Unicode, CBool, Bool, Instance, CRegExp
42 )
43 )
43
44
44 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
45 # Global utilities, errors and constants
46 # Global utilities, errors and constants
46 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
47
48
48
49
49 class PrefilterError(Exception):
50 class PrefilterError(Exception):
50 pass
51 pass
51
52
52
53
53 # RegExp to identify potential function names
54 # RegExp to identify potential function names
54 re_fun_name = re.compile(r'[a-zA-Z_]([a-zA-Z0-9_.]*) *$')
55 re_fun_name = re.compile(r'[a-zA-Z_]([a-zA-Z0-9_.]*) *$')
55
56
56 # RegExp to exclude strings with this start from autocalling. In
57 # RegExp to exclude strings with this start from autocalling. In
57 # particular, all binary operators should be excluded, so that if foo is
58 # particular, all binary operators should be excluded, so that if foo is
58 # callable, foo OP bar doesn't become foo(OP bar), which is invalid. The
59 # callable, foo OP bar doesn't become foo(OP bar), which is invalid. The
59 # characters '!=()' don't need to be checked for, as the checkPythonChars
60 # characters '!=()' don't need to be checked for, as the checkPythonChars
60 # routine explicitely does so, to catch direct calls and rebindings of
61 # routine explicitely does so, to catch direct calls and rebindings of
61 # existing names.
62 # existing names.
62
63
63 # Warning: the '-' HAS TO BE AT THE END of the first group, otherwise
64 # Warning: the '-' HAS TO BE AT THE END of the first group, otherwise
64 # it affects the rest of the group in square brackets.
65 # it affects the rest of the group in square brackets.
65 re_exclude_auto = re.compile(r'^[,&^\|\*/\+-]'
66 re_exclude_auto = re.compile(r'^[,&^\|\*/\+-]'
66 r'|^is |^not |^in |^and |^or ')
67 r'|^is |^not |^in |^and |^or ')
67
68
68 # try to catch also methods for stuff in lists/tuples/dicts: off
69 # try to catch also methods for stuff in lists/tuples/dicts: off
69 # (experimental). For this to work, the line_split regexp would need
70 # (experimental). For this to work, the line_split regexp would need
70 # to be modified so it wouldn't break things at '['. That line is
71 # to be modified so it wouldn't break things at '['. That line is
71 # nasty enough that I shouldn't change it until I can test it _well_.
72 # nasty enough that I shouldn't change it until I can test it _well_.
72 #self.re_fun_name = re.compile (r'[a-zA-Z_]([a-zA-Z0-9_.\[\]]*) ?$')
73 #self.re_fun_name = re.compile (r'[a-zA-Z_]([a-zA-Z0-9_.\[\]]*) ?$')
73
74
74
75
75 # Handler Check Utilities
76 # Handler Check Utilities
76 def is_shadowed(identifier, ip):
77 def is_shadowed(identifier, ip):
77 """Is the given identifier defined in one of the namespaces which shadow
78 """Is the given identifier defined in one of the namespaces which shadow
78 the alias and magic namespaces? Note that an identifier is different
79 the alias and magic namespaces? Note that an identifier is different
79 than ifun, because it can not contain a '.' character."""
80 than ifun, because it can not contain a '.' character."""
80 # This is much safer than calling ofind, which can change state
81 # This is much safer than calling ofind, which can change state
81 return (identifier in ip.user_ns \
82 return (identifier in ip.user_ns \
82 or identifier in ip.user_global_ns \
83 or identifier in ip.user_global_ns \
83 or identifier in ip.ns_table['builtin'])
84 or identifier in ip.ns_table['builtin']\
85 or iskeyword(identifier))
84
86
85
87
86 #-----------------------------------------------------------------------------
88 #-----------------------------------------------------------------------------
87 # Main Prefilter manager
89 # Main Prefilter manager
88 #-----------------------------------------------------------------------------
90 #-----------------------------------------------------------------------------
89
91
90
92
91 class PrefilterManager(Configurable):
93 class PrefilterManager(Configurable):
92 """Main prefilter component.
94 """Main prefilter component.
93
95
94 The IPython prefilter is run on all user input before it is run. The
96 The IPython prefilter is run on all user input before it is run. The
95 prefilter consumes lines of input and produces transformed lines of
97 prefilter consumes lines of input and produces transformed lines of
96 input.
98 input.
97
99
98 The iplementation consists of two phases:
100 The iplementation consists of two phases:
99
101
100 1. Transformers
102 1. Transformers
101 2. Checkers and handlers
103 2. Checkers and handlers
102
104
103 Over time, we plan on deprecating the checkers and handlers and doing
105 Over time, we plan on deprecating the checkers and handlers and doing
104 everything in the transformers.
106 everything in the transformers.
105
107
106 The transformers are instances of :class:`PrefilterTransformer` and have
108 The transformers are instances of :class:`PrefilterTransformer` and have
107 a single method :meth:`transform` that takes a line and returns a
109 a single method :meth:`transform` that takes a line and returns a
108 transformed line. The transformation can be accomplished using any
110 transformed line. The transformation can be accomplished using any
109 tool, but our current ones use regular expressions for speed.
111 tool, but our current ones use regular expressions for speed.
110
112
111 After all the transformers have been run, the line is fed to the checkers,
113 After all the transformers have been run, the line is fed to the checkers,
112 which are instances of :class:`PrefilterChecker`. The line is passed to
114 which are instances of :class:`PrefilterChecker`. The line is passed to
113 the :meth:`check` method, which either returns `None` or a
115 the :meth:`check` method, which either returns `None` or a
114 :class:`PrefilterHandler` instance. If `None` is returned, the other
116 :class:`PrefilterHandler` instance. If `None` is returned, the other
115 checkers are tried. If an :class:`PrefilterHandler` instance is returned,
117 checkers are tried. If an :class:`PrefilterHandler` instance is returned,
116 the line is passed to the :meth:`handle` method of the returned
118 the line is passed to the :meth:`handle` method of the returned
117 handler and no further checkers are tried.
119 handler and no further checkers are tried.
118
120
119 Both transformers and checkers have a `priority` attribute, that determines
121 Both transformers and checkers have a `priority` attribute, that determines
120 the order in which they are called. Smaller priorities are tried first.
122 the order in which they are called. Smaller priorities are tried first.
121
123
122 Both transformers and checkers also have `enabled` attribute, which is
124 Both transformers and checkers also have `enabled` attribute, which is
123 a boolean that determines if the instance is used.
125 a boolean that determines if the instance is used.
124
126
125 Users or developers can change the priority or enabled attribute of
127 Users or developers can change the priority or enabled attribute of
126 transformers or checkers, but they must call the :meth:`sort_checkers`
128 transformers or checkers, but they must call the :meth:`sort_checkers`
127 or :meth:`sort_transformers` method after changing the priority.
129 or :meth:`sort_transformers` method after changing the priority.
128 """
130 """
129
131
130 multi_line_specials = CBool(True, config=True)
132 multi_line_specials = CBool(True, config=True)
131 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
133 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
132
134
133 def __init__(self, shell=None, **kwargs):
135 def __init__(self, shell=None, **kwargs):
134 super(PrefilterManager, self).__init__(shell=shell, **kwargs)
136 super(PrefilterManager, self).__init__(shell=shell, **kwargs)
135 self.shell = shell
137 self.shell = shell
136 self.init_transformers()
138 self.init_transformers()
137 self.init_handlers()
139 self.init_handlers()
138 self.init_checkers()
140 self.init_checkers()
139
141
140 #-------------------------------------------------------------------------
142 #-------------------------------------------------------------------------
141 # API for managing transformers
143 # API for managing transformers
142 #-------------------------------------------------------------------------
144 #-------------------------------------------------------------------------
143
145
144 def init_transformers(self):
146 def init_transformers(self):
145 """Create the default transformers."""
147 """Create the default transformers."""
146 self._transformers = []
148 self._transformers = []
147 for transformer_cls in _default_transformers:
149 for transformer_cls in _default_transformers:
148 transformer_cls(
150 transformer_cls(
149 shell=self.shell, prefilter_manager=self, parent=self
151 shell=self.shell, prefilter_manager=self, parent=self
150 )
152 )
151
153
152 def sort_transformers(self):
154 def sort_transformers(self):
153 """Sort the transformers by priority.
155 """Sort the transformers by priority.
154
156
155 This must be called after the priority of a transformer is changed.
157 This must be called after the priority of a transformer is changed.
156 The :meth:`register_transformer` method calls this automatically.
158 The :meth:`register_transformer` method calls this automatically.
157 """
159 """
158 self._transformers.sort(key=lambda x: x.priority)
160 self._transformers.sort(key=lambda x: x.priority)
159
161
160 @property
162 @property
161 def transformers(self):
163 def transformers(self):
162 """Return a list of checkers, sorted by priority."""
164 """Return a list of checkers, sorted by priority."""
163 return self._transformers
165 return self._transformers
164
166
165 def register_transformer(self, transformer):
167 def register_transformer(self, transformer):
166 """Register a transformer instance."""
168 """Register a transformer instance."""
167 if transformer not in self._transformers:
169 if transformer not in self._transformers:
168 self._transformers.append(transformer)
170 self._transformers.append(transformer)
169 self.sort_transformers()
171 self.sort_transformers()
170
172
171 def unregister_transformer(self, transformer):
173 def unregister_transformer(self, transformer):
172 """Unregister a transformer instance."""
174 """Unregister a transformer instance."""
173 if transformer in self._transformers:
175 if transformer in self._transformers:
174 self._transformers.remove(transformer)
176 self._transformers.remove(transformer)
175
177
176 #-------------------------------------------------------------------------
178 #-------------------------------------------------------------------------
177 # API for managing checkers
179 # API for managing checkers
178 #-------------------------------------------------------------------------
180 #-------------------------------------------------------------------------
179
181
180 def init_checkers(self):
182 def init_checkers(self):
181 """Create the default checkers."""
183 """Create the default checkers."""
182 self._checkers = []
184 self._checkers = []
183 for checker in _default_checkers:
185 for checker in _default_checkers:
184 checker(
186 checker(
185 shell=self.shell, prefilter_manager=self, parent=self
187 shell=self.shell, prefilter_manager=self, parent=self
186 )
188 )
187
189
188 def sort_checkers(self):
190 def sort_checkers(self):
189 """Sort the checkers by priority.
191 """Sort the checkers by priority.
190
192
191 This must be called after the priority of a checker is changed.
193 This must be called after the priority of a checker is changed.
192 The :meth:`register_checker` method calls this automatically.
194 The :meth:`register_checker` method calls this automatically.
193 """
195 """
194 self._checkers.sort(key=lambda x: x.priority)
196 self._checkers.sort(key=lambda x: x.priority)
195
197
196 @property
198 @property
197 def checkers(self):
199 def checkers(self):
198 """Return a list of checkers, sorted by priority."""
200 """Return a list of checkers, sorted by priority."""
199 return self._checkers
201 return self._checkers
200
202
201 def register_checker(self, checker):
203 def register_checker(self, checker):
202 """Register a checker instance."""
204 """Register a checker instance."""
203 if checker not in self._checkers:
205 if checker not in self._checkers:
204 self._checkers.append(checker)
206 self._checkers.append(checker)
205 self.sort_checkers()
207 self.sort_checkers()
206
208
207 def unregister_checker(self, checker):
209 def unregister_checker(self, checker):
208 """Unregister a checker instance."""
210 """Unregister a checker instance."""
209 if checker in self._checkers:
211 if checker in self._checkers:
210 self._checkers.remove(checker)
212 self._checkers.remove(checker)
211
213
212 #-------------------------------------------------------------------------
214 #-------------------------------------------------------------------------
213 # API for managing checkers
215 # API for managing checkers
214 #-------------------------------------------------------------------------
216 #-------------------------------------------------------------------------
215
217
216 def init_handlers(self):
218 def init_handlers(self):
217 """Create the default handlers."""
219 """Create the default handlers."""
218 self._handlers = {}
220 self._handlers = {}
219 self._esc_handlers = {}
221 self._esc_handlers = {}
220 for handler in _default_handlers:
222 for handler in _default_handlers:
221 handler(
223 handler(
222 shell=self.shell, prefilter_manager=self, parent=self
224 shell=self.shell, prefilter_manager=self, parent=self
223 )
225 )
224
226
225 @property
227 @property
226 def handlers(self):
228 def handlers(self):
227 """Return a dict of all the handlers."""
229 """Return a dict of all the handlers."""
228 return self._handlers
230 return self._handlers
229
231
230 def register_handler(self, name, handler, esc_strings):
232 def register_handler(self, name, handler, esc_strings):
231 """Register a handler instance by name with esc_strings."""
233 """Register a handler instance by name with esc_strings."""
232 self._handlers[name] = handler
234 self._handlers[name] = handler
233 for esc_str in esc_strings:
235 for esc_str in esc_strings:
234 self._esc_handlers[esc_str] = handler
236 self._esc_handlers[esc_str] = handler
235
237
236 def unregister_handler(self, name, handler, esc_strings):
238 def unregister_handler(self, name, handler, esc_strings):
237 """Unregister a handler instance by name with esc_strings."""
239 """Unregister a handler instance by name with esc_strings."""
238 try:
240 try:
239 del self._handlers[name]
241 del self._handlers[name]
240 except KeyError:
242 except KeyError:
241 pass
243 pass
242 for esc_str in esc_strings:
244 for esc_str in esc_strings:
243 h = self._esc_handlers.get(esc_str)
245 h = self._esc_handlers.get(esc_str)
244 if h is handler:
246 if h is handler:
245 del self._esc_handlers[esc_str]
247 del self._esc_handlers[esc_str]
246
248
247 def get_handler_by_name(self, name):
249 def get_handler_by_name(self, name):
248 """Get a handler by its name."""
250 """Get a handler by its name."""
249 return self._handlers.get(name)
251 return self._handlers.get(name)
250
252
251 def get_handler_by_esc(self, esc_str):
253 def get_handler_by_esc(self, esc_str):
252 """Get a handler by its escape string."""
254 """Get a handler by its escape string."""
253 return self._esc_handlers.get(esc_str)
255 return self._esc_handlers.get(esc_str)
254
256
255 #-------------------------------------------------------------------------
257 #-------------------------------------------------------------------------
256 # Main prefiltering API
258 # Main prefiltering API
257 #-------------------------------------------------------------------------
259 #-------------------------------------------------------------------------
258
260
259 def prefilter_line_info(self, line_info):
261 def prefilter_line_info(self, line_info):
260 """Prefilter a line that has been converted to a LineInfo object.
262 """Prefilter a line that has been converted to a LineInfo object.
261
263
262 This implements the checker/handler part of the prefilter pipe.
264 This implements the checker/handler part of the prefilter pipe.
263 """
265 """
264 # print "prefilter_line_info: ", line_info
266 # print "prefilter_line_info: ", line_info
265 handler = self.find_handler(line_info)
267 handler = self.find_handler(line_info)
266 return handler.handle(line_info)
268 return handler.handle(line_info)
267
269
268 def find_handler(self, line_info):
270 def find_handler(self, line_info):
269 """Find a handler for the line_info by trying checkers."""
271 """Find a handler for the line_info by trying checkers."""
270 for checker in self.checkers:
272 for checker in self.checkers:
271 if checker.enabled:
273 if checker.enabled:
272 handler = checker.check(line_info)
274 handler = checker.check(line_info)
273 if handler:
275 if handler:
274 return handler
276 return handler
275 return self.get_handler_by_name('normal')
277 return self.get_handler_by_name('normal')
276
278
277 def transform_line(self, line, continue_prompt):
279 def transform_line(self, line, continue_prompt):
278 """Calls the enabled transformers in order of increasing priority."""
280 """Calls the enabled transformers in order of increasing priority."""
279 for transformer in self.transformers:
281 for transformer in self.transformers:
280 if transformer.enabled:
282 if transformer.enabled:
281 line = transformer.transform(line, continue_prompt)
283 line = transformer.transform(line, continue_prompt)
282 return line
284 return line
283
285
284 def prefilter_line(self, line, continue_prompt=False):
286 def prefilter_line(self, line, continue_prompt=False):
285 """Prefilter a single input line as text.
287 """Prefilter a single input line as text.
286
288
287 This method prefilters a single line of text by calling the
289 This method prefilters a single line of text by calling the
288 transformers and then the checkers/handlers.
290 transformers and then the checkers/handlers.
289 """
291 """
290
292
291 # print "prefilter_line: ", line, continue_prompt
293 # print "prefilter_line: ", line, continue_prompt
292 # All handlers *must* return a value, even if it's blank ('').
294 # All handlers *must* return a value, even if it's blank ('').
293
295
294 # save the line away in case we crash, so the post-mortem handler can
296 # save the line away in case we crash, so the post-mortem handler can
295 # record it
297 # record it
296 self.shell._last_input_line = line
298 self.shell._last_input_line = line
297
299
298 if not line:
300 if not line:
299 # Return immediately on purely empty lines, so that if the user
301 # Return immediately on purely empty lines, so that if the user
300 # previously typed some whitespace that started a continuation
302 # previously typed some whitespace that started a continuation
301 # prompt, he can break out of that loop with just an empty line.
303 # prompt, he can break out of that loop with just an empty line.
302 # This is how the default python prompt works.
304 # This is how the default python prompt works.
303 return ''
305 return ''
304
306
305 # At this point, we invoke our transformers.
307 # At this point, we invoke our transformers.
306 if not continue_prompt or (continue_prompt and self.multi_line_specials):
308 if not continue_prompt or (continue_prompt and self.multi_line_specials):
307 line = self.transform_line(line, continue_prompt)
309 line = self.transform_line(line, continue_prompt)
308
310
309 # Now we compute line_info for the checkers and handlers
311 # Now we compute line_info for the checkers and handlers
310 line_info = LineInfo(line, continue_prompt)
312 line_info = LineInfo(line, continue_prompt)
311
313
312 # the input history needs to track even empty lines
314 # the input history needs to track even empty lines
313 stripped = line.strip()
315 stripped = line.strip()
314
316
315 normal_handler = self.get_handler_by_name('normal')
317 normal_handler = self.get_handler_by_name('normal')
316 if not stripped:
318 if not stripped:
317 return normal_handler.handle(line_info)
319 return normal_handler.handle(line_info)
318
320
319 # special handlers are only allowed for single line statements
321 # special handlers are only allowed for single line statements
320 if continue_prompt and not self.multi_line_specials:
322 if continue_prompt and not self.multi_line_specials:
321 return normal_handler.handle(line_info)
323 return normal_handler.handle(line_info)
322
324
323 prefiltered = self.prefilter_line_info(line_info)
325 prefiltered = self.prefilter_line_info(line_info)
324 # print "prefiltered line: %r" % prefiltered
326 # print "prefiltered line: %r" % prefiltered
325 return prefiltered
327 return prefiltered
326
328
327 def prefilter_lines(self, lines, continue_prompt=False):
329 def prefilter_lines(self, lines, continue_prompt=False):
328 """Prefilter multiple input lines of text.
330 """Prefilter multiple input lines of text.
329
331
330 This is the main entry point for prefiltering multiple lines of
332 This is the main entry point for prefiltering multiple lines of
331 input. This simply calls :meth:`prefilter_line` for each line of
333 input. This simply calls :meth:`prefilter_line` for each line of
332 input.
334 input.
333
335
334 This covers cases where there are multiple lines in the user entry,
336 This covers cases where there are multiple lines in the user entry,
335 which is the case when the user goes back to a multiline history
337 which is the case when the user goes back to a multiline history
336 entry and presses enter.
338 entry and presses enter.
337 """
339 """
338 llines = lines.rstrip('\n').split('\n')
340 llines = lines.rstrip('\n').split('\n')
339 # We can get multiple lines in one shot, where multiline input 'blends'
341 # We can get multiple lines in one shot, where multiline input 'blends'
340 # into one line, in cases like recalling from the readline history
342 # into one line, in cases like recalling from the readline history
341 # buffer. We need to make sure that in such cases, we correctly
343 # buffer. We need to make sure that in such cases, we correctly
342 # communicate downstream which line is first and which are continuation
344 # communicate downstream which line is first and which are continuation
343 # ones.
345 # ones.
344 if len(llines) > 1:
346 if len(llines) > 1:
345 out = '\n'.join([self.prefilter_line(line, lnum>0)
347 out = '\n'.join([self.prefilter_line(line, lnum>0)
346 for lnum, line in enumerate(llines) ])
348 for lnum, line in enumerate(llines) ])
347 else:
349 else:
348 out = self.prefilter_line(llines[0], continue_prompt)
350 out = self.prefilter_line(llines[0], continue_prompt)
349
351
350 return out
352 return out
351
353
352 #-----------------------------------------------------------------------------
354 #-----------------------------------------------------------------------------
353 # Prefilter transformers
355 # Prefilter transformers
354 #-----------------------------------------------------------------------------
356 #-----------------------------------------------------------------------------
355
357
356
358
357 class PrefilterTransformer(Configurable):
359 class PrefilterTransformer(Configurable):
358 """Transform a line of user input."""
360 """Transform a line of user input."""
359
361
360 priority = Integer(100, config=True)
362 priority = Integer(100, config=True)
361 # Transformers don't currently use shell or prefilter_manager, but as we
363 # Transformers don't currently use shell or prefilter_manager, but as we
362 # move away from checkers and handlers, they will need them.
364 # move away from checkers and handlers, they will need them.
363 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
365 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
364 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
366 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
365 enabled = Bool(True, config=True)
367 enabled = Bool(True, config=True)
366
368
367 def __init__(self, shell=None, prefilter_manager=None, **kwargs):
369 def __init__(self, shell=None, prefilter_manager=None, **kwargs):
368 super(PrefilterTransformer, self).__init__(
370 super(PrefilterTransformer, self).__init__(
369 shell=shell, prefilter_manager=prefilter_manager, **kwargs
371 shell=shell, prefilter_manager=prefilter_manager, **kwargs
370 )
372 )
371 self.prefilter_manager.register_transformer(self)
373 self.prefilter_manager.register_transformer(self)
372
374
373 def transform(self, line, continue_prompt):
375 def transform(self, line, continue_prompt):
374 """Transform a line, returning the new one."""
376 """Transform a line, returning the new one."""
375 return None
377 return None
376
378
377 def __repr__(self):
379 def __repr__(self):
378 return "<%s(priority=%r, enabled=%r)>" % (
380 return "<%s(priority=%r, enabled=%r)>" % (
379 self.__class__.__name__, self.priority, self.enabled)
381 self.__class__.__name__, self.priority, self.enabled)
380
382
381
383
382 #-----------------------------------------------------------------------------
384 #-----------------------------------------------------------------------------
383 # Prefilter checkers
385 # Prefilter checkers
384 #-----------------------------------------------------------------------------
386 #-----------------------------------------------------------------------------
385
387
386
388
387 class PrefilterChecker(Configurable):
389 class PrefilterChecker(Configurable):
388 """Inspect an input line and return a handler for that line."""
390 """Inspect an input line and return a handler for that line."""
389
391
390 priority = Integer(100, config=True)
392 priority = Integer(100, config=True)
391 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
393 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
392 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
394 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
393 enabled = Bool(True, config=True)
395 enabled = Bool(True, config=True)
394
396
395 def __init__(self, shell=None, prefilter_manager=None, **kwargs):
397 def __init__(self, shell=None, prefilter_manager=None, **kwargs):
396 super(PrefilterChecker, self).__init__(
398 super(PrefilterChecker, self).__init__(
397 shell=shell, prefilter_manager=prefilter_manager, **kwargs
399 shell=shell, prefilter_manager=prefilter_manager, **kwargs
398 )
400 )
399 self.prefilter_manager.register_checker(self)
401 self.prefilter_manager.register_checker(self)
400
402
401 def check(self, line_info):
403 def check(self, line_info):
402 """Inspect line_info and return a handler instance or None."""
404 """Inspect line_info and return a handler instance or None."""
403 return None
405 return None
404
406
405 def __repr__(self):
407 def __repr__(self):
406 return "<%s(priority=%r, enabled=%r)>" % (
408 return "<%s(priority=%r, enabled=%r)>" % (
407 self.__class__.__name__, self.priority, self.enabled)
409 self.__class__.__name__, self.priority, self.enabled)
408
410
409
411
410 class EmacsChecker(PrefilterChecker):
412 class EmacsChecker(PrefilterChecker):
411
413
412 priority = Integer(100, config=True)
414 priority = Integer(100, config=True)
413 enabled = Bool(False, config=True)
415 enabled = Bool(False, config=True)
414
416
415 def check(self, line_info):
417 def check(self, line_info):
416 "Emacs ipython-mode tags certain input lines."
418 "Emacs ipython-mode tags certain input lines."
417 if line_info.line.endswith('# PYTHON-MODE'):
419 if line_info.line.endswith('# PYTHON-MODE'):
418 return self.prefilter_manager.get_handler_by_name('emacs')
420 return self.prefilter_manager.get_handler_by_name('emacs')
419 else:
421 else:
420 return None
422 return None
421
423
422
424
423 class MacroChecker(PrefilterChecker):
425 class MacroChecker(PrefilterChecker):
424
426
425 priority = Integer(250, config=True)
427 priority = Integer(250, config=True)
426
428
427 def check(self, line_info):
429 def check(self, line_info):
428 obj = self.shell.user_ns.get(line_info.ifun)
430 obj = self.shell.user_ns.get(line_info.ifun)
429 if isinstance(obj, Macro):
431 if isinstance(obj, Macro):
430 return self.prefilter_manager.get_handler_by_name('macro')
432 return self.prefilter_manager.get_handler_by_name('macro')
431 else:
433 else:
432 return None
434 return None
433
435
434
436
435 class IPyAutocallChecker(PrefilterChecker):
437 class IPyAutocallChecker(PrefilterChecker):
436
438
437 priority = Integer(300, config=True)
439 priority = Integer(300, config=True)
438
440
439 def check(self, line_info):
441 def check(self, line_info):
440 "Instances of IPyAutocall in user_ns get autocalled immediately"
442 "Instances of IPyAutocall in user_ns get autocalled immediately"
441 obj = self.shell.user_ns.get(line_info.ifun, None)
443 obj = self.shell.user_ns.get(line_info.ifun, None)
442 if isinstance(obj, IPyAutocall):
444 if isinstance(obj, IPyAutocall):
443 obj.set_ip(self.shell)
445 obj.set_ip(self.shell)
444 return self.prefilter_manager.get_handler_by_name('auto')
446 return self.prefilter_manager.get_handler_by_name('auto')
445 else:
447 else:
446 return None
448 return None
447
449
448
450
449 class AssignmentChecker(PrefilterChecker):
451 class AssignmentChecker(PrefilterChecker):
450
452
451 priority = Integer(600, config=True)
453 priority = Integer(600, config=True)
452
454
453 def check(self, line_info):
455 def check(self, line_info):
454 """Check to see if user is assigning to a var for the first time, in
456 """Check to see if user is assigning to a var for the first time, in
455 which case we want to avoid any sort of automagic / autocall games.
457 which case we want to avoid any sort of automagic / autocall games.
456
458
457 This allows users to assign to either alias or magic names true python
459 This allows users to assign to either alias or magic names true python
458 variables (the magic/alias systems always take second seat to true
460 variables (the magic/alias systems always take second seat to true
459 python code). E.g. ls='hi', or ls,that=1,2"""
461 python code). E.g. ls='hi', or ls,that=1,2"""
460 if line_info.the_rest:
462 if line_info.the_rest:
461 if line_info.the_rest[0] in '=,':
463 if line_info.the_rest[0] in '=,':
462 return self.prefilter_manager.get_handler_by_name('normal')
464 return self.prefilter_manager.get_handler_by_name('normal')
463 else:
465 else:
464 return None
466 return None
465
467
466
468
467 class AutoMagicChecker(PrefilterChecker):
469 class AutoMagicChecker(PrefilterChecker):
468
470
469 priority = Integer(700, config=True)
471 priority = Integer(700, config=True)
470
472
471 def check(self, line_info):
473 def check(self, line_info):
472 """If the ifun is magic, and automagic is on, run it. Note: normal,
474 """If the ifun is magic, and automagic is on, run it. Note: normal,
473 non-auto magic would already have been triggered via '%' in
475 non-auto magic would already have been triggered via '%' in
474 check_esc_chars. This just checks for automagic. Also, before
476 check_esc_chars. This just checks for automagic. Also, before
475 triggering the magic handler, make sure that there is nothing in the
477 triggering the magic handler, make sure that there is nothing in the
476 user namespace which could shadow it."""
478 user namespace which could shadow it."""
477 if not self.shell.automagic or not self.shell.find_magic(line_info.ifun):
479 if not self.shell.automagic or not self.shell.find_magic(line_info.ifun):
478 return None
480 return None
479
481
480 # We have a likely magic method. Make sure we should actually call it.
482 # We have a likely magic method. Make sure we should actually call it.
481 if line_info.continue_prompt and not self.prefilter_manager.multi_line_specials:
483 if line_info.continue_prompt and not self.prefilter_manager.multi_line_specials:
482 return None
484 return None
483
485
484 head = line_info.ifun.split('.',1)[0]
486 head = line_info.ifun.split('.',1)[0]
485 if is_shadowed(head, self.shell):
487 if is_shadowed(head, self.shell):
486 return None
488 return None
487
489
488 return self.prefilter_manager.get_handler_by_name('magic')
490 return self.prefilter_manager.get_handler_by_name('magic')
489
491
490
492
491 class AliasChecker(PrefilterChecker):
493 class AliasChecker(PrefilterChecker):
492
494
493 priority = Integer(800, config=True)
495 priority = Integer(800, config=True)
494
496
495 def check(self, line_info):
497 def check(self, line_info):
496 "Check if the initital identifier on the line is an alias."
498 "Check if the initital identifier on the line is an alias."
497 # Note: aliases can not contain '.'
499 # Note: aliases can not contain '.'
498 head = line_info.ifun.split('.',1)[0]
500 head = line_info.ifun.split('.',1)[0]
499 if line_info.ifun not in self.shell.alias_manager \
501 if line_info.ifun not in self.shell.alias_manager \
500 or head not in self.shell.alias_manager \
502 or head not in self.shell.alias_manager \
501 or is_shadowed(head, self.shell):
503 or is_shadowed(head, self.shell):
502 return None
504 return None
503
505
504 return self.prefilter_manager.get_handler_by_name('alias')
506 return self.prefilter_manager.get_handler_by_name('alias')
505
507
506
508
507 class PythonOpsChecker(PrefilterChecker):
509 class PythonOpsChecker(PrefilterChecker):
508
510
509 priority = Integer(900, config=True)
511 priority = Integer(900, config=True)
510
512
511 def check(self, line_info):
513 def check(self, line_info):
512 """If the 'rest' of the line begins with a function call or pretty much
514 """If the 'rest' of the line begins with a function call or pretty much
513 any python operator, we should simply execute the line (regardless of
515 any python operator, we should simply execute the line (regardless of
514 whether or not there's a possible autocall expansion). This avoids
516 whether or not there's a possible autocall expansion). This avoids
515 spurious (and very confusing) geattr() accesses."""
517 spurious (and very confusing) geattr() accesses."""
516 if line_info.the_rest and line_info.the_rest[0] in '!=()<>,+*/%^&|':
518 if line_info.the_rest and line_info.the_rest[0] in '!=()<>,+*/%^&|':
517 return self.prefilter_manager.get_handler_by_name('normal')
519 return self.prefilter_manager.get_handler_by_name('normal')
518 else:
520 else:
519 return None
521 return None
520
522
521
523
522 class AutocallChecker(PrefilterChecker):
524 class AutocallChecker(PrefilterChecker):
523
525
524 priority = Integer(1000, config=True)
526 priority = Integer(1000, config=True)
525
527
526 function_name_regexp = CRegExp(re_fun_name, config=True,
528 function_name_regexp = CRegExp(re_fun_name, config=True,
527 help="RegExp to identify potential function names.")
529 help="RegExp to identify potential function names.")
528 exclude_regexp = CRegExp(re_exclude_auto, config=True,
530 exclude_regexp = CRegExp(re_exclude_auto, config=True,
529 help="RegExp to exclude strings with this start from autocalling.")
531 help="RegExp to exclude strings with this start from autocalling.")
530
532
531 def check(self, line_info):
533 def check(self, line_info):
532 "Check if the initial word/function is callable and autocall is on."
534 "Check if the initial word/function is callable and autocall is on."
533 if not self.shell.autocall:
535 if not self.shell.autocall:
534 return None
536 return None
535
537
536 oinfo = line_info.ofind(self.shell) # This can mutate state via getattr
538 oinfo = line_info.ofind(self.shell) # This can mutate state via getattr
537 if not oinfo['found']:
539 if not oinfo['found']:
538 return None
540 return None
539
541
540 if callable(oinfo['obj']) \
542 if callable(oinfo['obj']) \
541 and (not self.exclude_regexp.match(line_info.the_rest)) \
543 and (not self.exclude_regexp.match(line_info.the_rest)) \
542 and self.function_name_regexp.match(line_info.ifun):
544 and self.function_name_regexp.match(line_info.ifun):
543 return self.prefilter_manager.get_handler_by_name('auto')
545 return self.prefilter_manager.get_handler_by_name('auto')
544 else:
546 else:
545 return None
547 return None
546
548
547
549
548 #-----------------------------------------------------------------------------
550 #-----------------------------------------------------------------------------
549 # Prefilter handlers
551 # Prefilter handlers
550 #-----------------------------------------------------------------------------
552 #-----------------------------------------------------------------------------
551
553
552
554
553 class PrefilterHandler(Configurable):
555 class PrefilterHandler(Configurable):
554
556
555 handler_name = Unicode('normal')
557 handler_name = Unicode('normal')
556 esc_strings = List([])
558 esc_strings = List([])
557 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
559 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
558 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
560 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
559
561
560 def __init__(self, shell=None, prefilter_manager=None, **kwargs):
562 def __init__(self, shell=None, prefilter_manager=None, **kwargs):
561 super(PrefilterHandler, self).__init__(
563 super(PrefilterHandler, self).__init__(
562 shell=shell, prefilter_manager=prefilter_manager, **kwargs
564 shell=shell, prefilter_manager=prefilter_manager, **kwargs
563 )
565 )
564 self.prefilter_manager.register_handler(
566 self.prefilter_manager.register_handler(
565 self.handler_name,
567 self.handler_name,
566 self,
568 self,
567 self.esc_strings
569 self.esc_strings
568 )
570 )
569
571
570 def handle(self, line_info):
572 def handle(self, line_info):
571 # print "normal: ", line_info
573 # print "normal: ", line_info
572 """Handle normal input lines. Use as a template for handlers."""
574 """Handle normal input lines. Use as a template for handlers."""
573
575
574 # With autoindent on, we need some way to exit the input loop, and I
576 # With autoindent on, we need some way to exit the input loop, and I
575 # don't want to force the user to have to backspace all the way to
577 # don't want to force the user to have to backspace all the way to
576 # clear the line. The rule will be in this case, that either two
578 # clear the line. The rule will be in this case, that either two
577 # lines of pure whitespace in a row, or a line of pure whitespace but
579 # lines of pure whitespace in a row, or a line of pure whitespace but
578 # of a size different to the indent level, will exit the input loop.
580 # of a size different to the indent level, will exit the input loop.
579 line = line_info.line
581 line = line_info.line
580 continue_prompt = line_info.continue_prompt
582 continue_prompt = line_info.continue_prompt
581
583
582 if (continue_prompt and
584 if (continue_prompt and
583 self.shell.autoindent and
585 self.shell.autoindent and
584 line.isspace() and
586 line.isspace() and
585 0 < abs(len(line) - self.shell.indent_current_nsp) <= 2):
587 0 < abs(len(line) - self.shell.indent_current_nsp) <= 2):
586 line = ''
588 line = ''
587
589
588 return line
590 return line
589
591
590 def __str__(self):
592 def __str__(self):
591 return "<%s(name=%s)>" % (self.__class__.__name__, self.handler_name)
593 return "<%s(name=%s)>" % (self.__class__.__name__, self.handler_name)
592
594
593
595
594 class AliasHandler(PrefilterHandler):
596 class AliasHandler(PrefilterHandler):
595
597
596 handler_name = Unicode('alias')
598 handler_name = Unicode('alias')
597
599
598 def handle(self, line_info):
600 def handle(self, line_info):
599 """Handle alias input lines. """
601 """Handle alias input lines. """
600 transformed = self.shell.alias_manager.expand_aliases(line_info.ifun,line_info.the_rest)
602 transformed = self.shell.alias_manager.expand_aliases(line_info.ifun,line_info.the_rest)
601 # pre is needed, because it carries the leading whitespace. Otherwise
603 # pre is needed, because it carries the leading whitespace. Otherwise
602 # aliases won't work in indented sections.
604 # aliases won't work in indented sections.
603 line_out = '%sget_ipython().system(%r)' % (line_info.pre_whitespace, transformed)
605 line_out = '%sget_ipython().system(%r)' % (line_info.pre_whitespace, transformed)
604
606
605 return line_out
607 return line_out
606
608
607
609
608 class MacroHandler(PrefilterHandler):
610 class MacroHandler(PrefilterHandler):
609 handler_name = Unicode("macro")
611 handler_name = Unicode("macro")
610
612
611 def handle(self, line_info):
613 def handle(self, line_info):
612 obj = self.shell.user_ns.get(line_info.ifun)
614 obj = self.shell.user_ns.get(line_info.ifun)
613 pre_space = line_info.pre_whitespace
615 pre_space = line_info.pre_whitespace
614 line_sep = "\n" + pre_space
616 line_sep = "\n" + pre_space
615 return pre_space + line_sep.join(obj.value.splitlines())
617 return pre_space + line_sep.join(obj.value.splitlines())
616
618
617
619
618 class MagicHandler(PrefilterHandler):
620 class MagicHandler(PrefilterHandler):
619
621
620 handler_name = Unicode('magic')
622 handler_name = Unicode('magic')
621 esc_strings = List([ESC_MAGIC])
623 esc_strings = List([ESC_MAGIC])
622
624
623 def handle(self, line_info):
625 def handle(self, line_info):
624 """Execute magic functions."""
626 """Execute magic functions."""
625 ifun = line_info.ifun
627 ifun = line_info.ifun
626 the_rest = line_info.the_rest
628 the_rest = line_info.the_rest
627 cmd = '%sget_ipython().magic(%r)' % (line_info.pre_whitespace,
629 cmd = '%sget_ipython().magic(%r)' % (line_info.pre_whitespace,
628 (ifun + " " + the_rest))
630 (ifun + " " + the_rest))
629 return cmd
631 return cmd
630
632
631
633
632 class AutoHandler(PrefilterHandler):
634 class AutoHandler(PrefilterHandler):
633
635
634 handler_name = Unicode('auto')
636 handler_name = Unicode('auto')
635 esc_strings = List([ESC_PAREN, ESC_QUOTE, ESC_QUOTE2])
637 esc_strings = List([ESC_PAREN, ESC_QUOTE, ESC_QUOTE2])
636
638
637 def handle(self, line_info):
639 def handle(self, line_info):
638 """Handle lines which can be auto-executed, quoting if requested."""
640 """Handle lines which can be auto-executed, quoting if requested."""
639 line = line_info.line
641 line = line_info.line
640 ifun = line_info.ifun
642 ifun = line_info.ifun
641 the_rest = line_info.the_rest
643 the_rest = line_info.the_rest
642 pre = line_info.pre
644 pre = line_info.pre
643 esc = line_info.esc
645 esc = line_info.esc
644 continue_prompt = line_info.continue_prompt
646 continue_prompt = line_info.continue_prompt
645 obj = line_info.ofind(self.shell)['obj']
647 obj = line_info.ofind(self.shell)['obj']
646 #print 'pre <%s> ifun <%s> rest <%s>' % (pre,ifun,the_rest) # dbg
648 #print 'pre <%s> ifun <%s> rest <%s>' % (pre,ifun,the_rest) # dbg
647
649
648 # This should only be active for single-line input!
650 # This should only be active for single-line input!
649 if continue_prompt:
651 if continue_prompt:
650 return line
652 return line
651
653
652 force_auto = isinstance(obj, IPyAutocall)
654 force_auto = isinstance(obj, IPyAutocall)
653
655
654 # User objects sometimes raise exceptions on attribute access other
656 # User objects sometimes raise exceptions on attribute access other
655 # than AttributeError (we've seen it in the past), so it's safest to be
657 # than AttributeError (we've seen it in the past), so it's safest to be
656 # ultra-conservative here and catch all.
658 # ultra-conservative here and catch all.
657 try:
659 try:
658 auto_rewrite = obj.rewrite
660 auto_rewrite = obj.rewrite
659 except Exception:
661 except Exception:
660 auto_rewrite = True
662 auto_rewrite = True
661
663
662 if esc == ESC_QUOTE:
664 if esc == ESC_QUOTE:
663 # Auto-quote splitting on whitespace
665 # Auto-quote splitting on whitespace
664 newcmd = '%s("%s")' % (ifun,'", "'.join(the_rest.split()) )
666 newcmd = '%s("%s")' % (ifun,'", "'.join(the_rest.split()) )
665 elif esc == ESC_QUOTE2:
667 elif esc == ESC_QUOTE2:
666 # Auto-quote whole string
668 # Auto-quote whole string
667 newcmd = '%s("%s")' % (ifun,the_rest)
669 newcmd = '%s("%s")' % (ifun,the_rest)
668 elif esc == ESC_PAREN:
670 elif esc == ESC_PAREN:
669 newcmd = '%s(%s)' % (ifun,",".join(the_rest.split()))
671 newcmd = '%s(%s)' % (ifun,",".join(the_rest.split()))
670 else:
672 else:
671 # Auto-paren.
673 # Auto-paren.
672 if force_auto:
674 if force_auto:
673 # Don't rewrite if it is already a call.
675 # Don't rewrite if it is already a call.
674 do_rewrite = not the_rest.startswith('(')
676 do_rewrite = not the_rest.startswith('(')
675 else:
677 else:
676 if not the_rest:
678 if not the_rest:
677 # We only apply it to argument-less calls if the autocall
679 # We only apply it to argument-less calls if the autocall
678 # parameter is set to 2.
680 # parameter is set to 2.
679 do_rewrite = (self.shell.autocall >= 2)
681 do_rewrite = (self.shell.autocall >= 2)
680 elif the_rest.startswith('[') and hasattr(obj, '__getitem__'):
682 elif the_rest.startswith('[') and hasattr(obj, '__getitem__'):
681 # Don't autocall in this case: item access for an object
683 # Don't autocall in this case: item access for an object
682 # which is BOTH callable and implements __getitem__.
684 # which is BOTH callable and implements __getitem__.
683 do_rewrite = False
685 do_rewrite = False
684 else:
686 else:
685 do_rewrite = True
687 do_rewrite = True
686
688
687 # Figure out the rewritten command
689 # Figure out the rewritten command
688 if do_rewrite:
690 if do_rewrite:
689 if the_rest.endswith(';'):
691 if the_rest.endswith(';'):
690 newcmd = '%s(%s);' % (ifun.rstrip(),the_rest[:-1])
692 newcmd = '%s(%s);' % (ifun.rstrip(),the_rest[:-1])
691 else:
693 else:
692 newcmd = '%s(%s)' % (ifun.rstrip(), the_rest)
694 newcmd = '%s(%s)' % (ifun.rstrip(), the_rest)
693 else:
695 else:
694 normal_handler = self.prefilter_manager.get_handler_by_name('normal')
696 normal_handler = self.prefilter_manager.get_handler_by_name('normal')
695 return normal_handler.handle(line_info)
697 return normal_handler.handle(line_info)
696
698
697 # Display the rewritten call
699 # Display the rewritten call
698 if auto_rewrite:
700 if auto_rewrite:
699 self.shell.auto_rewrite_input(newcmd)
701 self.shell.auto_rewrite_input(newcmd)
700
702
701 return newcmd
703 return newcmd
702
704
703
705
704 class EmacsHandler(PrefilterHandler):
706 class EmacsHandler(PrefilterHandler):
705
707
706 handler_name = Unicode('emacs')
708 handler_name = Unicode('emacs')
707 esc_strings = List([])
709 esc_strings = List([])
708
710
709 def handle(self, line_info):
711 def handle(self, line_info):
710 """Handle input lines marked by python-mode."""
712 """Handle input lines marked by python-mode."""
711
713
712 # Currently, nothing is done. Later more functionality can be added
714 # Currently, nothing is done. Later more functionality can be added
713 # here if needed.
715 # here if needed.
714
716
715 # The input cache shouldn't be updated
717 # The input cache shouldn't be updated
716 return line_info.line
718 return line_info.line
717
719
718
720
719 #-----------------------------------------------------------------------------
721 #-----------------------------------------------------------------------------
720 # Defaults
722 # Defaults
721 #-----------------------------------------------------------------------------
723 #-----------------------------------------------------------------------------
722
724
723
725
724 _default_transformers = [
726 _default_transformers = [
725 ]
727 ]
726
728
727 _default_checkers = [
729 _default_checkers = [
728 EmacsChecker,
730 EmacsChecker,
729 MacroChecker,
731 MacroChecker,
730 IPyAutocallChecker,
732 IPyAutocallChecker,
731 AssignmentChecker,
733 AssignmentChecker,
732 AutoMagicChecker,
734 AutoMagicChecker,
733 AliasChecker,
735 AliasChecker,
734 PythonOpsChecker,
736 PythonOpsChecker,
735 AutocallChecker
737 AutocallChecker
736 ]
738 ]
737
739
738 _default_handlers = [
740 _default_handlers = [
739 PrefilterHandler,
741 PrefilterHandler,
740 AliasHandler,
742 AliasHandler,
741 MacroHandler,
743 MacroHandler,
742 MagicHandler,
744 MagicHandler,
743 AutoHandler,
745 AutoHandler,
744 EmacsHandler
746 EmacsHandler
745 ]
747 ]
@@ -1,95 +1,118 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.globalipapp import get_ipython
9 from IPython.testing.globalipapp import get_ipython
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Tests
12 # Tests
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 ip = get_ipython()
14 ip = get_ipython()
15
15
16 def test_prefilter():
16 def test_prefilter():
17 """Test user input conversions"""
17 """Test user input conversions"""
18
18
19 # pairs of (raw, expected correct) input
19 # pairs of (raw, expected correct) input
20 pairs = [ ('2+2','2+2'),
20 pairs = [ ('2+2','2+2'),
21 ]
21 ]
22
22
23 for raw, correct in pairs:
23 for raw, correct in pairs:
24 nt.assert_equal(ip.prefilter(raw), correct)
24 nt.assert_equal(ip.prefilter(raw), correct)
25
25
26 def test_prefilter_shadowed():
27 def dummy_magic(line): pass
28
29 prev_automagic_state = ip.automagic
30 ip.automagic = True
31
32 try:
33 # These should not be transformed - they are shadowed by other names
34 for name in ['if', 'zip', 'get_ipython']: # keyword, builtin, global
35 ip.register_magic_function(dummy_magic, magic_name=name)
36 res = ip.prefilter(name+' foo')
37 nt.assert_equal(res, name+' foo')
38 del ip.magics_manager.magics['line'][name]
39
40 # These should be transformed
41 for name in ['fi', 'piz', 'nohtypi_teg']:
42 ip.register_magic_function(dummy_magic, magic_name=name)
43 res = ip.prefilter(name+' foo')
44 nt.assert_not_equal(res, name+' foo')
45 del ip.magics_manager.magics['line'][name]
46
47 finally:
48 ip.automagic = prev_automagic_state
26
49
27 def test_autocall_binops():
50 def test_autocall_binops():
28 """See https://github.com/ipython/ipython/issues/81"""
51 """See https://github.com/ipython/ipython/issues/81"""
29 ip.magic('autocall 2')
52 ip.magic('autocall 2')
30 f = lambda x: x
53 f = lambda x: x
31 ip.user_ns['f'] = f
54 ip.user_ns['f'] = f
32 try:
55 try:
33 nt.assert_equal(ip.prefilter('f 1'),'f(1)')
56 nt.assert_equal(ip.prefilter('f 1'),'f(1)')
34 for t in ['f +1', 'f -1']:
57 for t in ['f +1', 'f -1']:
35 nt.assert_equal(ip.prefilter(t), t)
58 nt.assert_equal(ip.prefilter(t), t)
36
59
37 # Run tests again with a more permissive exclude_regexp, which will
60 # Run tests again with a more permissive exclude_regexp, which will
38 # allow transformation of binary operations ('f -1' -> 'f(-1)').
61 # allow transformation of binary operations ('f -1' -> 'f(-1)').
39 pm = ip.prefilter_manager
62 pm = ip.prefilter_manager
40 ac = AutocallChecker(shell=pm.shell, prefilter_manager=pm,
63 ac = AutocallChecker(shell=pm.shell, prefilter_manager=pm,
41 config=pm.config)
64 config=pm.config)
42 try:
65 try:
43 ac.priority = 1
66 ac.priority = 1
44 ac.exclude_regexp = r'^[,&^\|\*/]|^is |^not |^in |^and |^or '
67 ac.exclude_regexp = r'^[,&^\|\*/]|^is |^not |^in |^and |^or '
45 pm.sort_checkers()
68 pm.sort_checkers()
46
69
47 nt.assert_equal(ip.prefilter('f -1'), 'f(-1)')
70 nt.assert_equal(ip.prefilter('f -1'), 'f(-1)')
48 nt.assert_equal(ip.prefilter('f +1'), 'f(+1)')
71 nt.assert_equal(ip.prefilter('f +1'), 'f(+1)')
49 finally:
72 finally:
50 pm.unregister_checker(ac)
73 pm.unregister_checker(ac)
51 finally:
74 finally:
52 ip.magic('autocall 0')
75 ip.magic('autocall 0')
53 del ip.user_ns['f']
76 del ip.user_ns['f']
54
77
55
78
56 def test_issue_114():
79 def test_issue_114():
57 """Check that multiline string literals don't expand as magic
80 """Check that multiline string literals don't expand as magic
58 see http://github.com/ipython/ipython/issues/114"""
81 see http://github.com/ipython/ipython/issues/114"""
59
82
60 template = '"""\n%s\n"""'
83 template = '"""\n%s\n"""'
61 # Store the current value of multi_line_specials and turn it off before
84 # Store the current value of multi_line_specials and turn it off before
62 # running test, since it could be true (case in which the test doesn't make
85 # running test, since it could be true (case in which the test doesn't make
63 # sense, as multiline string literals *will* expand as magic in that case).
86 # sense, as multiline string literals *will* expand as magic in that case).
64 msp = ip.prefilter_manager.multi_line_specials
87 msp = ip.prefilter_manager.multi_line_specials
65 ip.prefilter_manager.multi_line_specials = False
88 ip.prefilter_manager.multi_line_specials = False
66 try:
89 try:
67 for mgk in ip.magics_manager.lsmagic()['line']:
90 for mgk in ip.magics_manager.lsmagic()['line']:
68 raw = template % mgk
91 raw = template % mgk
69 nt.assert_equal(ip.prefilter(raw), raw)
92 nt.assert_equal(ip.prefilter(raw), raw)
70 finally:
93 finally:
71 ip.prefilter_manager.multi_line_specials = msp
94 ip.prefilter_manager.multi_line_specials = msp
72
95
73
96
74 def test_prefilter_attribute_errors():
97 def test_prefilter_attribute_errors():
75 """Capture exceptions thrown by user objects on attribute access.
98 """Capture exceptions thrown by user objects on attribute access.
76
99
77 See http://github.com/ipython/ipython/issues/988."""
100 See http://github.com/ipython/ipython/issues/988."""
78
101
79 class X(object):
102 class X(object):
80 def __getattr__(self, k):
103 def __getattr__(self, k):
81 raise ValueError('broken object')
104 raise ValueError('broken object')
82 def __call__(self, x):
105 def __call__(self, x):
83 return x
106 return x
84
107
85 # Create a callable broken object
108 # Create a callable broken object
86 ip.user_ns['x'] = X()
109 ip.user_ns['x'] = X()
87 ip.magic('autocall 2')
110 ip.magic('autocall 2')
88 try:
111 try:
89 # Even if x throws an attribute error when looking at its rewrite
112 # Even if x throws an attribute error when looking at its rewrite
90 # attribute, we should not crash. So the test here is simply making
113 # attribute, we should not crash. So the test here is simply making
91 # the prefilter call and not having an exception.
114 # the prefilter call and not having an exception.
92 ip.prefilter('x 1')
115 ip.prefilter('x 1')
93 finally:
116 finally:
94 del ip.user_ns['x']
117 del ip.user_ns['x']
95 ip.magic('autocall 0')
118 ip.magic('autocall 0')
General Comments 0
You need to be logged in to leave comments. Login now