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