##// END OF EJS Templates
Backport PR #13056: add expiry days option to pastebin magic and change http protocol to https
Blazej Michalik -
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
26 26 # Our own packages
27 27 from IPython.core.error import TryNext, StdinNotImplementedError, UsageError
28 28 from IPython.core.macro import Macro
29 29 from IPython.core.magic import Magics, magics_class, line_magic
30 30 from IPython.core.oinspect import find_file, find_source_lines
31 31 from IPython.core.release import version
32 32 from IPython.testing.skipdoctest import skip_doctest
33 33 from IPython.utils.contexts import preserve_keys
34 34 from IPython.utils.path import get_py_filename
35 35 from warnings import warn
36 36 from logging import error
37 37 from IPython.utils.text import get_text_list
38 38
39 39 #-----------------------------------------------------------------------------
40 40 # Magic implementation classes
41 41 #-----------------------------------------------------------------------------
42 42
43 43 # Used for exception handling in magic_edit
44 44 class MacroToEdit(ValueError): pass
45 45
46 46 ipython_input_pat = re.compile(r"<ipython\-input\-(\d+)-[a-z\d]+>$")
47 47
48 48 # To match, e.g. 8-10 1:5 :10 3-
49 49 range_re = re.compile(r"""
50 50 (?P<start>\d+)?
51 51 ((?P<sep>[\-:])
52 52 (?P<end>\d+)?)?
53 53 $""", re.VERBOSE)
54 54
55 55
56 56 def extract_code_ranges(ranges_str):
57 57 """Turn a string of range for %%load into 2-tuples of (start, stop)
58 58 ready to use as a slice of the content split by lines.
59 59
60 60 Examples
61 61 --------
62 62 list(extract_input_ranges("5-10 2"))
63 63 [(4, 10), (1, 2)]
64 64 """
65 65 for range_str in ranges_str.split():
66 66 rmatch = range_re.match(range_str)
67 67 if not rmatch:
68 68 continue
69 69 sep = rmatch.group("sep")
70 70 start = rmatch.group("start")
71 71 end = rmatch.group("end")
72 72
73 73 if sep == '-':
74 74 start = int(start) - 1 if start else None
75 75 end = int(end) if end else None
76 76 elif sep == ':':
77 77 start = int(start) - 1 if start else None
78 78 end = int(end) - 1 if end else None
79 79 else:
80 80 end = int(start)
81 81 start = int(start) - 1
82 82 yield (start, end)
83 83
84 84
85 85 def extract_symbols(code, symbols):
86 86 """
87 87 Return a tuple (blocks, not_found)
88 88 where ``blocks`` is a list of code fragments
89 89 for each symbol parsed from code, and ``not_found`` are
90 90 symbols not found in the code.
91 91
92 92 For example::
93 93
94 94 In [1]: code = '''a = 10
95 95 ...: def b(): return 42
96 96 ...: class A: pass'''
97 97
98 98 In [2]: extract_symbols(code, 'A,b,z')
99 99 Out[2]: (['class A: pass\\n', 'def b(): return 42\\n'], ['z'])
100 100 """
101 101 symbols = symbols.split(',')
102 102
103 103 # this will raise SyntaxError if code isn't valid Python
104 104 py_code = ast.parse(code)
105 105
106 106 marks = [(getattr(s, 'name', None), s.lineno) for s in py_code.body]
107 107 code = code.split('\n')
108 108
109 109 symbols_lines = {}
110 110
111 111 # we already know the start_lineno of each symbol (marks).
112 112 # To find each end_lineno, we traverse in reverse order until each
113 113 # non-blank line
114 114 end = len(code)
115 115 for name, start in reversed(marks):
116 116 while not code[end - 1].strip():
117 117 end -= 1
118 118 if name:
119 119 symbols_lines[name] = (start - 1, end)
120 120 end = start - 1
121 121
122 122 # Now symbols_lines is a map
123 123 # {'symbol_name': (start_lineno, end_lineno), ...}
124 124
125 125 # fill a list with chunks of codes for each requested symbol
126 126 blocks = []
127 127 not_found = []
128 128 for symbol in symbols:
129 129 if symbol in symbols_lines:
130 130 start, end = symbols_lines[symbol]
131 131 blocks.append('\n'.join(code[start:end]) + '\n')
132 132 else:
133 133 not_found.append(symbol)
134 134
135 135 return blocks, not_found
136 136
137 137 def strip_initial_indent(lines):
138 138 """For %load, strip indent from lines until finding an unindented line.
139 139
140 140 https://github.com/ipython/ipython/issues/9775
141 141 """
142 142 indent_re = re.compile(r'\s+')
143 143
144 144 it = iter(lines)
145 145 first_line = next(it)
146 146 indent_match = indent_re.match(first_line)
147 147
148 148 if indent_match:
149 149 # First line was indented
150 150 indent = indent_match.group()
151 151 yield first_line[len(indent):]
152 152
153 153 for line in it:
154 154 if line.startswith(indent):
155 155 yield line[len(indent):]
156 156 else:
157 157 # Less indented than the first line - stop dedenting
158 158 yield line
159 159 break
160 160 else:
161 161 yield first_line
162 162
163 163 # Pass the remaining lines through without dedenting
164 164 for line in it:
165 165 yield line
166 166
167 167
168 168 class InteractivelyDefined(Exception):
169 169 """Exception for interactively defined variable in magic_edit"""
170 170 def __init__(self, index):
171 171 self.index = index
172 172
173 173
174 174 @magics_class
175 175 class CodeMagics(Magics):
176 176 """Magics related to code management (loading, saving, editing, ...)."""
177 177
178 178 def __init__(self, *args, **kwargs):
179 179 self._knowntemps = set()
180 180 super(CodeMagics, self).__init__(*args, **kwargs)
181 181
182 182 @line_magic
183 183 def save(self, parameter_s=''):
184 184 """Save a set of lines or a macro to a given filename.
185 185
186 186 Usage:\\
187 187 %save [options] filename n1-n2 n3-n4 ... n5 .. n6 ...
188 188
189 189 Options:
190 190
191 191 -r: use 'raw' input. By default, the 'processed' history is used,
192 192 so that magics are loaded in their transformed version to valid
193 193 Python. If this option is given, the raw input as typed as the
194 194 command line is used instead.
195 195
196 196 -f: force overwrite. If file exists, %save will prompt for overwrite
197 197 unless -f is given.
198 198
199 199 -a: append to the file instead of overwriting it.
200 200
201 201 This function uses the same syntax as %history for input ranges,
202 202 then saves the lines to the filename you specify.
203 203
204 204 It adds a '.py' extension to the file if you don't do so yourself, and
205 205 it asks for confirmation before overwriting existing files.
206 206
207 207 If `-r` option is used, the default extension is `.ipy`.
208 208 """
209 209
210 210 opts,args = self.parse_options(parameter_s,'fra',mode='list')
211 211 if not args:
212 212 raise UsageError('Missing filename.')
213 213 raw = 'r' in opts
214 214 force = 'f' in opts
215 215 append = 'a' in opts
216 216 mode = 'a' if append else 'w'
217 217 ext = '.ipy' if raw else '.py'
218 218 fname, codefrom = args[0], " ".join(args[1:])
219 219 if not fname.endswith(('.py','.ipy')):
220 220 fname += ext
221 221 file_exists = os.path.isfile(fname)
222 222 if file_exists and not force and not append:
223 223 try:
224 224 overwrite = self.shell.ask_yes_no('File `%s` exists. Overwrite (y/[N])? ' % fname, default='n')
225 225 except StdinNotImplementedError:
226 226 print("File `%s` exists. Use `%%save -f %s` to force overwrite" % (fname, parameter_s))
227 227 return
228 228 if not overwrite :
229 229 print('Operation cancelled.')
230 230 return
231 231 try:
232 232 cmds = self.shell.find_user_code(codefrom,raw)
233 233 except (TypeError, ValueError) as e:
234 234 print(e.args[0])
235 235 return
236 236 with io.open(fname, mode, encoding="utf-8") as f:
237 237 if not file_exists or not append:
238 238 f.write("# coding: utf-8\n")
239 239 f.write(cmds)
240 240 # make sure we end on a newline
241 241 if not cmds.endswith('\n'):
242 242 f.write('\n')
243 243 print('The following commands were written to file `%s`:' % fname)
244 244 print(cmds)
245 245
246 246 @line_magic
247 247 def pastebin(self, parameter_s=''):
248 248 """Upload code to dpaste.com, returning the URL.
249 249
250 250 Usage:\\
251 %pastebin [-d "Custom description"] 1-7
251 %pastebin [-d "Custom description"][-e 24] 1-7
252 252
253 253 The argument can be an input history range, a filename, or the name of a
254 254 string or macro.
255 255
256 256 Options:
257 257
258 258 -d: Pass a custom description. The default will say
259 259 "Pasted from IPython".
260 -e: Pass number of days for the link to be expired.
261 The default will be 7 days.
260 262 """
261 opts, args = self.parse_options(parameter_s, 'd:')
263 opts, args = self.parse_options(parameter_s, "d:e:")
262 264
263 265 try:
264 266 code = self.shell.find_user_code(args)
265 267 except (ValueError, TypeError) as e:
266 268 print(e.args[0])
267 269 return
268 270
271 expiry_days = 7
272 try:
273 expiry_days = int(opts.get("e", 7))
274 except ValueError as e:
275 print(e.args[0].capitalize())
276 return
277 if expiry_days < 1 or expiry_days > 365:
278 print("Expiry days should be in range of 1 to 365")
279 return
280
269 281 post_data = urlencode(
270 282 {
271 283 "title": opts.get("d", "Pasted from IPython"),
272 284 "syntax": "python",
273 285 "content": code,
286 "expiry_days": expiry_days,
274 287 }
275 288 ).encode("utf-8")
276 289
277 290 request = Request(
278 "http://dpaste.com/api/v2/",
291 "https://dpaste.com/api/v2/",
279 292 headers={"User-Agent": "IPython v{}".format(version)},
280 293 )
281 294 response = urlopen(request, post_data)
282 295 return response.headers.get('Location')
283 296
284 297 @line_magic
285 298 def loadpy(self, arg_s):
286 299 """Alias of `%load`
287 300
288 301 `%loadpy` has gained some flexibility and dropped the requirement of a `.py`
289 302 extension. So it has been renamed simply into %load. You can look at
290 303 `%load`'s docstring for more info.
291 304 """
292 305 self.load(arg_s)
293 306
294 307 @line_magic
295 308 def load(self, arg_s):
296 309 """Load code into the current frontend.
297 310
298 311 Usage:\\
299 312 %load [options] source
300 313
301 314 where source can be a filename, URL, input history range, macro, or
302 315 element in the user namespace
303 316
304 317 Options:
305 318
306 319 -r <lines>: Specify lines or ranges of lines to load from the source.
307 320 Ranges could be specified as x-y (x..y) or in python-style x:y
308 321 (x..(y-1)). Both limits x and y can be left blank (meaning the
309 322 beginning and end of the file, respectively).
310 323
311 324 -s <symbols>: Specify function or classes to load from python source.
312 325
313 326 -y : Don't ask confirmation for loading source above 200 000 characters.
314 327
315 328 -n : Include the user's namespace when searching for source code.
316 329
317 330 This magic command can either take a local filename, a URL, an history
318 331 range (see %history) or a macro as argument, it will prompt for
319 332 confirmation before loading source with more than 200 000 characters, unless
320 333 -y flag is passed or if the frontend does not support raw_input::
321 334
322 335 %load myscript.py
323 336 %load 7-27
324 337 %load myMacro
325 338 %load http://www.example.com/myscript.py
326 339 %load -r 5-10 myscript.py
327 340 %load -r 10-20,30,40: foo.py
328 341 %load -s MyClass,wonder_function myscript.py
329 342 %load -n MyClass
330 343 %load -n my_module.wonder_function
331 344 """
332 345 opts,args = self.parse_options(arg_s,'yns:r:')
333 346
334 347 if not args:
335 348 raise UsageError('Missing filename, URL, input history range, '
336 349 'macro, or element in the user namespace.')
337 350
338 351 search_ns = 'n' in opts
339 352
340 353 contents = self.shell.find_user_code(args, search_ns=search_ns)
341 354
342 355 if 's' in opts:
343 356 try:
344 357 blocks, not_found = extract_symbols(contents, opts['s'])
345 358 except SyntaxError:
346 359 # non python code
347 360 error("Unable to parse the input as valid Python code")
348 361 return
349 362
350 363 if len(not_found) == 1:
351 364 warn('The symbol `%s` was not found' % not_found[0])
352 365 elif len(not_found) > 1:
353 366 warn('The symbols %s were not found' % get_text_list(not_found,
354 367 wrap_item_with='`')
355 368 )
356 369
357 370 contents = '\n'.join(blocks)
358 371
359 372 if 'r' in opts:
360 373 ranges = opts['r'].replace(',', ' ')
361 374 lines = contents.split('\n')
362 375 slices = extract_code_ranges(ranges)
363 376 contents = [lines[slice(*slc)] for slc in slices]
364 377 contents = '\n'.join(strip_initial_indent(chain.from_iterable(contents)))
365 378
366 379 l = len(contents)
367 380
368 381 # 200 000 is ~ 2500 full 80 character lines
369 382 # so in average, more than 5000 lines
370 383 if l > 200000 and 'y' not in opts:
371 384 try:
372 385 ans = self.shell.ask_yes_no(("The text you're trying to load seems pretty big"\
373 386 " (%d characters). Continue (y/[N]) ?" % l), default='n' )
374 387 except StdinNotImplementedError:
375 388 #assume yes if raw input not implemented
376 389 ans = True
377 390
378 391 if ans is False :
379 392 print('Operation cancelled.')
380 393 return
381 394
382 395 contents = "# %load {}\n".format(arg_s) + contents
383 396
384 397 self.shell.set_next_input(contents, replace=True)
385 398
386 399 @staticmethod
387 400 def _find_edit_target(shell, args, opts, last_call):
388 401 """Utility method used by magic_edit to find what to edit."""
389 402
390 403 def make_filename(arg):
391 404 "Make a filename from the given args"
392 405 try:
393 406 filename = get_py_filename(arg)
394 407 except IOError:
395 408 # If it ends with .py but doesn't already exist, assume we want
396 409 # a new file.
397 410 if arg.endswith('.py'):
398 411 filename = arg
399 412 else:
400 413 filename = None
401 414 return filename
402 415
403 416 # Set a few locals from the options for convenience:
404 417 opts_prev = 'p' in opts
405 418 opts_raw = 'r' in opts
406 419
407 420 # custom exceptions
408 421 class DataIsObject(Exception): pass
409 422
410 423 # Default line number value
411 424 lineno = opts.get('n',None)
412 425
413 426 if opts_prev:
414 427 args = '_%s' % last_call[0]
415 428 if args not in shell.user_ns:
416 429 args = last_call[1]
417 430
418 431 # by default this is done with temp files, except when the given
419 432 # arg is a filename
420 433 use_temp = True
421 434
422 435 data = ''
423 436
424 437 # First, see if the arguments should be a filename.
425 438 filename = make_filename(args)
426 439 if filename:
427 440 use_temp = False
428 441 elif args:
429 442 # Mode where user specifies ranges of lines, like in %macro.
430 443 data = shell.extract_input_lines(args, opts_raw)
431 444 if not data:
432 445 try:
433 446 # Load the parameter given as a variable. If not a string,
434 447 # process it as an object instead (below)
435 448
436 449 #print '*** args',args,'type',type(args) # dbg
437 450 data = eval(args, shell.user_ns)
438 451 if not isinstance(data, str):
439 452 raise DataIsObject
440 453
441 454 except (NameError,SyntaxError):
442 455 # given argument is not a variable, try as a filename
443 456 filename = make_filename(args)
444 457 if filename is None:
445 458 warn("Argument given (%s) can't be found as a variable "
446 459 "or as a filename." % args)
447 460 return (None, None, None)
448 461 use_temp = False
449 462
450 463 except DataIsObject:
451 464 # macros have a special edit function
452 465 if isinstance(data, Macro):
453 466 raise MacroToEdit(data)
454 467
455 468 # For objects, try to edit the file where they are defined
456 469 filename = find_file(data)
457 470 if filename:
458 471 if 'fakemodule' in filename.lower() and \
459 472 inspect.isclass(data):
460 473 # class created by %edit? Try to find source
461 474 # by looking for method definitions instead, the
462 475 # __module__ in those classes is FakeModule.
463 476 attrs = [getattr(data, aname) for aname in dir(data)]
464 477 for attr in attrs:
465 478 if not inspect.ismethod(attr):
466 479 continue
467 480 filename = find_file(attr)
468 481 if filename and \
469 482 'fakemodule' not in filename.lower():
470 483 # change the attribute to be the edit
471 484 # target instead
472 485 data = attr
473 486 break
474 487
475 488 m = ipython_input_pat.match(os.path.basename(filename))
476 489 if m:
477 490 raise InteractivelyDefined(int(m.groups()[0]))
478 491
479 492 datafile = 1
480 493 if filename is None:
481 494 filename = make_filename(args)
482 495 datafile = 1
483 496 if filename is not None:
484 497 # only warn about this if we get a real name
485 498 warn('Could not find file where `%s` is defined.\n'
486 499 'Opening a file named `%s`' % (args, filename))
487 500 # Now, make sure we can actually read the source (if it was
488 501 # in a temp file it's gone by now).
489 502 if datafile:
490 503 if lineno is None:
491 504 lineno = find_source_lines(data)
492 505 if lineno is None:
493 506 filename = make_filename(args)
494 507 if filename is None:
495 508 warn('The file where `%s` was defined '
496 509 'cannot be read or found.' % data)
497 510 return (None, None, None)
498 511 use_temp = False
499 512
500 513 if use_temp:
501 514 filename = shell.mktempfile(data)
502 515 print('IPython will make a temporary file named:',filename)
503 516
504 517 # use last_call to remember the state of the previous call, but don't
505 518 # let it be clobbered by successive '-p' calls.
506 519 try:
507 520 last_call[0] = shell.displayhook.prompt_count
508 521 if not opts_prev:
509 522 last_call[1] = args
510 523 except:
511 524 pass
512 525
513 526
514 527 return filename, lineno, use_temp
515 528
516 529 def _edit_macro(self,mname,macro):
517 530 """open an editor with the macro data in a file"""
518 531 filename = self.shell.mktempfile(macro.value)
519 532 self.shell.hooks.editor(filename)
520 533
521 534 # and make a new macro object, to replace the old one
522 535 with open(filename) as mfile:
523 536 mvalue = mfile.read()
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 try:
699 712 # Quote filenames that may have spaces in them
700 713 if ' ' in filename:
701 714 filename = "'%s'" % filename
702 715 self.shell.hooks.editor(filename,lineno)
703 716 except TryNext:
704 717 warn('Could not open editor')
705 718 return
706 719
707 720 # XXX TODO: should this be generalized for all string vars?
708 721 # For now, this is special-cased to blocks created by cpaste
709 722 if args.strip() == 'pasted_block':
710 723 with open(filename, 'r') as f:
711 724 self.shell.user_ns['pasted_block'] = f.read()
712 725
713 726 if 'x' in opts: # -x prevents actual execution
714 727 print()
715 728 else:
716 729 print('done. Executing edited code...')
717 730 with preserve_keys(self.shell.user_ns, '__file__'):
718 731 if not is_temp:
719 732 self.shell.user_ns['__file__'] = filename
720 733 if 'r' in opts: # Untranslated IPython code
721 734 with open(filename, 'r') as f:
722 735 source = f.read()
723 736 self.shell.run_cell(source, store_history=False)
724 737 else:
725 738 self.shell.safe_execfile(filename, self.shell.user_ns,
726 739 self.shell.user_ns)
727 740
728 741 if is_temp:
729 742 try:
730 743 with open(filename) as f:
731 744 return f.read()
732 745 except IOError as msg:
733 746 if msg.filename == filename:
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