##// END OF EJS Templates
fix for #10327 : get_ipython.magic() replaced with get_ipython.run_line_magic()
adityausathe -
Show More
@@ -1,525 +1,531 b''
1 1 """Input transformer classes to support IPython special syntax.
2 2
3 3 This includes the machinery to recognise and transform ``%magic`` commands,
4 4 ``!system`` commands, ``help?`` querying, prompt stripping, and so forth.
5 5 """
6 6 import abc
7 7 import functools
8 8 import re
9 9 from io import StringIO
10 10
11 11 from IPython.core.splitinput import LineInfo
12 12 from IPython.utils import tokenize2
13 13 from IPython.utils.tokenize2 import generate_tokens, untokenize, TokenError
14 14
15 15 #-----------------------------------------------------------------------------
16 16 # Globals
17 17 #-----------------------------------------------------------------------------
18 18
19 19 # The escape sequences that define the syntax transformations IPython will
20 20 # apply to user input. These can NOT be just changed here: many regular
21 21 # expressions and other parts of the code may use their hardcoded values, and
22 22 # for all intents and purposes they constitute the 'IPython syntax', so they
23 23 # should be considered fixed.
24 24
25 25 ESC_SHELL = '!' # Send line to underlying system shell
26 26 ESC_SH_CAP = '!!' # Send line to system shell and capture output
27 27 ESC_HELP = '?' # Find information about object
28 28 ESC_HELP2 = '??' # Find extra-detailed information about object
29 29 ESC_MAGIC = '%' # Call magic function
30 30 ESC_MAGIC2 = '%%' # Call cell-magic function
31 31 ESC_QUOTE = ',' # Split args on whitespace, quote each as string and call
32 32 ESC_QUOTE2 = ';' # Quote all args as a single string, call
33 33 ESC_PAREN = '/' # Call first argument with rest of line as arguments
34 34
35 35 ESC_SEQUENCES = [ESC_SHELL, ESC_SH_CAP, ESC_HELP ,\
36 36 ESC_HELP2, ESC_MAGIC, ESC_MAGIC2,\
37 37 ESC_QUOTE, ESC_QUOTE2, ESC_PAREN ]
38 38
39 39
40 40 class InputTransformer(metaclass=abc.ABCMeta):
41 41 """Abstract base class for line-based input transformers."""
42 42
43 43 @abc.abstractmethod
44 44 def push(self, line):
45 45 """Send a line of input to the transformer, returning the transformed
46 46 input or None if the transformer is waiting for more input.
47 47
48 48 Must be overridden by subclasses.
49 49
50 50 Implementations may raise ``SyntaxError`` if the input is invalid. No
51 51 other exceptions may be raised.
52 52 """
53 53 pass
54 54
55 55 @abc.abstractmethod
56 56 def reset(self):
57 57 """Return, transformed any lines that the transformer has accumulated,
58 58 and reset its internal state.
59 59
60 60 Must be overridden by subclasses.
61 61 """
62 62 pass
63 63
64 64 @classmethod
65 65 def wrap(cls, func):
66 66 """Can be used by subclasses as a decorator, to return a factory that
67 67 will allow instantiation with the decorated object.
68 68 """
69 69 @functools.wraps(func)
70 70 def transformer_factory(**kwargs):
71 71 return cls(func, **kwargs)
72 72
73 73 return transformer_factory
74 74
75 75 class StatelessInputTransformer(InputTransformer):
76 76 """Wrapper for a stateless input transformer implemented as a function."""
77 77 def __init__(self, func):
78 78 self.func = func
79 79
80 80 def __repr__(self):
81 81 return "StatelessInputTransformer(func={0!r})".format(self.func)
82 82
83 83 def push(self, line):
84 84 """Send a line of input to the transformer, returning the
85 85 transformed input."""
86 86 return self.func(line)
87 87
88 88 def reset(self):
89 89 """No-op - exists for compatibility."""
90 90 pass
91 91
92 92 class CoroutineInputTransformer(InputTransformer):
93 93 """Wrapper for an input transformer implemented as a coroutine."""
94 94 def __init__(self, coro, **kwargs):
95 95 # Prime it
96 96 self.coro = coro(**kwargs)
97 97 next(self.coro)
98 98
99 99 def __repr__(self):
100 100 return "CoroutineInputTransformer(coro={0!r})".format(self.coro)
101 101
102 102 def push(self, line):
103 103 """Send a line of input to the transformer, returning the
104 104 transformed input or None if the transformer is waiting for more
105 105 input.
106 106 """
107 107 return self.coro.send(line)
108 108
109 109 def reset(self):
110 110 """Return, transformed any lines that the transformer has
111 111 accumulated, and reset its internal state.
112 112 """
113 113 return self.coro.send(None)
114 114
115 115 class TokenInputTransformer(InputTransformer):
116 116 """Wrapper for a token-based input transformer.
117 117
118 118 func should accept a list of tokens (5-tuples, see tokenize docs), and
119 119 return an iterable which can be passed to tokenize.untokenize().
120 120 """
121 121 def __init__(self, func):
122 122 self.func = func
123 123 self.buf = []
124 124 self.reset_tokenizer()
125 125
126 126 def reset_tokenizer(self):
127 127 it = iter(self.buf)
128 128 self.tokenizer = generate_tokens(it.__next__)
129 129
130 130 def push(self, line):
131 131 self.buf.append(line + '\n')
132 132 if all(l.isspace() for l in self.buf):
133 133 return self.reset()
134 134
135 135 tokens = []
136 136 stop_at_NL = False
137 137 try:
138 138 for intok in self.tokenizer:
139 139 tokens.append(intok)
140 140 t = intok[0]
141 141 if t == tokenize2.NEWLINE or (stop_at_NL and t == tokenize2.NL):
142 142 # Stop before we try to pull a line we don't have yet
143 143 break
144 144 elif t == tokenize2.ERRORTOKEN:
145 145 stop_at_NL = True
146 146 except TokenError:
147 147 # Multi-line statement - stop and try again with the next line
148 148 self.reset_tokenizer()
149 149 return None
150 150
151 151 return self.output(tokens)
152 152
153 153 def output(self, tokens):
154 154 self.buf.clear()
155 155 self.reset_tokenizer()
156 156 return untokenize(self.func(tokens)).rstrip('\n')
157 157
158 158 def reset(self):
159 159 l = ''.join(self.buf)
160 160 self.buf.clear()
161 161 self.reset_tokenizer()
162 162 if l:
163 163 return l.rstrip('\n')
164 164
165 165 class assemble_python_lines(TokenInputTransformer):
166 166 def __init__(self):
167 167 super(assemble_python_lines, self).__init__(None)
168 168
169 169 def output(self, tokens):
170 170 return self.reset()
171 171
172 172 @CoroutineInputTransformer.wrap
173 173 def assemble_logical_lines():
174 174 """Join lines following explicit line continuations (\)"""
175 175 line = ''
176 176 while True:
177 177 line = (yield line)
178 178 if not line or line.isspace():
179 179 continue
180 180
181 181 parts = []
182 182 while line is not None:
183 183 if line.endswith('\\') and (not has_comment(line)):
184 184 parts.append(line[:-1])
185 185 line = (yield None) # Get another line
186 186 else:
187 187 parts.append(line)
188 188 break
189 189
190 190 # Output
191 191 line = ''.join(parts)
192 192
193 193 # Utilities
194 194 def _make_help_call(target, esc, lspace, next_input=None):
195 195 """Prepares a pinfo(2)/psearch call from a target name and the escape
196 196 (i.e. ? or ??)"""
197 197 method = 'pinfo2' if esc == '??' \
198 198 else 'psearch' if '*' in target \
199 199 else 'pinfo'
200 200 arg = " ".join([method, target])
201 201 if next_input is None:
202 202 return '%sget_ipython().magic(%r)' % (lspace, arg)
203 203 else:
204 204 return '%sget_ipython().set_next_input(%r);get_ipython().magic(%r)' % \
205 205 (lspace, next_input, arg)
206 206
207 207 # These define the transformations for the different escape characters.
208 208 def _tr_system(line_info):
209 209 "Translate lines escaped with: !"
210 210 cmd = line_info.line.lstrip().lstrip(ESC_SHELL)
211 211 return '%sget_ipython().system(%r)' % (line_info.pre, cmd)
212 212
213 213 def _tr_system2(line_info):
214 214 "Translate lines escaped with: !!"
215 215 cmd = line_info.line.lstrip()[2:]
216 216 return '%sget_ipython().getoutput(%r)' % (line_info.pre, cmd)
217 217
218 218 def _tr_help(line_info):
219 219 "Translate lines escaped with: ?/??"
220 220 # A naked help line should just fire the intro help screen
221 221 if not line_info.line[1:]:
222 222 return 'get_ipython().show_usage()'
223 223
224 224 return _make_help_call(line_info.ifun, line_info.esc, line_info.pre)
225 225
226 226 def _tr_magic(line_info):
227 227 "Translate lines escaped with: %"
228 tpl = '%sget_ipython().magic(%r)'
228 tpl = '%sget_ipython().run_line_magic(%r, %r)'
229 229 if line_info.line.startswith(ESC_MAGIC2):
230 230 return line_info.line
231 231 cmd = ' '.join([line_info.ifun, line_info.the_rest]).strip()
232 return tpl % (line_info.pre, cmd)
232 #Prepare arguments for get_ipython().run_line_magic(magic_name, magic_args)
233 t_magic_name, _, t_magic_arg_s = cmd.partition(' ')
234 t_magic_name = t_magic_name.lstrip(ESC_MAGIC)
235 return tpl % (line_info.pre, t_magic_name, t_magic_arg_s)
233 236
234 237 def _tr_quote(line_info):
235 238 "Translate lines escaped with: ,"
236 239 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
237 240 '", "'.join(line_info.the_rest.split()) )
238 241
239 242 def _tr_quote2(line_info):
240 243 "Translate lines escaped with: ;"
241 244 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
242 245 line_info.the_rest)
243 246
244 247 def _tr_paren(line_info):
245 248 "Translate lines escaped with: /"
246 249 return '%s%s(%s)' % (line_info.pre, line_info.ifun,
247 250 ", ".join(line_info.the_rest.split()))
248 251
249 252 tr = { ESC_SHELL : _tr_system,
250 253 ESC_SH_CAP : _tr_system2,
251 254 ESC_HELP : _tr_help,
252 255 ESC_HELP2 : _tr_help,
253 256 ESC_MAGIC : _tr_magic,
254 257 ESC_QUOTE : _tr_quote,
255 258 ESC_QUOTE2 : _tr_quote2,
256 259 ESC_PAREN : _tr_paren }
257 260
258 261 @StatelessInputTransformer.wrap
259 262 def escaped_commands(line):
260 263 """Transform escaped commands - %magic, !system, ?help + various autocalls.
261 264 """
262 265 if not line or line.isspace():
263 266 return line
264 267 lineinf = LineInfo(line)
265 268 if lineinf.esc not in tr:
266 269 return line
267 270
268 271 return tr[lineinf.esc](lineinf)
269 272
270 273 _initial_space_re = re.compile(r'\s*')
271 274
272 275 _help_end_re = re.compile(r"""(%{0,2}
273 276 [a-zA-Z_*][\w*]* # Variable name
274 277 (\.[a-zA-Z_*][\w*]*)* # .etc.etc
275 278 )
276 279 (\?\??)$ # ? or ??
277 280 """,
278 281 re.VERBOSE)
279 282
280 283 # Extra pseudotokens for multiline strings and data structures
281 284 _MULTILINE_STRING = object()
282 285 _MULTILINE_STRUCTURE = object()
283 286
284 287 def _line_tokens(line):
285 288 """Helper for has_comment and ends_in_comment_or_string."""
286 289 readline = StringIO(line).readline
287 290 toktypes = set()
288 291 try:
289 292 for t in generate_tokens(readline):
290 293 toktypes.add(t[0])
291 294 except TokenError as e:
292 295 # There are only two cases where a TokenError is raised.
293 296 if 'multi-line string' in e.args[0]:
294 297 toktypes.add(_MULTILINE_STRING)
295 298 else:
296 299 toktypes.add(_MULTILINE_STRUCTURE)
297 300 return toktypes
298 301
299 302 def has_comment(src):
300 303 """Indicate whether an input line has (i.e. ends in, or is) a comment.
301 304
302 305 This uses tokenize, so it can distinguish comments from # inside strings.
303 306
304 307 Parameters
305 308 ----------
306 309 src : string
307 310 A single line input string.
308 311
309 312 Returns
310 313 -------
311 314 comment : bool
312 315 True if source has a comment.
313 316 """
314 317 return (tokenize2.COMMENT in _line_tokens(src))
315 318
316 319 def ends_in_comment_or_string(src):
317 320 """Indicates whether or not an input line ends in a comment or within
318 321 a multiline string.
319 322
320 323 Parameters
321 324 ----------
322 325 src : string
323 326 A single line input string.
324 327
325 328 Returns
326 329 -------
327 330 comment : bool
328 331 True if source ends in a comment or multiline string.
329 332 """
330 333 toktypes = _line_tokens(src)
331 334 return (tokenize2.COMMENT in toktypes) or (_MULTILINE_STRING in toktypes)
332 335
333 336
334 337 @StatelessInputTransformer.wrap
335 338 def help_end(line):
336 339 """Translate lines with ?/?? at the end"""
337 340 m = _help_end_re.search(line)
338 341 if m is None or ends_in_comment_or_string(line):
339 342 return line
340 343 target = m.group(1)
341 344 esc = m.group(3)
342 345 lspace = _initial_space_re.match(line).group(0)
343 346
344 347 # If we're mid-command, put it back on the next prompt for the user.
345 348 next_input = line.rstrip('?') if line.strip() != m.group(0) else None
346 349
347 350 return _make_help_call(target, esc, lspace, next_input)
348 351
349 352
350 353 @CoroutineInputTransformer.wrap
351 354 def cellmagic(end_on_blank_line=False):
352 355 """Captures & transforms cell magics.
353 356
354 357 After a cell magic is started, this stores up any lines it gets until it is
355 358 reset (sent None).
356 359 """
357 360 tpl = 'get_ipython().run_cell_magic(%r, %r, %r)'
358 361 cellmagic_help_re = re.compile('%%\w+\?')
359 362 line = ''
360 363 while True:
361 364 line = (yield line)
362 365 # consume leading empty lines
363 366 while not line:
364 367 line = (yield line)
365 368
366 369 if not line.startswith(ESC_MAGIC2):
367 370 # This isn't a cell magic, idle waiting for reset then start over
368 371 while line is not None:
369 372 line = (yield line)
370 373 continue
371 374
372 375 if cellmagic_help_re.match(line):
373 376 # This case will be handled by help_end
374 377 continue
375 378
376 379 first = line
377 380 body = []
378 381 line = (yield None)
379 382 while (line is not None) and \
380 383 ((line.strip() != '') or not end_on_blank_line):
381 384 body.append(line)
382 385 line = (yield None)
383 386
384 387 # Output
385 388 magic_name, _, first = first.partition(' ')
386 389 magic_name = magic_name.lstrip(ESC_MAGIC2)
387 390 line = tpl % (magic_name, first, u'\n'.join(body))
388 391
389 392
390 393 def _strip_prompts(prompt_re, initial_re=None, turnoff_re=None):
391 394 """Remove matching input prompts from a block of input.
392 395
393 396 Parameters
394 397 ----------
395 398 prompt_re : regular expression
396 399 A regular expression matching any input prompt (including continuation)
397 400 initial_re : regular expression, optional
398 401 A regular expression matching only the initial prompt, but not continuation.
399 402 If no initial expression is given, prompt_re will be used everywhere.
400 403 Used mainly for plain Python prompts, where the continuation prompt
401 404 ``...`` is a valid Python expression in Python 3, so shouldn't be stripped.
402 405
403 406 If initial_re and prompt_re differ,
404 407 only initial_re will be tested against the first line.
405 408 If any prompt is found on the first two lines,
406 409 prompts will be stripped from the rest of the block.
407 410 """
408 411 if initial_re is None:
409 412 initial_re = prompt_re
410 413 line = ''
411 414 while True:
412 415 line = (yield line)
413 416
414 417 # First line of cell
415 418 if line is None:
416 419 continue
417 420 out, n1 = initial_re.subn('', line, count=1)
418 421 if turnoff_re and not n1:
419 422 if turnoff_re.match(line):
420 423 # We're in e.g. a cell magic; disable this transformer for
421 424 # the rest of the cell.
422 425 while line is not None:
423 426 line = (yield line)
424 427 continue
425 428
426 429 line = (yield out)
427 430
428 431 if line is None:
429 432 continue
430 433 # check for any prompt on the second line of the cell,
431 434 # because people often copy from just after the first prompt,
432 435 # so we might not see it in the first line.
433 436 out, n2 = prompt_re.subn('', line, count=1)
434 437 line = (yield out)
435 438
436 439 if n1 or n2:
437 440 # Found a prompt in the first two lines - check for it in
438 441 # the rest of the cell as well.
439 442 while line is not None:
440 443 line = (yield prompt_re.sub('', line, count=1))
441 444
442 445 else:
443 446 # Prompts not in input - wait for reset
444 447 while line is not None:
445 448 line = (yield line)
446 449
447 450 @CoroutineInputTransformer.wrap
448 451 def classic_prompt():
449 452 """Strip the >>>/... prompts of the Python interactive shell."""
450 453 # FIXME: non-capturing version (?:...) usable?
451 454 prompt_re = re.compile(r'^(>>>|\.\.\.)( |$)')
452 455 initial_re = re.compile(r'^>>>( |$)')
453 456 # Any %magic/!system is IPython syntax, so we needn't look for >>> prompts
454 457 turnoff_re = re.compile(r'^[%!]')
455 458 return _strip_prompts(prompt_re, initial_re, turnoff_re)
456 459
457 460 @CoroutineInputTransformer.wrap
458 461 def ipy_prompt():
459 462 """Strip IPython's In [1]:/...: prompts."""
460 463 # FIXME: non-capturing version (?:...) usable?
461 464 prompt_re = re.compile(r'^(In \[\d+\]: |\s*\.{3,}: ?)')
462 465 # Disable prompt stripping inside cell magics
463 466 turnoff_re = re.compile(r'^%%')
464 467 return _strip_prompts(prompt_re, turnoff_re=turnoff_re)
465 468
466 469
467 470 @CoroutineInputTransformer.wrap
468 471 def leading_indent():
469 472 """Remove leading indentation.
470 473
471 474 If the first line starts with a spaces or tabs, the same whitespace will be
472 475 removed from each following line until it is reset.
473 476 """
474 477 space_re = re.compile(r'^[ \t]+')
475 478 line = ''
476 479 while True:
477 480 line = (yield line)
478 481
479 482 if line is None:
480 483 continue
481 484
482 485 m = space_re.match(line)
483 486 if m:
484 487 space = m.group(0)
485 488 while line is not None:
486 489 if line.startswith(space):
487 490 line = line[len(space):]
488 491 line = (yield line)
489 492 else:
490 493 # No leading spaces - wait for reset
491 494 while line is not None:
492 495 line = (yield line)
493 496
494 497
495 498 _assign_pat = \
496 499 r'''(?P<lhs>(\s*)
497 500 ([\w\.]+) # Initial identifier
498 501 (\s*,\s*
499 502 \*?[\w\.]+)* # Further identifiers for unpacking
500 503 \s*?,? # Trailing comma
501 504 )
502 505 \s*=\s*
503 506 '''
504 507
505 508 assign_system_re = re.compile(r'{}!\s*(?P<cmd>.*)'.format(_assign_pat), re.VERBOSE)
506 509 assign_system_template = '%s = get_ipython().getoutput(%r)'
507 510 @StatelessInputTransformer.wrap
508 511 def assign_from_system(line):
509 512 """Transform assignment from system commands (e.g. files = !ls)"""
510 513 m = assign_system_re.match(line)
511 514 if m is None:
512 515 return line
513 516
514 517 return assign_system_template % m.group('lhs', 'cmd')
515 518
516 519 assign_magic_re = re.compile(r'{}%\s*(?P<cmd>.*)'.format(_assign_pat), re.VERBOSE)
517 assign_magic_template = '%s = get_ipython().magic(%r)'
520 assign_magic_template = '%s = get_ipython().run_line_magic(%r, %r)'
518 521 @StatelessInputTransformer.wrap
519 522 def assign_from_magic(line):
520 523 """Transform assignment from magic commands (e.g. a = %who_ls)"""
521 524 m = assign_magic_re.match(line)
522 525 if m is None:
523 526 return line
524
525 return assign_magic_template % m.group('lhs', 'cmd')
527 #Prepare arguments for get_ipython().run_line_magic(magic_name, magic_args)
528 m_lhs, m_cmd = m.group('lhs', 'cmd')
529 t_magic_name, _, t_magic_arg_s = cmd.partition(' ')
530 t_magic_name = t_magic_name.lstrip(ESC_MAGIC)
531 return assign_magic_template % (m_lhs, t_magic_name, t_magic_arg_s)
@@ -1,318 +1,318 b''
1 1 """Implementation of magic functions related to History.
2 2 """
3 3 #-----------------------------------------------------------------------------
4 4 # Copyright (c) 2012, IPython Development Team.
5 5 #
6 6 # Distributed under the terms of the Modified BSD License.
7 7 #
8 8 # The full license is in the file COPYING.txt, distributed with this software.
9 9 #-----------------------------------------------------------------------------
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Imports
13 13 #-----------------------------------------------------------------------------
14 14
15 15 # Stdlib
16 16 import os
17 17 import sys
18 18 from io import open as io_open
19 19
20 20 # Our own packages
21 21 from IPython.core.error import StdinNotImplementedError
22 22 from IPython.core.magic import Magics, magics_class, line_magic
23 23 from IPython.core.magic_arguments import (argument, magic_arguments,
24 24 parse_argstring)
25 25 from IPython.testing.skipdoctest import skip_doctest
26 26 from IPython.utils import io
27 27
28 28 #-----------------------------------------------------------------------------
29 29 # Magics class implementation
30 30 #-----------------------------------------------------------------------------
31 31
32 32
33 33 _unspecified = object()
34 34
35 35
36 36 @magics_class
37 37 class HistoryMagics(Magics):
38 38
39 39 @magic_arguments()
40 40 @argument(
41 41 '-n', dest='print_nums', action='store_true', default=False,
42 42 help="""
43 43 print line numbers for each input.
44 44 This feature is only available if numbered prompts are in use.
45 45 """)
46 46 @argument(
47 47 '-o', dest='get_output', action='store_true', default=False,
48 48 help="also print outputs for each input.")
49 49 @argument(
50 50 '-p', dest='pyprompts', action='store_true', default=False,
51 51 help="""
52 52 print classic '>>>' python prompts before each input.
53 53 This is useful for making documentation, and in conjunction
54 54 with -o, for producing doctest-ready output.
55 55 """)
56 56 @argument(
57 57 '-t', dest='raw', action='store_false', default=True,
58 58 help="""
59 59 print the 'translated' history, as IPython understands it.
60 60 IPython filters your input and converts it all into valid Python
61 61 source before executing it (things like magics or aliases are turned
62 62 into function calls, for example). With this option, you'll see the
63 63 native history instead of the user-entered version: '%%cd /' will be
64 seen as 'get_ipython().magic("%%cd /")' instead of '%%cd /'.
64 seen as 'get_ipython().run_line_magic("cd", "/")' instead of '%%cd /'.
65 65 """)
66 66 @argument(
67 67 '-f', dest='filename',
68 68 help="""
69 69 FILENAME: instead of printing the output to the screen, redirect
70 70 it to the given file. The file is always overwritten, though *when
71 71 it can*, IPython asks for confirmation first. In particular, running
72 72 the command 'history -f FILENAME' from the IPython Notebook
73 73 interface will replace FILENAME even if it already exists *without*
74 74 confirmation.
75 75 """)
76 76 @argument(
77 77 '-g', dest='pattern', nargs='*', default=None,
78 78 help="""
79 79 treat the arg as a glob pattern to search for in (full) history.
80 80 This includes the saved history (almost all commands ever written).
81 81 The pattern may contain '?' to match one unknown character and '*'
82 82 to match any number of unknown characters. Use '%%hist -g' to show
83 83 full saved history (may be very long).
84 84 """)
85 85 @argument(
86 86 '-l', dest='limit', type=int, nargs='?', default=_unspecified,
87 87 help="""
88 88 get the last n lines from all sessions. Specify n as a single
89 89 arg, or the default is the last 10 lines.
90 90 """)
91 91 @argument(
92 92 '-u', dest='unique', action='store_true',
93 93 help="""
94 94 when searching history using `-g`, show only unique history.
95 95 """)
96 96 @argument('range', nargs='*')
97 97 @skip_doctest
98 98 @line_magic
99 99 def history(self, parameter_s = ''):
100 100 """Print input history (_i<n> variables), with most recent last.
101 101
102 102 By default, input history is printed without line numbers so it can be
103 103 directly pasted into an editor. Use -n to show them.
104 104
105 105 By default, all input history from the current session is displayed.
106 106 Ranges of history can be indicated using the syntax:
107 107
108 108 ``4``
109 109 Line 4, current session
110 110 ``4-6``
111 111 Lines 4-6, current session
112 112 ``243/1-5``
113 113 Lines 1-5, session 243
114 114 ``~2/7``
115 115 Line 7, session 2 before current
116 116 ``~8/1-~6/5``
117 117 From the first line of 8 sessions ago, to the fifth line of 6
118 118 sessions ago.
119 119
120 120 Multiple ranges can be entered, separated by spaces
121 121
122 122 The same syntax is used by %macro, %save, %edit, %rerun
123 123
124 124 Examples
125 125 --------
126 126 ::
127 127
128 128 In [6]: %history -n 4-6
129 129 4:a = 12
130 130 5:print a**2
131 131 6:%history -n 4-6
132 132
133 133 """
134 134
135 135 args = parse_argstring(self.history, parameter_s)
136 136
137 137 # For brevity
138 138 history_manager = self.shell.history_manager
139 139
140 140 def _format_lineno(session, line):
141 141 """Helper function to format line numbers properly."""
142 142 if session in (0, history_manager.session_number):
143 143 return str(line)
144 144 return "%s/%s" % (session, line)
145 145
146 146 # Check if output to specific file was requested.
147 147 outfname = args.filename
148 148 if not outfname:
149 149 outfile = sys.stdout # default
150 150 # We don't want to close stdout at the end!
151 151 close_at_end = False
152 152 else:
153 153 if os.path.exists(outfname):
154 154 try:
155 155 ans = io.ask_yes_no("File %r exists. Overwrite?" % outfname)
156 156 except StdinNotImplementedError:
157 157 ans = True
158 158 if not ans:
159 159 print('Aborting.')
160 160 return
161 161 print("Overwriting file.")
162 162 outfile = io_open(outfname, 'w', encoding='utf-8')
163 163 close_at_end = True
164 164
165 165 print_nums = args.print_nums
166 166 get_output = args.get_output
167 167 pyprompts = args.pyprompts
168 168 raw = args.raw
169 169
170 170 pattern = None
171 171 limit = None if args.limit is _unspecified else args.limit
172 172
173 173 if args.pattern is not None:
174 174 if args.pattern:
175 175 pattern = "*" + " ".join(args.pattern) + "*"
176 176 else:
177 177 pattern = "*"
178 178 hist = history_manager.search(pattern, raw=raw, output=get_output,
179 179 n=limit, unique=args.unique)
180 180 print_nums = True
181 181 elif args.limit is not _unspecified:
182 182 n = 10 if limit is None else limit
183 183 hist = history_manager.get_tail(n, raw=raw, output=get_output)
184 184 else:
185 185 if args.range: # Get history by ranges
186 186 hist = history_manager.get_range_by_str(" ".join(args.range),
187 187 raw, get_output)
188 188 else: # Just get history for the current session
189 189 hist = history_manager.get_range(raw=raw, output=get_output)
190 190
191 191 # We could be displaying the entire history, so let's not try to pull
192 192 # it into a list in memory. Anything that needs more space will just
193 193 # misalign.
194 194 width = 4
195 195
196 196 for session, lineno, inline in hist:
197 197 # Print user history with tabs expanded to 4 spaces. The GUI
198 198 # clients use hard tabs for easier usability in auto-indented code,
199 199 # but we want to produce PEP-8 compliant history for safe pasting
200 200 # into an editor.
201 201 if get_output:
202 202 inline, output = inline
203 203 inline = inline.expandtabs(4).rstrip()
204 204
205 205 multiline = "\n" in inline
206 206 line_sep = '\n' if multiline else ' '
207 207 if print_nums:
208 208 print(u'%s:%s' % (_format_lineno(session, lineno).rjust(width),
209 209 line_sep), file=outfile, end=u'')
210 210 if pyprompts:
211 211 print(u">>> ", end=u"", file=outfile)
212 212 if multiline:
213 213 inline = "\n... ".join(inline.splitlines()) + "\n..."
214 214 print(inline, file=outfile)
215 215 if get_output and output:
216 216 print(output, file=outfile)
217 217
218 218 if close_at_end:
219 219 outfile.close()
220 220
221 221 @line_magic
222 222 def recall(self, arg):
223 223 r"""Repeat a command, or get command to input line for editing.
224 224
225 225 %recall and %rep are equivalent.
226 226
227 227 - %recall (no arguments):
228 228
229 229 Place a string version of last computation result (stored in the
230 230 special '_' variable) to the next input prompt. Allows you to create
231 231 elaborate command lines without using copy-paste::
232 232
233 233 In[1]: l = ["hei", "vaan"]
234 234 In[2]: "".join(l)
235 235 Out[2]: heivaan
236 236 In[3]: %recall
237 237 In[4]: heivaan_ <== cursor blinking
238 238
239 239 %recall 45
240 240
241 241 Place history line 45 on the next input prompt. Use %hist to find
242 242 out the number.
243 243
244 244 %recall 1-4
245 245
246 246 Combine the specified lines into one cell, and place it on the next
247 247 input prompt. See %history for the slice syntax.
248 248
249 249 %recall foo+bar
250 250
251 251 If foo+bar can be evaluated in the user namespace, the result is
252 252 placed at the next input prompt. Otherwise, the history is searched
253 253 for lines which contain that substring, and the most recent one is
254 254 placed at the next input prompt.
255 255 """
256 256 if not arg: # Last output
257 257 self.shell.set_next_input(str(self.shell.user_ns["_"]))
258 258 return
259 259 # Get history range
260 260 histlines = self.shell.history_manager.get_range_by_str(arg)
261 261 cmd = "\n".join(x[2] for x in histlines)
262 262 if cmd:
263 263 self.shell.set_next_input(cmd.rstrip())
264 264 return
265 265
266 266 try: # Variable in user namespace
267 267 cmd = str(eval(arg, self.shell.user_ns))
268 268 except Exception: # Search for term in history
269 269 histlines = self.shell.history_manager.search("*"+arg+"*")
270 270 for h in reversed([x[2] for x in histlines]):
271 271 if 'recall' in h or 'rep' in h:
272 272 continue
273 273 self.shell.set_next_input(h.rstrip())
274 274 return
275 275 else:
276 276 self.shell.set_next_input(cmd.rstrip())
277 277 print("Couldn't evaluate or find in history:", arg)
278 278
279 279 @line_magic
280 280 def rerun(self, parameter_s=''):
281 281 """Re-run previous input
282 282
283 283 By default, you can specify ranges of input history to be repeated
284 284 (as with %history). With no arguments, it will repeat the last line.
285 285
286 286 Options:
287 287
288 288 -l <n> : Repeat the last n lines of input, not including the
289 289 current command.
290 290
291 291 -g foo : Repeat the most recent line which contains foo
292 292 """
293 293 opts, args = self.parse_options(parameter_s, 'l:g:', mode='string')
294 294 if "l" in opts: # Last n lines
295 295 n = int(opts['l'])
296 296 hist = self.shell.history_manager.get_tail(n)
297 297 elif "g" in opts: # Search
298 298 p = "*"+opts['g']+"*"
299 299 hist = list(self.shell.history_manager.search(p))
300 300 for l in reversed(hist):
301 301 if "rerun" not in l[2]:
302 302 hist = [l] # The last match which isn't a %rerun
303 303 break
304 304 else:
305 305 hist = [] # No matches except %rerun
306 306 elif args: # Specify history ranges
307 307 hist = self.shell.history_manager.get_range_by_str(args)
308 308 else: # Last line
309 309 hist = self.shell.history_manager.get_tail(1)
310 310 hist = [x[2] for x in hist]
311 311 if not hist:
312 312 print("No lines in history match specification")
313 313 return
314 314 histlines = "\n".join(hist)
315 315 print("=== Executing: ===")
316 316 print(histlines)
317 317 print("=== Output: ===")
318 318 self.shell.run_cell("\n".join(hist), store_history=False)
@@ -1,706 +1,709 b''
1 1 # encoding: utf-8
2 2 """
3 3 Prefiltering components.
4 4
5 5 Prefilters transform user input before it is exec'd by Python. These
6 6 transforms are used to implement additional syntax such as !ls and %magic.
7 7 """
8 8
9 9 # Copyright (c) IPython Development Team.
10 10 # Distributed under the terms of the Modified BSD License.
11 11
12 12 from keyword import iskeyword
13 13 import re
14 14
15 15 from IPython.core.autocall import IPyAutocall
16 16 from traitlets.config.configurable import Configurable
17 17 from IPython.core.inputsplitter import (
18 18 ESC_MAGIC,
19 19 ESC_QUOTE,
20 20 ESC_QUOTE2,
21 21 ESC_PAREN,
22 22 )
23 23 from IPython.core.macro import Macro
24 24 from IPython.core.splitinput import LineInfo
25 25
26 26 from traitlets import (
27 27 List, Integer, Unicode, Bool, Instance, CRegExp
28 28 )
29 29
30 30 #-----------------------------------------------------------------------------
31 31 # Global utilities, errors and constants
32 32 #-----------------------------------------------------------------------------
33 33
34 34
35 35 class PrefilterError(Exception):
36 36 pass
37 37
38 38
39 39 # RegExp to identify potential function names
40 40 re_fun_name = re.compile(r'[a-zA-Z_]([a-zA-Z0-9_.]*) *$')
41 41
42 42 # RegExp to exclude strings with this start from autocalling. In
43 43 # particular, all binary operators should be excluded, so that if foo is
44 44 # callable, foo OP bar doesn't become foo(OP bar), which is invalid. The
45 45 # characters '!=()' don't need to be checked for, as the checkPythonChars
46 46 # routine explicitely does so, to catch direct calls and rebindings of
47 47 # existing names.
48 48
49 49 # Warning: the '-' HAS TO BE AT THE END of the first group, otherwise
50 50 # it affects the rest of the group in square brackets.
51 51 re_exclude_auto = re.compile(r'^[,&^\|\*/\+-]'
52 52 r'|^is |^not |^in |^and |^or ')
53 53
54 54 # try to catch also methods for stuff in lists/tuples/dicts: off
55 55 # (experimental). For this to work, the line_split regexp would need
56 56 # to be modified so it wouldn't break things at '['. That line is
57 57 # nasty enough that I shouldn't change it until I can test it _well_.
58 58 #self.re_fun_name = re.compile (r'[a-zA-Z_]([a-zA-Z0-9_.\[\]]*) ?$')
59 59
60 60
61 61 # Handler Check Utilities
62 62 def is_shadowed(identifier, ip):
63 63 """Is the given identifier defined in one of the namespaces which shadow
64 64 the alias and magic namespaces? Note that an identifier is different
65 65 than ifun, because it can not contain a '.' character."""
66 66 # This is much safer than calling ofind, which can change state
67 67 return (identifier in ip.user_ns \
68 68 or identifier in ip.user_global_ns \
69 69 or identifier in ip.ns_table['builtin']\
70 70 or iskeyword(identifier))
71 71
72 72
73 73 #-----------------------------------------------------------------------------
74 74 # Main Prefilter manager
75 75 #-----------------------------------------------------------------------------
76 76
77 77
78 78 class PrefilterManager(Configurable):
79 79 """Main prefilter component.
80 80
81 81 The IPython prefilter is run on all user input before it is run. The
82 82 prefilter consumes lines of input and produces transformed lines of
83 83 input.
84 84
85 85 The iplementation consists of two phases:
86 86
87 87 1. Transformers
88 88 2. Checkers and handlers
89 89
90 90 Over time, we plan on deprecating the checkers and handlers and doing
91 91 everything in the transformers.
92 92
93 93 The transformers are instances of :class:`PrefilterTransformer` and have
94 94 a single method :meth:`transform` that takes a line and returns a
95 95 transformed line. The transformation can be accomplished using any
96 96 tool, but our current ones use regular expressions for speed.
97 97
98 98 After all the transformers have been run, the line is fed to the checkers,
99 99 which are instances of :class:`PrefilterChecker`. The line is passed to
100 100 the :meth:`check` method, which either returns `None` or a
101 101 :class:`PrefilterHandler` instance. If `None` is returned, the other
102 102 checkers are tried. If an :class:`PrefilterHandler` instance is returned,
103 103 the line is passed to the :meth:`handle` method of the returned
104 104 handler and no further checkers are tried.
105 105
106 106 Both transformers and checkers have a `priority` attribute, that determines
107 107 the order in which they are called. Smaller priorities are tried first.
108 108
109 109 Both transformers and checkers also have `enabled` attribute, which is
110 110 a boolean that determines if the instance is used.
111 111
112 112 Users or developers can change the priority or enabled attribute of
113 113 transformers or checkers, but they must call the :meth:`sort_checkers`
114 114 or :meth:`sort_transformers` method after changing the priority.
115 115 """
116 116
117 117 multi_line_specials = Bool(True).tag(config=True)
118 118 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
119 119
120 120 def __init__(self, shell=None, **kwargs):
121 121 super(PrefilterManager, self).__init__(shell=shell, **kwargs)
122 122 self.shell = shell
123 123 self.init_transformers()
124 124 self.init_handlers()
125 125 self.init_checkers()
126 126
127 127 #-------------------------------------------------------------------------
128 128 # API for managing transformers
129 129 #-------------------------------------------------------------------------
130 130
131 131 def init_transformers(self):
132 132 """Create the default transformers."""
133 133 self._transformers = []
134 134 for transformer_cls in _default_transformers:
135 135 transformer_cls(
136 136 shell=self.shell, prefilter_manager=self, parent=self
137 137 )
138 138
139 139 def sort_transformers(self):
140 140 """Sort the transformers by priority.
141 141
142 142 This must be called after the priority of a transformer is changed.
143 143 The :meth:`register_transformer` method calls this automatically.
144 144 """
145 145 self._transformers.sort(key=lambda x: x.priority)
146 146
147 147 @property
148 148 def transformers(self):
149 149 """Return a list of checkers, sorted by priority."""
150 150 return self._transformers
151 151
152 152 def register_transformer(self, transformer):
153 153 """Register a transformer instance."""
154 154 if transformer not in self._transformers:
155 155 self._transformers.append(transformer)
156 156 self.sort_transformers()
157 157
158 158 def unregister_transformer(self, transformer):
159 159 """Unregister a transformer instance."""
160 160 if transformer in self._transformers:
161 161 self._transformers.remove(transformer)
162 162
163 163 #-------------------------------------------------------------------------
164 164 # API for managing checkers
165 165 #-------------------------------------------------------------------------
166 166
167 167 def init_checkers(self):
168 168 """Create the default checkers."""
169 169 self._checkers = []
170 170 for checker in _default_checkers:
171 171 checker(
172 172 shell=self.shell, prefilter_manager=self, parent=self
173 173 )
174 174
175 175 def sort_checkers(self):
176 176 """Sort the checkers by priority.
177 177
178 178 This must be called after the priority of a checker is changed.
179 179 The :meth:`register_checker` method calls this automatically.
180 180 """
181 181 self._checkers.sort(key=lambda x: x.priority)
182 182
183 183 @property
184 184 def checkers(self):
185 185 """Return a list of checkers, sorted by priority."""
186 186 return self._checkers
187 187
188 188 def register_checker(self, checker):
189 189 """Register a checker instance."""
190 190 if checker not in self._checkers:
191 191 self._checkers.append(checker)
192 192 self.sort_checkers()
193 193
194 194 def unregister_checker(self, checker):
195 195 """Unregister a checker instance."""
196 196 if checker in self._checkers:
197 197 self._checkers.remove(checker)
198 198
199 199 #-------------------------------------------------------------------------
200 200 # API for managing handlers
201 201 #-------------------------------------------------------------------------
202 202
203 203 def init_handlers(self):
204 204 """Create the default handlers."""
205 205 self._handlers = {}
206 206 self._esc_handlers = {}
207 207 for handler in _default_handlers:
208 208 handler(
209 209 shell=self.shell, prefilter_manager=self, parent=self
210 210 )
211 211
212 212 @property
213 213 def handlers(self):
214 214 """Return a dict of all the handlers."""
215 215 return self._handlers
216 216
217 217 def register_handler(self, name, handler, esc_strings):
218 218 """Register a handler instance by name with esc_strings."""
219 219 self._handlers[name] = handler
220 220 for esc_str in esc_strings:
221 221 self._esc_handlers[esc_str] = handler
222 222
223 223 def unregister_handler(self, name, handler, esc_strings):
224 224 """Unregister a handler instance by name with esc_strings."""
225 225 try:
226 226 del self._handlers[name]
227 227 except KeyError:
228 228 pass
229 229 for esc_str in esc_strings:
230 230 h = self._esc_handlers.get(esc_str)
231 231 if h is handler:
232 232 del self._esc_handlers[esc_str]
233 233
234 234 def get_handler_by_name(self, name):
235 235 """Get a handler by its name."""
236 236 return self._handlers.get(name)
237 237
238 238 def get_handler_by_esc(self, esc_str):
239 239 """Get a handler by its escape string."""
240 240 return self._esc_handlers.get(esc_str)
241 241
242 242 #-------------------------------------------------------------------------
243 243 # Main prefiltering API
244 244 #-------------------------------------------------------------------------
245 245
246 246 def prefilter_line_info(self, line_info):
247 247 """Prefilter a line that has been converted to a LineInfo object.
248 248
249 249 This implements the checker/handler part of the prefilter pipe.
250 250 """
251 251 # print "prefilter_line_info: ", line_info
252 252 handler = self.find_handler(line_info)
253 253 return handler.handle(line_info)
254 254
255 255 def find_handler(self, line_info):
256 256 """Find a handler for the line_info by trying checkers."""
257 257 for checker in self.checkers:
258 258 if checker.enabled:
259 259 handler = checker.check(line_info)
260 260 if handler:
261 261 return handler
262 262 return self.get_handler_by_name('normal')
263 263
264 264 def transform_line(self, line, continue_prompt):
265 265 """Calls the enabled transformers in order of increasing priority."""
266 266 for transformer in self.transformers:
267 267 if transformer.enabled:
268 268 line = transformer.transform(line, continue_prompt)
269 269 return line
270 270
271 271 def prefilter_line(self, line, continue_prompt=False):
272 272 """Prefilter a single input line as text.
273 273
274 274 This method prefilters a single line of text by calling the
275 275 transformers and then the checkers/handlers.
276 276 """
277 277
278 278 # print "prefilter_line: ", line, continue_prompt
279 279 # All handlers *must* return a value, even if it's blank ('').
280 280
281 281 # save the line away in case we crash, so the post-mortem handler can
282 282 # record it
283 283 self.shell._last_input_line = line
284 284
285 285 if not line:
286 286 # Return immediately on purely empty lines, so that if the user
287 287 # previously typed some whitespace that started a continuation
288 288 # prompt, he can break out of that loop with just an empty line.
289 289 # This is how the default python prompt works.
290 290 return ''
291 291
292 292 # At this point, we invoke our transformers.
293 293 if not continue_prompt or (continue_prompt and self.multi_line_specials):
294 294 line = self.transform_line(line, continue_prompt)
295 295
296 296 # Now we compute line_info for the checkers and handlers
297 297 line_info = LineInfo(line, continue_prompt)
298 298
299 299 # the input history needs to track even empty lines
300 300 stripped = line.strip()
301 301
302 302 normal_handler = self.get_handler_by_name('normal')
303 303 if not stripped:
304 304 return normal_handler.handle(line_info)
305 305
306 306 # special handlers are only allowed for single line statements
307 307 if continue_prompt and not self.multi_line_specials:
308 308 return normal_handler.handle(line_info)
309 309
310 310 prefiltered = self.prefilter_line_info(line_info)
311 311 # print "prefiltered line: %r" % prefiltered
312 312 return prefiltered
313 313
314 314 def prefilter_lines(self, lines, continue_prompt=False):
315 315 """Prefilter multiple input lines of text.
316 316
317 317 This is the main entry point for prefiltering multiple lines of
318 318 input. This simply calls :meth:`prefilter_line` for each line of
319 319 input.
320 320
321 321 This covers cases where there are multiple lines in the user entry,
322 322 which is the case when the user goes back to a multiline history
323 323 entry and presses enter.
324 324 """
325 325 llines = lines.rstrip('\n').split('\n')
326 326 # We can get multiple lines in one shot, where multiline input 'blends'
327 327 # into one line, in cases like recalling from the readline history
328 328 # buffer. We need to make sure that in such cases, we correctly
329 329 # communicate downstream which line is first and which are continuation
330 330 # ones.
331 331 if len(llines) > 1:
332 332 out = '\n'.join([self.prefilter_line(line, lnum>0)
333 333 for lnum, line in enumerate(llines) ])
334 334 else:
335 335 out = self.prefilter_line(llines[0], continue_prompt)
336 336
337 337 return out
338 338
339 339 #-----------------------------------------------------------------------------
340 340 # Prefilter transformers
341 341 #-----------------------------------------------------------------------------
342 342
343 343
344 344 class PrefilterTransformer(Configurable):
345 345 """Transform a line of user input."""
346 346
347 347 priority = Integer(100).tag(config=True)
348 348 # Transformers don't currently use shell or prefilter_manager, but as we
349 349 # move away from checkers and handlers, they will need them.
350 350 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
351 351 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager', allow_none=True)
352 352 enabled = Bool(True).tag(config=True)
353 353
354 354 def __init__(self, shell=None, prefilter_manager=None, **kwargs):
355 355 super(PrefilterTransformer, self).__init__(
356 356 shell=shell, prefilter_manager=prefilter_manager, **kwargs
357 357 )
358 358 self.prefilter_manager.register_transformer(self)
359 359
360 360 def transform(self, line, continue_prompt):
361 361 """Transform a line, returning the new one."""
362 362 return None
363 363
364 364 def __repr__(self):
365 365 return "<%s(priority=%r, enabled=%r)>" % (
366 366 self.__class__.__name__, self.priority, self.enabled)
367 367
368 368
369 369 #-----------------------------------------------------------------------------
370 370 # Prefilter checkers
371 371 #-----------------------------------------------------------------------------
372 372
373 373
374 374 class PrefilterChecker(Configurable):
375 375 """Inspect an input line and return a handler for that line."""
376 376
377 377 priority = Integer(100).tag(config=True)
378 378 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
379 379 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager', allow_none=True)
380 380 enabled = Bool(True).tag(config=True)
381 381
382 382 def __init__(self, shell=None, prefilter_manager=None, **kwargs):
383 383 super(PrefilterChecker, self).__init__(
384 384 shell=shell, prefilter_manager=prefilter_manager, **kwargs
385 385 )
386 386 self.prefilter_manager.register_checker(self)
387 387
388 388 def check(self, line_info):
389 389 """Inspect line_info and return a handler instance or None."""
390 390 return None
391 391
392 392 def __repr__(self):
393 393 return "<%s(priority=%r, enabled=%r)>" % (
394 394 self.__class__.__name__, self.priority, self.enabled)
395 395
396 396
397 397 class EmacsChecker(PrefilterChecker):
398 398
399 399 priority = Integer(100).tag(config=True)
400 400 enabled = Bool(False).tag(config=True)
401 401
402 402 def check(self, line_info):
403 403 "Emacs ipython-mode tags certain input lines."
404 404 if line_info.line.endswith('# PYTHON-MODE'):
405 405 return self.prefilter_manager.get_handler_by_name('emacs')
406 406 else:
407 407 return None
408 408
409 409
410 410 class MacroChecker(PrefilterChecker):
411 411
412 412 priority = Integer(250).tag(config=True)
413 413
414 414 def check(self, line_info):
415 415 obj = self.shell.user_ns.get(line_info.ifun)
416 416 if isinstance(obj, Macro):
417 417 return self.prefilter_manager.get_handler_by_name('macro')
418 418 else:
419 419 return None
420 420
421 421
422 422 class IPyAutocallChecker(PrefilterChecker):
423 423
424 424 priority = Integer(300).tag(config=True)
425 425
426 426 def check(self, line_info):
427 427 "Instances of IPyAutocall in user_ns get autocalled immediately"
428 428 obj = self.shell.user_ns.get(line_info.ifun, None)
429 429 if isinstance(obj, IPyAutocall):
430 430 obj.set_ip(self.shell)
431 431 return self.prefilter_manager.get_handler_by_name('auto')
432 432 else:
433 433 return None
434 434
435 435
436 436 class AssignmentChecker(PrefilterChecker):
437 437
438 438 priority = Integer(600).tag(config=True)
439 439
440 440 def check(self, line_info):
441 441 """Check to see if user is assigning to a var for the first time, in
442 442 which case we want to avoid any sort of automagic / autocall games.
443 443
444 444 This allows users to assign to either alias or magic names true python
445 445 variables (the magic/alias systems always take second seat to true
446 446 python code). E.g. ls='hi', or ls,that=1,2"""
447 447 if line_info.the_rest:
448 448 if line_info.the_rest[0] in '=,':
449 449 return self.prefilter_manager.get_handler_by_name('normal')
450 450 else:
451 451 return None
452 452
453 453
454 454 class AutoMagicChecker(PrefilterChecker):
455 455
456 456 priority = Integer(700).tag(config=True)
457 457
458 458 def check(self, line_info):
459 459 """If the ifun is magic, and automagic is on, run it. Note: normal,
460 460 non-auto magic would already have been triggered via '%' in
461 461 check_esc_chars. This just checks for automagic. Also, before
462 462 triggering the magic handler, make sure that there is nothing in the
463 463 user namespace which could shadow it."""
464 464 if not self.shell.automagic or not self.shell.find_magic(line_info.ifun):
465 465 return None
466 466
467 467 # We have a likely magic method. Make sure we should actually call it.
468 468 if line_info.continue_prompt and not self.prefilter_manager.multi_line_specials:
469 469 return None
470 470
471 471 head = line_info.ifun.split('.',1)[0]
472 472 if is_shadowed(head, self.shell):
473 473 return None
474 474
475 475 return self.prefilter_manager.get_handler_by_name('magic')
476 476
477 477
478 478 class PythonOpsChecker(PrefilterChecker):
479 479
480 480 priority = Integer(900).tag(config=True)
481 481
482 482 def check(self, line_info):
483 483 """If the 'rest' of the line begins with a function call or pretty much
484 484 any python operator, we should simply execute the line (regardless of
485 485 whether or not there's a possible autocall expansion). This avoids
486 486 spurious (and very confusing) geattr() accesses."""
487 487 if line_info.the_rest and line_info.the_rest[0] in '!=()<>,+*/%^&|':
488 488 return self.prefilter_manager.get_handler_by_name('normal')
489 489 else:
490 490 return None
491 491
492 492
493 493 class AutocallChecker(PrefilterChecker):
494 494
495 495 priority = Integer(1000).tag(config=True)
496 496
497 497 function_name_regexp = CRegExp(re_fun_name,
498 498 help="RegExp to identify potential function names."
499 499 ).tag(config=True)
500 500 exclude_regexp = CRegExp(re_exclude_auto,
501 501 help="RegExp to exclude strings with this start from autocalling."
502 502 ).tag(config=True)
503 503
504 504 def check(self, line_info):
505 505 "Check if the initial word/function is callable and autocall is on."
506 506 if not self.shell.autocall:
507 507 return None
508 508
509 509 oinfo = line_info.ofind(self.shell) # This can mutate state via getattr
510 510 if not oinfo['found']:
511 511 return None
512 512
513 513 ignored_funs = ['b', 'f', 'r', 'u', 'br', 'rb', 'fr', 'rf']
514 514 ifun = line_info.ifun
515 515 line = line_info.line
516 516 if ifun.lower() in ignored_funs and (line.startswith(ifun + "'") or line.startswith(ifun + '"')):
517 517 return None
518 518
519 519 if callable(oinfo['obj']) \
520 520 and (not self.exclude_regexp.match(line_info.the_rest)) \
521 521 and self.function_name_regexp.match(line_info.ifun):
522 522 return self.prefilter_manager.get_handler_by_name('auto')
523 523 else:
524 524 return None
525 525
526 526
527 527 #-----------------------------------------------------------------------------
528 528 # Prefilter handlers
529 529 #-----------------------------------------------------------------------------
530 530
531 531
532 532 class PrefilterHandler(Configurable):
533 533
534 534 handler_name = Unicode('normal')
535 535 esc_strings = List([])
536 536 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
537 537 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager', allow_none=True)
538 538
539 539 def __init__(self, shell=None, prefilter_manager=None, **kwargs):
540 540 super(PrefilterHandler, self).__init__(
541 541 shell=shell, prefilter_manager=prefilter_manager, **kwargs
542 542 )
543 543 self.prefilter_manager.register_handler(
544 544 self.handler_name,
545 545 self,
546 546 self.esc_strings
547 547 )
548 548
549 549 def handle(self, line_info):
550 550 # print "normal: ", line_info
551 551 """Handle normal input lines. Use as a template for handlers."""
552 552
553 553 # With autoindent on, we need some way to exit the input loop, and I
554 554 # don't want to force the user to have to backspace all the way to
555 555 # clear the line. The rule will be in this case, that either two
556 556 # lines of pure whitespace in a row, or a line of pure whitespace but
557 557 # of a size different to the indent level, will exit the input loop.
558 558 line = line_info.line
559 559 continue_prompt = line_info.continue_prompt
560 560
561 561 if (continue_prompt and
562 562 self.shell.autoindent and
563 563 line.isspace() and
564 564 0 < abs(len(line) - self.shell.indent_current_nsp) <= 2):
565 565 line = ''
566 566
567 567 return line
568 568
569 569 def __str__(self):
570 570 return "<%s(name=%s)>" % (self.__class__.__name__, self.handler_name)
571 571
572 572
573 573 class MacroHandler(PrefilterHandler):
574 574 handler_name = Unicode("macro")
575 575
576 576 def handle(self, line_info):
577 577 obj = self.shell.user_ns.get(line_info.ifun)
578 578 pre_space = line_info.pre_whitespace
579 579 line_sep = "\n" + pre_space
580 580 return pre_space + line_sep.join(obj.value.splitlines())
581 581
582 582
583 583 class MagicHandler(PrefilterHandler):
584 584
585 585 handler_name = Unicode('magic')
586 586 esc_strings = List([ESC_MAGIC])
587 587
588 588 def handle(self, line_info):
589 589 """Execute magic functions."""
590 590 ifun = line_info.ifun
591 591 the_rest = line_info.the_rest
592 cmd = '%sget_ipython().magic(%r)' % (line_info.pre_whitespace,
593 (ifun + " " + the_rest))
592 #Prepare arguments for get_ipython().run_line_magic(magic_name, magic_args)
593 t_arg_s = ifun + " " + the_rest
594 t_magic_name, _, t_magic_arg_s = t_arg_s.partition(' ')
595 t_magic_name = t_magic_name.lstrip(ESC_MAGIC)
596 cmd = '%sget_ipython().run_line_magic(%r, %r)' % (line_info.pre_whitespace, t_magic_name, t_magic_arg_s)
594 597 return cmd
595 598
596 599
597 600 class AutoHandler(PrefilterHandler):
598 601
599 602 handler_name = Unicode('auto')
600 603 esc_strings = List([ESC_PAREN, ESC_QUOTE, ESC_QUOTE2])
601 604
602 605 def handle(self, line_info):
603 606 """Handle lines which can be auto-executed, quoting if requested."""
604 607 line = line_info.line
605 608 ifun = line_info.ifun
606 609 the_rest = line_info.the_rest
607 610 esc = line_info.esc
608 611 continue_prompt = line_info.continue_prompt
609 612 obj = line_info.ofind(self.shell)['obj']
610 613
611 614 # This should only be active for single-line input!
612 615 if continue_prompt:
613 616 return line
614 617
615 618 force_auto = isinstance(obj, IPyAutocall)
616 619
617 620 # User objects sometimes raise exceptions on attribute access other
618 621 # than AttributeError (we've seen it in the past), so it's safest to be
619 622 # ultra-conservative here and catch all.
620 623 try:
621 624 auto_rewrite = obj.rewrite
622 625 except Exception:
623 626 auto_rewrite = True
624 627
625 628 if esc == ESC_QUOTE:
626 629 # Auto-quote splitting on whitespace
627 630 newcmd = '%s("%s")' % (ifun,'", "'.join(the_rest.split()) )
628 631 elif esc == ESC_QUOTE2:
629 632 # Auto-quote whole string
630 633 newcmd = '%s("%s")' % (ifun,the_rest)
631 634 elif esc == ESC_PAREN:
632 635 newcmd = '%s(%s)' % (ifun,",".join(the_rest.split()))
633 636 else:
634 637 # Auto-paren.
635 638 if force_auto:
636 639 # Don't rewrite if it is already a call.
637 640 do_rewrite = not the_rest.startswith('(')
638 641 else:
639 642 if not the_rest:
640 643 # We only apply it to argument-less calls if the autocall
641 644 # parameter is set to 2.
642 645 do_rewrite = (self.shell.autocall >= 2)
643 646 elif the_rest.startswith('[') and hasattr(obj, '__getitem__'):
644 647 # Don't autocall in this case: item access for an object
645 648 # which is BOTH callable and implements __getitem__.
646 649 do_rewrite = False
647 650 else:
648 651 do_rewrite = True
649 652
650 653 # Figure out the rewritten command
651 654 if do_rewrite:
652 655 if the_rest.endswith(';'):
653 656 newcmd = '%s(%s);' % (ifun.rstrip(),the_rest[:-1])
654 657 else:
655 658 newcmd = '%s(%s)' % (ifun.rstrip(), the_rest)
656 659 else:
657 660 normal_handler = self.prefilter_manager.get_handler_by_name('normal')
658 661 return normal_handler.handle(line_info)
659 662
660 663 # Display the rewritten call
661 664 if auto_rewrite:
662 665 self.shell.auto_rewrite_input(newcmd)
663 666
664 667 return newcmd
665 668
666 669
667 670 class EmacsHandler(PrefilterHandler):
668 671
669 672 handler_name = Unicode('emacs')
670 673 esc_strings = List([])
671 674
672 675 def handle(self, line_info):
673 676 """Handle input lines marked by python-mode."""
674 677
675 678 # Currently, nothing is done. Later more functionality can be added
676 679 # here if needed.
677 680
678 681 # The input cache shouldn't be updated
679 682 return line_info.line
680 683
681 684
682 685 #-----------------------------------------------------------------------------
683 686 # Defaults
684 687 #-----------------------------------------------------------------------------
685 688
686 689
687 690 _default_transformers = [
688 691 ]
689 692
690 693 _default_checkers = [
691 694 EmacsChecker,
692 695 MacroChecker,
693 696 IPyAutocallChecker,
694 697 AssignmentChecker,
695 698 AutoMagicChecker,
696 699 PythonOpsChecker,
697 700 AutocallChecker
698 701 ]
699 702
700 703 _default_handlers = [
701 704 PrefilterHandler,
702 705 MacroHandler,
703 706 MagicHandler,
704 707 AutoHandler,
705 708 EmacsHandler
706 709 ]
General Comments 0
You need to be logged in to leave comments. Login now