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