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