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