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