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