##// END OF EJS Templates
Disambiguated docstring, since there have been other dpastes
Paul Bissex -
Show More
@@ -1,733 +1,733 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 """Upload code to dpaste's paste bin, returning the URL.
249 """Upload code to dpaste.com, returning the URL.
250 250
251 251 Usage:\\
252 252 %pastebin [-d "Custom description"] 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 261 """
262 262 opts, args = self.parse_options(parameter_s, 'd:')
263 263
264 264 try:
265 265 code = self.shell.find_user_code(args)
266 266 except (ValueError, TypeError) as e:
267 267 print(e.args[0])
268 268 return
269 269
270 270 post_data = urlencode({
271 271 "title": opts.get('d', "Pasted from IPython"),
272 272 "syntax": "python",
273 273 "content": code
274 274 }).encode('utf-8')
275 275
276 276 request = Request("http://dpaste.com/api/v2/",
277 277 headers={"User-Agent": "IPython v{}".format(version)})
278 278 response = urlopen(request, post_data)
279 279 return response.headers.get('Location')
280 280
281 281 @line_magic
282 282 def loadpy(self, arg_s):
283 283 """Alias of `%load`
284 284
285 285 `%loadpy` has gained some flexibility and dropped the requirement of a `.py`
286 286 extension. So it has been renamed simply into %load. You can look at
287 287 `%load`'s docstring for more info.
288 288 """
289 289 self.load(arg_s)
290 290
291 291 @line_magic
292 292 def load(self, arg_s):
293 293 """Load code into the current frontend.
294 294
295 295 Usage:\\
296 296 %load [options] source
297 297
298 298 where source can be a filename, URL, input history range, macro, or
299 299 element in the user namespace
300 300
301 301 Options:
302 302
303 303 -r <lines>: Specify lines or ranges of lines to load from the source.
304 304 Ranges could be specified as x-y (x..y) or in python-style x:y
305 305 (x..(y-1)). Both limits x and y can be left blank (meaning the
306 306 beginning and end of the file, respectively).
307 307
308 308 -s <symbols>: Specify function or classes to load from python source.
309 309
310 310 -y : Don't ask confirmation for loading source above 200 000 characters.
311 311
312 312 -n : Include the user's namespace when searching for source code.
313 313
314 314 This magic command can either take a local filename, a URL, an history
315 315 range (see %history) or a macro as argument, it will prompt for
316 316 confirmation before loading source with more than 200 000 characters, unless
317 317 -y flag is passed or if the frontend does not support raw_input::
318 318
319 319 %load myscript.py
320 320 %load 7-27
321 321 %load myMacro
322 322 %load http://www.example.com/myscript.py
323 323 %load -r 5-10 myscript.py
324 324 %load -r 10-20,30,40: foo.py
325 325 %load -s MyClass,wonder_function myscript.py
326 326 %load -n MyClass
327 327 %load -n my_module.wonder_function
328 328 """
329 329 opts,args = self.parse_options(arg_s,'yns:r:')
330 330
331 331 if not args:
332 332 raise UsageError('Missing filename, URL, input history range, '
333 333 'macro, or element in the user namespace.')
334 334
335 335 search_ns = 'n' in opts
336 336
337 337 contents = self.shell.find_user_code(args, search_ns=search_ns)
338 338
339 339 if 's' in opts:
340 340 try:
341 341 blocks, not_found = extract_symbols(contents, opts['s'])
342 342 except SyntaxError:
343 343 # non python code
344 344 error("Unable to parse the input as valid Python code")
345 345 return
346 346
347 347 if len(not_found) == 1:
348 348 warn('The symbol `%s` was not found' % not_found[0])
349 349 elif len(not_found) > 1:
350 350 warn('The symbols %s were not found' % get_text_list(not_found,
351 351 wrap_item_with='`')
352 352 )
353 353
354 354 contents = '\n'.join(blocks)
355 355
356 356 if 'r' in opts:
357 357 ranges = opts['r'].replace(',', ' ')
358 358 lines = contents.split('\n')
359 359 slices = extract_code_ranges(ranges)
360 360 contents = [lines[slice(*slc)] for slc in slices]
361 361 contents = '\n'.join(strip_initial_indent(chain.from_iterable(contents)))
362 362
363 363 l = len(contents)
364 364
365 365 # 200 000 is ~ 2500 full 80 character lines
366 366 # so in average, more than 5000 lines
367 367 if l > 200000 and 'y' not in opts:
368 368 try:
369 369 ans = self.shell.ask_yes_no(("The text you're trying to load seems pretty big"\
370 370 " (%d characters). Continue (y/[N]) ?" % l), default='n' )
371 371 except StdinNotImplementedError:
372 372 #assume yes if raw input not implemented
373 373 ans = True
374 374
375 375 if ans is False :
376 376 print('Operation cancelled.')
377 377 return
378 378
379 379 contents = "# %load {}\n".format(arg_s) + contents
380 380
381 381 self.shell.set_next_input(contents, replace=True)
382 382
383 383 @staticmethod
384 384 def _find_edit_target(shell, args, opts, last_call):
385 385 """Utility method used by magic_edit to find what to edit."""
386 386
387 387 def make_filename(arg):
388 388 "Make a filename from the given args"
389 389 try:
390 390 filename = get_py_filename(arg)
391 391 except IOError:
392 392 # If it ends with .py but doesn't already exist, assume we want
393 393 # a new file.
394 394 if arg.endswith('.py'):
395 395 filename = arg
396 396 else:
397 397 filename = None
398 398 return filename
399 399
400 400 # Set a few locals from the options for convenience:
401 401 opts_prev = 'p' in opts
402 402 opts_raw = 'r' in opts
403 403
404 404 # custom exceptions
405 405 class DataIsObject(Exception): pass
406 406
407 407 # Default line number value
408 408 lineno = opts.get('n',None)
409 409
410 410 if opts_prev:
411 411 args = '_%s' % last_call[0]
412 412 if args not in shell.user_ns:
413 413 args = last_call[1]
414 414
415 415 # by default this is done with temp files, except when the given
416 416 # arg is a filename
417 417 use_temp = True
418 418
419 419 data = ''
420 420
421 421 # First, see if the arguments should be a filename.
422 422 filename = make_filename(args)
423 423 if filename:
424 424 use_temp = False
425 425 elif args:
426 426 # Mode where user specifies ranges of lines, like in %macro.
427 427 data = shell.extract_input_lines(args, opts_raw)
428 428 if not data:
429 429 try:
430 430 # Load the parameter given as a variable. If not a string,
431 431 # process it as an object instead (below)
432 432
433 433 #print '*** args',args,'type',type(args) # dbg
434 434 data = eval(args, shell.user_ns)
435 435 if not isinstance(data, str):
436 436 raise DataIsObject
437 437
438 438 except (NameError,SyntaxError):
439 439 # given argument is not a variable, try as a filename
440 440 filename = make_filename(args)
441 441 if filename is None:
442 442 warn("Argument given (%s) can't be found as a variable "
443 443 "or as a filename." % args)
444 444 return (None, None, None)
445 445 use_temp = False
446 446
447 447 except DataIsObject as e:
448 448 # macros have a special edit function
449 449 if isinstance(data, Macro):
450 450 raise MacroToEdit(data) from e
451 451
452 452 # For objects, try to edit the file where they are defined
453 453 filename = find_file(data)
454 454 if filename:
455 455 if 'fakemodule' in filename.lower() and \
456 456 inspect.isclass(data):
457 457 # class created by %edit? Try to find source
458 458 # by looking for method definitions instead, the
459 459 # __module__ in those classes is FakeModule.
460 460 attrs = [getattr(data, aname) for aname in dir(data)]
461 461 for attr in attrs:
462 462 if not inspect.ismethod(attr):
463 463 continue
464 464 filename = find_file(attr)
465 465 if filename and \
466 466 'fakemodule' not in filename.lower():
467 467 # change the attribute to be the edit
468 468 # target instead
469 469 data = attr
470 470 break
471 471
472 472 m = ipython_input_pat.match(os.path.basename(filename))
473 473 if m:
474 474 raise InteractivelyDefined(int(m.groups()[0])) from e
475 475
476 476 datafile = 1
477 477 if filename is None:
478 478 filename = make_filename(args)
479 479 datafile = 1
480 480 if filename is not None:
481 481 # only warn about this if we get a real name
482 482 warn('Could not find file where `%s` is defined.\n'
483 483 'Opening a file named `%s`' % (args, filename))
484 484 # Now, make sure we can actually read the source (if it was
485 485 # in a temp file it's gone by now).
486 486 if datafile:
487 487 if lineno is None:
488 488 lineno = find_source_lines(data)
489 489 if lineno is None:
490 490 filename = make_filename(args)
491 491 if filename is None:
492 492 warn('The file where `%s` was defined '
493 493 'cannot be read or found.' % data)
494 494 return (None, None, None)
495 495 use_temp = False
496 496
497 497 if use_temp:
498 498 filename = shell.mktempfile(data)
499 499 print('IPython will make a temporary file named:',filename)
500 500
501 501 # use last_call to remember the state of the previous call, but don't
502 502 # let it be clobbered by successive '-p' calls.
503 503 try:
504 504 last_call[0] = shell.displayhook.prompt_count
505 505 if not opts_prev:
506 506 last_call[1] = args
507 507 except:
508 508 pass
509 509
510 510
511 511 return filename, lineno, use_temp
512 512
513 513 def _edit_macro(self,mname,macro):
514 514 """open an editor with the macro data in a file"""
515 515 filename = self.shell.mktempfile(macro.value)
516 516 self.shell.hooks.editor(filename)
517 517
518 518 # and make a new macro object, to replace the old one
519 519 mvalue = Path(filename).read_text()
520 520 self.shell.user_ns[mname] = Macro(mvalue)
521 521
522 522 @skip_doctest
523 523 @line_magic
524 524 def edit(self, parameter_s='',last_call=['','']):
525 525 """Bring up an editor and execute the resulting code.
526 526
527 527 Usage:
528 528 %edit [options] [args]
529 529
530 530 %edit runs IPython's editor hook. The default version of this hook is
531 531 set to call the editor specified by your $EDITOR environment variable.
532 532 If this isn't found, it will default to vi under Linux/Unix and to
533 533 notepad under Windows. See the end of this docstring for how to change
534 534 the editor hook.
535 535
536 536 You can also set the value of this editor via the
537 537 ``TerminalInteractiveShell.editor`` option in your configuration file.
538 538 This is useful if you wish to use a different editor from your typical
539 539 default with IPython (and for Windows users who typically don't set
540 540 environment variables).
541 541
542 542 This command allows you to conveniently edit multi-line code right in
543 543 your IPython session.
544 544
545 545 If called without arguments, %edit opens up an empty editor with a
546 546 temporary file and will execute the contents of this file when you
547 547 close it (don't forget to save it!).
548 548
549 549
550 550 Options:
551 551
552 552 -n <number>: open the editor at a specified line number. By default,
553 553 the IPython editor hook uses the unix syntax 'editor +N filename', but
554 554 you can configure this by providing your own modified hook if your
555 555 favorite editor supports line-number specifications with a different
556 556 syntax.
557 557
558 558 -p: this will call the editor with the same data as the previous time
559 559 it was used, regardless of how long ago (in your current session) it
560 560 was.
561 561
562 562 -r: use 'raw' input. This option only applies to input taken from the
563 563 user's history. By default, the 'processed' history is used, so that
564 564 magics are loaded in their transformed version to valid Python. If
565 565 this option is given, the raw input as typed as the command line is
566 566 used instead. When you exit the editor, it will be executed by
567 567 IPython's own processor.
568 568
569 569 -x: do not execute the edited code immediately upon exit. This is
570 570 mainly useful if you are editing programs which need to be called with
571 571 command line arguments, which you can then do using %run.
572 572
573 573
574 574 Arguments:
575 575
576 576 If arguments are given, the following possibilities exist:
577 577
578 578 - If the argument is a filename, IPython will load that into the
579 579 editor. It will execute its contents with execfile() when you exit,
580 580 loading any code in the file into your interactive namespace.
581 581
582 582 - The arguments are ranges of input history, e.g. "7 ~1/4-6".
583 583 The syntax is the same as in the %history magic.
584 584
585 585 - If the argument is a string variable, its contents are loaded
586 586 into the editor. You can thus edit any string which contains
587 587 python code (including the result of previous edits).
588 588
589 589 - If the argument is the name of an object (other than a string),
590 590 IPython will try to locate the file where it was defined and open the
591 591 editor at the point where it is defined. You can use `%edit function`
592 592 to load an editor exactly at the point where 'function' is defined,
593 593 edit it and have the file be executed automatically.
594 594
595 595 - If the object is a macro (see %macro for details), this opens up your
596 596 specified editor with a temporary file containing the macro's data.
597 597 Upon exit, the macro is reloaded with the contents of the file.
598 598
599 599 Note: opening at an exact line is only supported under Unix, and some
600 600 editors (like kedit and gedit up to Gnome 2.8) do not understand the
601 601 '+NUMBER' parameter necessary for this feature. Good editors like
602 602 (X)Emacs, vi, jed, pico and joe all do.
603 603
604 604 After executing your code, %edit will return as output the code you
605 605 typed in the editor (except when it was an existing file). This way
606 606 you can reload the code in further invocations of %edit as a variable,
607 607 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
608 608 the output.
609 609
610 610 Note that %edit is also available through the alias %ed.
611 611
612 612 This is an example of creating a simple function inside the editor and
613 613 then modifying it. First, start up the editor::
614 614
615 615 In [1]: edit
616 616 Editing... done. Executing edited code...
617 617 Out[1]: 'def foo():\\n print "foo() was defined in an editing
618 618 session"\\n'
619 619
620 620 We can then call the function foo()::
621 621
622 622 In [2]: foo()
623 623 foo() was defined in an editing session
624 624
625 625 Now we edit foo. IPython automatically loads the editor with the
626 626 (temporary) file where foo() was previously defined::
627 627
628 628 In [3]: edit foo
629 629 Editing... done. Executing edited code...
630 630
631 631 And if we call foo() again we get the modified version::
632 632
633 633 In [4]: foo()
634 634 foo() has now been changed!
635 635
636 636 Here is an example of how to edit a code snippet successive
637 637 times. First we call the editor::
638 638
639 639 In [5]: edit
640 640 Editing... done. Executing edited code...
641 641 hello
642 642 Out[5]: "print 'hello'\\n"
643 643
644 644 Now we call it again with the previous output (stored in _)::
645 645
646 646 In [6]: edit _
647 647 Editing... done. Executing edited code...
648 648 hello world
649 649 Out[6]: "print 'hello world'\\n"
650 650
651 651 Now we call it with the output #8 (stored in _8, also as Out[8])::
652 652
653 653 In [7]: edit _8
654 654 Editing... done. Executing edited code...
655 655 hello again
656 656 Out[7]: "print 'hello again'\\n"
657 657
658 658
659 659 Changing the default editor hook:
660 660
661 661 If you wish to write your own editor hook, you can put it in a
662 662 configuration file which you load at startup time. The default hook
663 663 is defined in the IPython.core.hooks module, and you can use that as a
664 664 starting example for further modifications. That file also has
665 665 general instructions on how to set a new hook for use once you've
666 666 defined it."""
667 667 opts,args = self.parse_options(parameter_s,'prxn:')
668 668
669 669 try:
670 670 filename, lineno, is_temp = self._find_edit_target(self.shell,
671 671 args, opts, last_call)
672 672 except MacroToEdit as e:
673 673 self._edit_macro(args, e.args[0])
674 674 return
675 675 except InteractivelyDefined as e:
676 676 print("Editing In[%i]" % e.index)
677 677 args = str(e.index)
678 678 filename, lineno, is_temp = self._find_edit_target(self.shell,
679 679 args, opts, last_call)
680 680 if filename is None:
681 681 # nothing was found, warnings have already been issued,
682 682 # just give up.
683 683 return
684 684
685 685 if is_temp:
686 686 self._knowntemps.add(filename)
687 687 elif (filename in self._knowntemps):
688 688 is_temp = True
689 689
690 690
691 691 # do actual editing here
692 692 print('Editing...', end=' ')
693 693 sys.stdout.flush()
694 694 filepath = Path(filename)
695 695 try:
696 696 # Quote filenames that may have spaces in them when opening
697 697 # the editor
698 698 quoted = filename = str(filepath.absolute())
699 699 if " " in quoted:
700 700 quoted = "'%s'" % quoted
701 701 self.shell.hooks.editor(quoted, lineno)
702 702 except TryNext:
703 703 warn('Could not open editor')
704 704 return
705 705
706 706 # XXX TODO: should this be generalized for all string vars?
707 707 # For now, this is special-cased to blocks created by cpaste
708 708 if args.strip() == "pasted_block":
709 709 self.shell.user_ns["pasted_block"] = filepath.read_text()
710 710
711 711 if 'x' in opts: # -x prevents actual execution
712 712 print()
713 713 else:
714 714 print('done. Executing edited code...')
715 715 with preserve_keys(self.shell.user_ns, '__file__'):
716 716 if not is_temp:
717 717 self.shell.user_ns['__file__'] = filename
718 718 if 'r' in opts: # Untranslated IPython code
719 719 source = filepath.read_text()
720 720 self.shell.run_cell(source, store_history=False)
721 721 else:
722 722 self.shell.safe_execfile(filename, self.shell.user_ns,
723 723 self.shell.user_ns)
724 724
725 725 if is_temp:
726 726 try:
727 727 return filepath.read_text()
728 728 except IOError as msg:
729 729 if Path(msg.filename) == filepath:
730 730 warn('File not found. Did you forget to save?')
731 731 return
732 732 else:
733 733 self.shell.showtraceback()
General Comments 0
You need to be logged in to leave comments. Login now