##// END OF EJS Templates
Merge pull request #13056 from eyenpi/fix-dpaste-magic...
Blazej Michalik -
r26665:b3355a94 merge
parent child Browse files
Show More
@@ -0,0 +1,7 b''
1 Pastebin magic expiry days option
2 =================================
3
4 The Pastebin magic now has ``-e`` option to determine
5 the number of days for paste expiration. For example
6 the paste that created with ``%pastebin -e 20 1`` magic will
7 be available for next 20 days.
@@ -1,737 +1,750 b''
1 1 """Implementation of code management magic functions.
2 2 """
3 3 #-----------------------------------------------------------------------------
4 4 # Copyright (c) 2012 The 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 inspect
17 17 import io
18 18 import os
19 19 import re
20 20 import sys
21 21 import ast
22 22 from itertools import chain
23 23 from urllib.request import Request, urlopen
24 24 from urllib.parse import urlencode
25 25 from pathlib import Path
26 26
27 27 # Our own packages
28 28 from IPython.core.error import TryNext, StdinNotImplementedError, UsageError
29 29 from IPython.core.macro import Macro
30 30 from IPython.core.magic import Magics, magics_class, line_magic
31 31 from IPython.core.oinspect import find_file, find_source_lines
32 32 from IPython.core.release import version
33 33 from IPython.testing.skipdoctest import skip_doctest
34 34 from IPython.utils.contexts import preserve_keys
35 35 from IPython.utils.path import get_py_filename
36 36 from warnings import warn
37 37 from logging import error
38 38 from IPython.utils.text import get_text_list
39 39
40 40 #-----------------------------------------------------------------------------
41 41 # Magic implementation classes
42 42 #-----------------------------------------------------------------------------
43 43
44 44 # Used for exception handling in magic_edit
45 45 class MacroToEdit(ValueError): pass
46 46
47 47 ipython_input_pat = re.compile(r"<ipython\-input\-(\d+)-[a-z\d]+>$")
48 48
49 49 # To match, e.g. 8-10 1:5 :10 3-
50 50 range_re = re.compile(r"""
51 51 (?P<start>\d+)?
52 52 ((?P<sep>[\-:])
53 53 (?P<end>\d+)?)?
54 54 $""", re.VERBOSE)
55 55
56 56
57 57 def extract_code_ranges(ranges_str):
58 58 """Turn a string of range for %%load into 2-tuples of (start, stop)
59 59 ready to use as a slice of the content split by lines.
60 60
61 61 Examples
62 62 --------
63 63 list(extract_input_ranges("5-10 2"))
64 64 [(4, 10), (1, 2)]
65 65 """
66 66 for range_str in ranges_str.split():
67 67 rmatch = range_re.match(range_str)
68 68 if not rmatch:
69 69 continue
70 70 sep = rmatch.group("sep")
71 71 start = rmatch.group("start")
72 72 end = rmatch.group("end")
73 73
74 74 if sep == '-':
75 75 start = int(start) - 1 if start else None
76 76 end = int(end) if end else None
77 77 elif sep == ':':
78 78 start = int(start) - 1 if start else None
79 79 end = int(end) - 1 if end else None
80 80 else:
81 81 end = int(start)
82 82 start = int(start) - 1
83 83 yield (start, end)
84 84
85 85
86 86 def extract_symbols(code, symbols):
87 87 """
88 88 Return a tuple (blocks, not_found)
89 89 where ``blocks`` is a list of code fragments
90 90 for each symbol parsed from code, and ``not_found`` are
91 91 symbols not found in the code.
92 92
93 93 For example::
94 94
95 95 In [1]: code = '''a = 10
96 96 ...: def b(): return 42
97 97 ...: class A: pass'''
98 98
99 99 In [2]: extract_symbols(code, 'A,b,z')
100 100 Out[2]: (['class A: pass\\n', 'def b(): return 42\\n'], ['z'])
101 101 """
102 102 symbols = symbols.split(',')
103 103
104 104 # this will raise SyntaxError if code isn't valid Python
105 105 py_code = ast.parse(code)
106 106
107 107 marks = [(getattr(s, 'name', None), s.lineno) for s in py_code.body]
108 108 code = code.split('\n')
109 109
110 110 symbols_lines = {}
111 111
112 112 # we already know the start_lineno of each symbol (marks).
113 113 # To find each end_lineno, we traverse in reverse order until each
114 114 # non-blank line
115 115 end = len(code)
116 116 for name, start in reversed(marks):
117 117 while not code[end - 1].strip():
118 118 end -= 1
119 119 if name:
120 120 symbols_lines[name] = (start - 1, end)
121 121 end = start - 1
122 122
123 123 # Now symbols_lines is a map
124 124 # {'symbol_name': (start_lineno, end_lineno), ...}
125 125
126 126 # fill a list with chunks of codes for each requested symbol
127 127 blocks = []
128 128 not_found = []
129 129 for symbol in symbols:
130 130 if symbol in symbols_lines:
131 131 start, end = symbols_lines[symbol]
132 132 blocks.append('\n'.join(code[start:end]) + '\n')
133 133 else:
134 134 not_found.append(symbol)
135 135
136 136 return blocks, not_found
137 137
138 138 def strip_initial_indent(lines):
139 139 """For %load, strip indent from lines until finding an unindented line.
140 140
141 141 https://github.com/ipython/ipython/issues/9775
142 142 """
143 143 indent_re = re.compile(r'\s+')
144 144
145 145 it = iter(lines)
146 146 first_line = next(it)
147 147 indent_match = indent_re.match(first_line)
148 148
149 149 if indent_match:
150 150 # First line was indented
151 151 indent = indent_match.group()
152 152 yield first_line[len(indent):]
153 153
154 154 for line in it:
155 155 if line.startswith(indent):
156 156 yield line[len(indent):]
157 157 else:
158 158 # Less indented than the first line - stop dedenting
159 159 yield line
160 160 break
161 161 else:
162 162 yield first_line
163 163
164 164 # Pass the remaining lines through without dedenting
165 165 for line in it:
166 166 yield line
167 167
168 168
169 169 class InteractivelyDefined(Exception):
170 170 """Exception for interactively defined variable in magic_edit"""
171 171 def __init__(self, index):
172 172 self.index = index
173 173
174 174
175 175 @magics_class
176 176 class CodeMagics(Magics):
177 177 """Magics related to code management (loading, saving, editing, ...)."""
178 178
179 179 def __init__(self, *args, **kwargs):
180 180 self._knowntemps = set()
181 181 super(CodeMagics, self).__init__(*args, **kwargs)
182 182
183 183 @line_magic
184 184 def save(self, parameter_s=''):
185 185 """Save a set of lines or a macro to a given filename.
186 186
187 187 Usage:\\
188 188 %save [options] filename n1-n2 n3-n4 ... n5 .. n6 ...
189 189
190 190 Options:
191 191
192 192 -r: use 'raw' input. By default, the 'processed' history is used,
193 193 so that magics are loaded in their transformed version to valid
194 194 Python. If this option is given, the raw input as typed as the
195 195 command line is used instead.
196 196
197 197 -f: force overwrite. If file exists, %save will prompt for overwrite
198 198 unless -f is given.
199 199
200 200 -a: append to the file instead of overwriting it.
201 201
202 202 This function uses the same syntax as %history for input ranges,
203 203 then saves the lines to the filename you specify.
204 204
205 205 It adds a '.py' extension to the file if you don't do so yourself, and
206 206 it asks for confirmation before overwriting existing files.
207 207
208 208 If `-r` option is used, the default extension is `.ipy`.
209 209 """
210 210
211 211 opts,args = self.parse_options(parameter_s,'fra',mode='list')
212 212 if not args:
213 213 raise UsageError('Missing filename.')
214 214 raw = 'r' in opts
215 215 force = 'f' in opts
216 216 append = 'a' in opts
217 217 mode = 'a' if append else 'w'
218 218 ext = '.ipy' if raw else '.py'
219 219 fname, codefrom = args[0], " ".join(args[1:])
220 220 if not fname.endswith(('.py','.ipy')):
221 221 fname += ext
222 222 file_exists = os.path.isfile(fname)
223 223 if file_exists and not force and not append:
224 224 try:
225 225 overwrite = self.shell.ask_yes_no('File `%s` exists. Overwrite (y/[N])? ' % fname, default='n')
226 226 except StdinNotImplementedError:
227 227 print("File `%s` exists. Use `%%save -f %s` to force overwrite" % (fname, parameter_s))
228 228 return
229 229 if not overwrite :
230 230 print('Operation cancelled.')
231 231 return
232 232 try:
233 233 cmds = self.shell.find_user_code(codefrom,raw)
234 234 except (TypeError, ValueError) as e:
235 235 print(e.args[0])
236 236 return
237 237 with io.open(fname, mode, encoding="utf-8") as f:
238 238 if not file_exists or not append:
239 239 f.write("# coding: utf-8\n")
240 240 f.write(cmds)
241 241 # make sure we end on a newline
242 242 if not cmds.endswith('\n'):
243 243 f.write('\n')
244 244 print('The following commands were written to file `%s`:' % fname)
245 245 print(cmds)
246 246
247 247 @line_magic
248 248 def pastebin(self, parameter_s=''):
249 249 """Upload code to dpaste.com, returning the URL.
250 250
251 251 Usage:\\
252 %pastebin [-d "Custom description"] 1-7
252 %pastebin [-d "Custom description"][-e 24] 1-7
253 253
254 254 The argument can be an input history range, a filename, or the name of a
255 255 string or macro.
256 256
257 257 Options:
258 258
259 259 -d: Pass a custom description. The default will say
260 260 "Pasted from IPython".
261 -e: Pass number of days for the link to be expired.
262 The default will be 7 days.
261 263 """
262 opts, args = self.parse_options(parameter_s, 'd:')
264 opts, args = self.parse_options(parameter_s, "d:e:")
263 265
264 266 try:
265 267 code = self.shell.find_user_code(args)
266 268 except (ValueError, TypeError) as e:
267 269 print(e.args[0])
268 270 return
269 271
272 expiry_days = 7
273 try:
274 expiry_days = int(opts.get("e", 7))
275 except ValueError as e:
276 print(e.args[0].capitalize())
277 return
278 if expiry_days < 1 or expiry_days > 365:
279 print("Expiry days should be in range of 1 to 365")
280 return
281
270 282 post_data = urlencode(
271 283 {
272 284 "title": opts.get("d", "Pasted from IPython"),
273 285 "syntax": "python",
274 286 "content": code,
287 "expiry_days": expiry_days,
275 288 }
276 289 ).encode("utf-8")
277 290
278 291 request = Request(
279 "http://dpaste.com/api/v2/",
292 "https://dpaste.com/api/v2/",
280 293 headers={"User-Agent": "IPython v{}".format(version)},
281 294 )
282 295 response = urlopen(request, post_data)
283 296 return response.headers.get('Location')
284 297
285 298 @line_magic
286 299 def loadpy(self, arg_s):
287 300 """Alias of `%load`
288 301
289 302 `%loadpy` has gained some flexibility and dropped the requirement of a `.py`
290 303 extension. So it has been renamed simply into %load. You can look at
291 304 `%load`'s docstring for more info.
292 305 """
293 306 self.load(arg_s)
294 307
295 308 @line_magic
296 309 def load(self, arg_s):
297 310 """Load code into the current frontend.
298 311
299 312 Usage:\\
300 313 %load [options] source
301 314
302 315 where source can be a filename, URL, input history range, macro, or
303 316 element in the user namespace
304 317
305 318 Options:
306 319
307 320 -r <lines>: Specify lines or ranges of lines to load from the source.
308 321 Ranges could be specified as x-y (x..y) or in python-style x:y
309 322 (x..(y-1)). Both limits x and y can be left blank (meaning the
310 323 beginning and end of the file, respectively).
311 324
312 325 -s <symbols>: Specify function or classes to load from python source.
313 326
314 327 -y : Don't ask confirmation for loading source above 200 000 characters.
315 328
316 329 -n : Include the user's namespace when searching for source code.
317 330
318 331 This magic command can either take a local filename, a URL, an history
319 332 range (see %history) or a macro as argument, it will prompt for
320 333 confirmation before loading source with more than 200 000 characters, unless
321 334 -y flag is passed or if the frontend does not support raw_input::
322 335
323 336 %load myscript.py
324 337 %load 7-27
325 338 %load myMacro
326 339 %load http://www.example.com/myscript.py
327 340 %load -r 5-10 myscript.py
328 341 %load -r 10-20,30,40: foo.py
329 342 %load -s MyClass,wonder_function myscript.py
330 343 %load -n MyClass
331 344 %load -n my_module.wonder_function
332 345 """
333 346 opts,args = self.parse_options(arg_s,'yns:r:')
334 347
335 348 if not args:
336 349 raise UsageError('Missing filename, URL, input history range, '
337 350 'macro, or element in the user namespace.')
338 351
339 352 search_ns = 'n' in opts
340 353
341 354 contents = self.shell.find_user_code(args, search_ns=search_ns)
342 355
343 356 if 's' in opts:
344 357 try:
345 358 blocks, not_found = extract_symbols(contents, opts['s'])
346 359 except SyntaxError:
347 360 # non python code
348 361 error("Unable to parse the input as valid Python code")
349 362 return
350 363
351 364 if len(not_found) == 1:
352 365 warn('The symbol `%s` was not found' % not_found[0])
353 366 elif len(not_found) > 1:
354 367 warn('The symbols %s were not found' % get_text_list(not_found,
355 368 wrap_item_with='`')
356 369 )
357 370
358 371 contents = '\n'.join(blocks)
359 372
360 373 if 'r' in opts:
361 374 ranges = opts['r'].replace(',', ' ')
362 375 lines = contents.split('\n')
363 376 slices = extract_code_ranges(ranges)
364 377 contents = [lines[slice(*slc)] for slc in slices]
365 378 contents = '\n'.join(strip_initial_indent(chain.from_iterable(contents)))
366 379
367 380 l = len(contents)
368 381
369 382 # 200 000 is ~ 2500 full 80 character lines
370 383 # so in average, more than 5000 lines
371 384 if l > 200000 and 'y' not in opts:
372 385 try:
373 386 ans = self.shell.ask_yes_no(("The text you're trying to load seems pretty big"\
374 387 " (%d characters). Continue (y/[N]) ?" % l), default='n' )
375 388 except StdinNotImplementedError:
376 389 #assume yes if raw input not implemented
377 390 ans = True
378 391
379 392 if ans is False :
380 393 print('Operation cancelled.')
381 394 return
382 395
383 396 contents = "# %load {}\n".format(arg_s) + contents
384 397
385 398 self.shell.set_next_input(contents, replace=True)
386 399
387 400 @staticmethod
388 401 def _find_edit_target(shell, args, opts, last_call):
389 402 """Utility method used by magic_edit to find what to edit."""
390 403
391 404 def make_filename(arg):
392 405 "Make a filename from the given args"
393 406 try:
394 407 filename = get_py_filename(arg)
395 408 except IOError:
396 409 # If it ends with .py but doesn't already exist, assume we want
397 410 # a new file.
398 411 if arg.endswith('.py'):
399 412 filename = arg
400 413 else:
401 414 filename = None
402 415 return filename
403 416
404 417 # Set a few locals from the options for convenience:
405 418 opts_prev = 'p' in opts
406 419 opts_raw = 'r' in opts
407 420
408 421 # custom exceptions
409 422 class DataIsObject(Exception): pass
410 423
411 424 # Default line number value
412 425 lineno = opts.get('n',None)
413 426
414 427 if opts_prev:
415 428 args = '_%s' % last_call[0]
416 429 if args not in shell.user_ns:
417 430 args = last_call[1]
418 431
419 432 # by default this is done with temp files, except when the given
420 433 # arg is a filename
421 434 use_temp = True
422 435
423 436 data = ''
424 437
425 438 # First, see if the arguments should be a filename.
426 439 filename = make_filename(args)
427 440 if filename:
428 441 use_temp = False
429 442 elif args:
430 443 # Mode where user specifies ranges of lines, like in %macro.
431 444 data = shell.extract_input_lines(args, opts_raw)
432 445 if not data:
433 446 try:
434 447 # Load the parameter given as a variable. If not a string,
435 448 # process it as an object instead (below)
436 449
437 450 #print '*** args',args,'type',type(args) # dbg
438 451 data = eval(args, shell.user_ns)
439 452 if not isinstance(data, str):
440 453 raise DataIsObject
441 454
442 455 except (NameError,SyntaxError):
443 456 # given argument is not a variable, try as a filename
444 457 filename = make_filename(args)
445 458 if filename is None:
446 459 warn("Argument given (%s) can't be found as a variable "
447 460 "or as a filename." % args)
448 461 return (None, None, None)
449 462 use_temp = False
450 463
451 464 except DataIsObject as e:
452 465 # macros have a special edit function
453 466 if isinstance(data, Macro):
454 467 raise MacroToEdit(data) from e
455 468
456 469 # For objects, try to edit the file where they are defined
457 470 filename = find_file(data)
458 471 if filename:
459 472 if 'fakemodule' in filename.lower() and \
460 473 inspect.isclass(data):
461 474 # class created by %edit? Try to find source
462 475 # by looking for method definitions instead, the
463 476 # __module__ in those classes is FakeModule.
464 477 attrs = [getattr(data, aname) for aname in dir(data)]
465 478 for attr in attrs:
466 479 if not inspect.ismethod(attr):
467 480 continue
468 481 filename = find_file(attr)
469 482 if filename and \
470 483 'fakemodule' not in filename.lower():
471 484 # change the attribute to be the edit
472 485 # target instead
473 486 data = attr
474 487 break
475 488
476 489 m = ipython_input_pat.match(os.path.basename(filename))
477 490 if m:
478 491 raise InteractivelyDefined(int(m.groups()[0])) from e
479 492
480 493 datafile = 1
481 494 if filename is None:
482 495 filename = make_filename(args)
483 496 datafile = 1
484 497 if filename is not None:
485 498 # only warn about this if we get a real name
486 499 warn('Could not find file where `%s` is defined.\n'
487 500 'Opening a file named `%s`' % (args, filename))
488 501 # Now, make sure we can actually read the source (if it was
489 502 # in a temp file it's gone by now).
490 503 if datafile:
491 504 if lineno is None:
492 505 lineno = find_source_lines(data)
493 506 if lineno is None:
494 507 filename = make_filename(args)
495 508 if filename is None:
496 509 warn('The file where `%s` was defined '
497 510 'cannot be read or found.' % data)
498 511 return (None, None, None)
499 512 use_temp = False
500 513
501 514 if use_temp:
502 515 filename = shell.mktempfile(data)
503 516 print('IPython will make a temporary file named:',filename)
504 517
505 518 # use last_call to remember the state of the previous call, but don't
506 519 # let it be clobbered by successive '-p' calls.
507 520 try:
508 521 last_call[0] = shell.displayhook.prompt_count
509 522 if not opts_prev:
510 523 last_call[1] = args
511 524 except:
512 525 pass
513 526
514 527
515 528 return filename, lineno, use_temp
516 529
517 530 def _edit_macro(self,mname,macro):
518 531 """open an editor with the macro data in a file"""
519 532 filename = self.shell.mktempfile(macro.value)
520 533 self.shell.hooks.editor(filename)
521 534
522 535 # and make a new macro object, to replace the old one
523 536 mvalue = Path(filename).read_text()
524 537 self.shell.user_ns[mname] = Macro(mvalue)
525 538
526 539 @skip_doctest
527 540 @line_magic
528 541 def edit(self, parameter_s='',last_call=['','']):
529 542 """Bring up an editor and execute the resulting code.
530 543
531 544 Usage:
532 545 %edit [options] [args]
533 546
534 547 %edit runs IPython's editor hook. The default version of this hook is
535 548 set to call the editor specified by your $EDITOR environment variable.
536 549 If this isn't found, it will default to vi under Linux/Unix and to
537 550 notepad under Windows. See the end of this docstring for how to change
538 551 the editor hook.
539 552
540 553 You can also set the value of this editor via the
541 554 ``TerminalInteractiveShell.editor`` option in your configuration file.
542 555 This is useful if you wish to use a different editor from your typical
543 556 default with IPython (and for Windows users who typically don't set
544 557 environment variables).
545 558
546 559 This command allows you to conveniently edit multi-line code right in
547 560 your IPython session.
548 561
549 562 If called without arguments, %edit opens up an empty editor with a
550 563 temporary file and will execute the contents of this file when you
551 564 close it (don't forget to save it!).
552 565
553 566
554 567 Options:
555 568
556 569 -n <number>: open the editor at a specified line number. By default,
557 570 the IPython editor hook uses the unix syntax 'editor +N filename', but
558 571 you can configure this by providing your own modified hook if your
559 572 favorite editor supports line-number specifications with a different
560 573 syntax.
561 574
562 575 -p: this will call the editor with the same data as the previous time
563 576 it was used, regardless of how long ago (in your current session) it
564 577 was.
565 578
566 579 -r: use 'raw' input. This option only applies to input taken from the
567 580 user's history. By default, the 'processed' history is used, so that
568 581 magics are loaded in their transformed version to valid Python. If
569 582 this option is given, the raw input as typed as the command line is
570 583 used instead. When you exit the editor, it will be executed by
571 584 IPython's own processor.
572 585
573 586 -x: do not execute the edited code immediately upon exit. This is
574 587 mainly useful if you are editing programs which need to be called with
575 588 command line arguments, which you can then do using %run.
576 589
577 590
578 591 Arguments:
579 592
580 593 If arguments are given, the following possibilities exist:
581 594
582 595 - If the argument is a filename, IPython will load that into the
583 596 editor. It will execute its contents with execfile() when you exit,
584 597 loading any code in the file into your interactive namespace.
585 598
586 599 - The arguments are ranges of input history, e.g. "7 ~1/4-6".
587 600 The syntax is the same as in the %history magic.
588 601
589 602 - If the argument is a string variable, its contents are loaded
590 603 into the editor. You can thus edit any string which contains
591 604 python code (including the result of previous edits).
592 605
593 606 - If the argument is the name of an object (other than a string),
594 607 IPython will try to locate the file where it was defined and open the
595 608 editor at the point where it is defined. You can use `%edit function`
596 609 to load an editor exactly at the point where 'function' is defined,
597 610 edit it and have the file be executed automatically.
598 611
599 612 - If the object is a macro (see %macro for details), this opens up your
600 613 specified editor with a temporary file containing the macro's data.
601 614 Upon exit, the macro is reloaded with the contents of the file.
602 615
603 616 Note: opening at an exact line is only supported under Unix, and some
604 617 editors (like kedit and gedit up to Gnome 2.8) do not understand the
605 618 '+NUMBER' parameter necessary for this feature. Good editors like
606 619 (X)Emacs, vi, jed, pico and joe all do.
607 620
608 621 After executing your code, %edit will return as output the code you
609 622 typed in the editor (except when it was an existing file). This way
610 623 you can reload the code in further invocations of %edit as a variable,
611 624 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
612 625 the output.
613 626
614 627 Note that %edit is also available through the alias %ed.
615 628
616 629 This is an example of creating a simple function inside the editor and
617 630 then modifying it. First, start up the editor::
618 631
619 632 In [1]: edit
620 633 Editing... done. Executing edited code...
621 634 Out[1]: 'def foo():\\n print "foo() was defined in an editing
622 635 session"\\n'
623 636
624 637 We can then call the function foo()::
625 638
626 639 In [2]: foo()
627 640 foo() was defined in an editing session
628 641
629 642 Now we edit foo. IPython automatically loads the editor with the
630 643 (temporary) file where foo() was previously defined::
631 644
632 645 In [3]: edit foo
633 646 Editing... done. Executing edited code...
634 647
635 648 And if we call foo() again we get the modified version::
636 649
637 650 In [4]: foo()
638 651 foo() has now been changed!
639 652
640 653 Here is an example of how to edit a code snippet successive
641 654 times. First we call the editor::
642 655
643 656 In [5]: edit
644 657 Editing... done. Executing edited code...
645 658 hello
646 659 Out[5]: "print 'hello'\\n"
647 660
648 661 Now we call it again with the previous output (stored in _)::
649 662
650 663 In [6]: edit _
651 664 Editing... done. Executing edited code...
652 665 hello world
653 666 Out[6]: "print 'hello world'\\n"
654 667
655 668 Now we call it with the output #8 (stored in _8, also as Out[8])::
656 669
657 670 In [7]: edit _8
658 671 Editing... done. Executing edited code...
659 672 hello again
660 673 Out[7]: "print 'hello again'\\n"
661 674
662 675
663 676 Changing the default editor hook:
664 677
665 678 If you wish to write your own editor hook, you can put it in a
666 679 configuration file which you load at startup time. The default hook
667 680 is defined in the IPython.core.hooks module, and you can use that as a
668 681 starting example for further modifications. That file also has
669 682 general instructions on how to set a new hook for use once you've
670 683 defined it."""
671 684 opts,args = self.parse_options(parameter_s,'prxn:')
672 685
673 686 try:
674 687 filename, lineno, is_temp = self._find_edit_target(self.shell,
675 688 args, opts, last_call)
676 689 except MacroToEdit as e:
677 690 self._edit_macro(args, e.args[0])
678 691 return
679 692 except InteractivelyDefined as e:
680 693 print("Editing In[%i]" % e.index)
681 694 args = str(e.index)
682 695 filename, lineno, is_temp = self._find_edit_target(self.shell,
683 696 args, opts, last_call)
684 697 if filename is None:
685 698 # nothing was found, warnings have already been issued,
686 699 # just give up.
687 700 return
688 701
689 702 if is_temp:
690 703 self._knowntemps.add(filename)
691 704 elif (filename in self._knowntemps):
692 705 is_temp = True
693 706
694 707
695 708 # do actual editing here
696 709 print('Editing...', end=' ')
697 710 sys.stdout.flush()
698 711 filepath = Path(filename)
699 712 try:
700 713 # Quote filenames that may have spaces in them when opening
701 714 # the editor
702 715 quoted = filename = str(filepath.absolute())
703 716 if " " in quoted:
704 717 quoted = "'%s'" % quoted
705 718 self.shell.hooks.editor(quoted, lineno)
706 719 except TryNext:
707 720 warn('Could not open editor')
708 721 return
709 722
710 723 # XXX TODO: should this be generalized for all string vars?
711 724 # For now, this is special-cased to blocks created by cpaste
712 725 if args.strip() == "pasted_block":
713 726 self.shell.user_ns["pasted_block"] = filepath.read_text()
714 727
715 728 if 'x' in opts: # -x prevents actual execution
716 729 print()
717 730 else:
718 731 print('done. Executing edited code...')
719 732 with preserve_keys(self.shell.user_ns, '__file__'):
720 733 if not is_temp:
721 734 self.shell.user_ns['__file__'] = filename
722 735 if 'r' in opts: # Untranslated IPython code
723 736 source = filepath.read_text()
724 737 self.shell.run_cell(source, store_history=False)
725 738 else:
726 739 self.shell.safe_execfile(filename, self.shell.user_ns,
727 740 self.shell.user_ns)
728 741
729 742 if is_temp:
730 743 try:
731 744 return filepath.read_text()
732 745 except IOError as msg:
733 746 if Path(msg.filename) == filepath:
734 747 warn('File not found. Did you forget to save?')
735 748 return
736 749 else:
737 750 self.shell.showtraceback()
General Comments 0
You need to be logged in to leave comments. Login now