##// END OF EJS Templates
Backport PR #2816: in %edit, don't save "last_call" unless last call succeeded...
MinRK -
Show More
@@ -1,521 +1,522 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 json
19 19 import os
20 20 import sys
21 21 from urllib2 import urlopen
22 22
23 23 # Our own packages
24 24 from IPython.core.error import TryNext, StdinNotImplementedError
25 25 from IPython.core.macro import Macro
26 26 from IPython.core.magic import Magics, magics_class, line_magic
27 27 from IPython.core.oinspect import find_file, find_source_lines
28 28 from IPython.testing.skipdoctest import skip_doctest
29 29 from IPython.utils import openpy
30 30 from IPython.utils import py3compat
31 31 from IPython.utils.io import file_read
32 32 from IPython.utils.path import get_py_filename, unquote_filename
33 33 from IPython.utils.warn import warn
34 34
35 35 #-----------------------------------------------------------------------------
36 36 # Magic implementation classes
37 37 #-----------------------------------------------------------------------------
38 38
39 39 # Used for exception handling in magic_edit
40 40 class MacroToEdit(ValueError): pass
41 41
42 42
43 43 @magics_class
44 44 class CodeMagics(Magics):
45 45 """Magics related to code management (loading, saving, editing, ...)."""
46 46
47 47 @line_magic
48 48 def save(self, parameter_s=''):
49 49 """Save a set of lines or a macro to a given filename.
50 50
51 51 Usage:\\
52 52 %save [options] filename n1-n2 n3-n4 ... n5 .. n6 ...
53 53
54 54 Options:
55 55
56 56 -r: use 'raw' input. By default, the 'processed' history is used,
57 57 so that magics are loaded in their transformed version to valid
58 58 Python. If this option is given, the raw input as typed as the
59 59 command line is used instead.
60 60
61 61 -f: force overwrite. If file exists, %save will prompt for overwrite
62 62 unless -f is given.
63 63
64 64 This function uses the same syntax as %history for input ranges,
65 65 then saves the lines to the filename you specify.
66 66
67 67 It adds a '.py' extension to the file if you don't do so yourself, and
68 68 it asks for confirmation before overwriting existing files.
69 69
70 70 If `-r` option is used, the default extension is `.ipy`.
71 71 """
72 72
73 73 opts,args = self.parse_options(parameter_s,'fr',mode='list')
74 74 raw = 'r' in opts
75 75 force = 'f' in opts
76 76 ext = u'.ipy' if raw else u'.py'
77 77 fname, codefrom = unquote_filename(args[0]), " ".join(args[1:])
78 78 if not fname.endswith((u'.py',u'.ipy')):
79 79 fname += ext
80 80 if os.path.isfile(fname) and not force:
81 81 try:
82 82 overwrite = self.shell.ask_yes_no('File `%s` exists. Overwrite (y/[N])? ' % fname, default='n')
83 83 except StdinNotImplementedError:
84 84 print "File `%s` exists. Use `%%save -f %s` to force overwrite" % (fname, parameter_s)
85 85 return
86 86 if not overwrite :
87 87 print 'Operation cancelled.'
88 88 return
89 89 try:
90 90 cmds = self.shell.find_user_code(codefrom,raw)
91 91 except (TypeError, ValueError) as e:
92 92 print e.args[0]
93 93 return
94 94 with io.open(fname,'w', encoding="utf-8") as f:
95 95 f.write(u"# coding: utf-8\n")
96 96 f.write(py3compat.cast_unicode(cmds))
97 97 print 'The following commands were written to file `%s`:' % fname
98 98 print cmds
99 99
100 100 @line_magic
101 101 def pastebin(self, parameter_s=''):
102 102 """Upload code to Github's Gist paste bin, returning the URL.
103 103
104 104 Usage:\\
105 105 %pastebin [-d "Custom description"] 1-7
106 106
107 107 The argument can be an input history range, a filename, or the name of a
108 108 string or macro.
109 109
110 110 Options:
111 111
112 112 -d: Pass a custom description for the gist. The default will say
113 113 "Pasted from IPython".
114 114 """
115 115 opts, args = self.parse_options(parameter_s, 'd:')
116 116
117 117 try:
118 118 code = self.shell.find_user_code(args)
119 119 except (ValueError, TypeError) as e:
120 120 print e.args[0]
121 121 return
122 122
123 123 post_data = json.dumps({
124 124 "description": opts.get('d', "Pasted from IPython"),
125 125 "public": True,
126 126 "files": {
127 127 "file1.py": {
128 128 "content": code
129 129 }
130 130 }
131 131 }).encode('utf-8')
132 132
133 133 response = urlopen("https://api.github.com/gists", post_data)
134 134 response_data = json.loads(response.read().decode('utf-8'))
135 135 return response_data['html_url']
136 136
137 137 @line_magic
138 138 def loadpy(self, arg_s):
139 139 """Alias of `%load`
140 140
141 141 `%loadpy` has gained some flexibility and droped the requirement of a `.py`
142 142 extension. So it has been renamed simply into %load. You can look at
143 143 `%load`'s docstring for more info.
144 144 """
145 145 self.load(arg_s)
146 146
147 147 @line_magic
148 148 def load(self, arg_s):
149 149 """Load code into the current frontend.
150 150
151 151 Usage:\\
152 152 %load [options] source
153 153
154 154 where source can be a filename, URL, input history range or macro
155 155
156 156 Options:
157 157 --------
158 158 -y : Don't ask confirmation for loading source above 200 000 characters.
159 159
160 160 This magic command can either take a local filename, a URL, an history
161 161 range (see %history) or a macro as argument, it will prompt for
162 162 confirmation before loading source with more than 200 000 characters, unless
163 163 -y flag is passed or if the frontend does not support raw_input::
164 164
165 165 %load myscript.py
166 166 %load 7-27
167 167 %load myMacro
168 168 %load http://www.example.com/myscript.py
169 169 """
170 170 opts,args = self.parse_options(arg_s,'y')
171 171
172 172 contents = self.shell.find_user_code(args)
173 173 l = len(contents)
174 174
175 175 # 200 000 is ~ 2500 full 80 caracter lines
176 176 # so in average, more than 5000 lines
177 177 if l > 200000 and 'y' not in opts:
178 178 try:
179 179 ans = self.shell.ask_yes_no(("The text you're trying to load seems pretty big"\
180 180 " (%d characters). Continue (y/[N]) ?" % l), default='n' )
181 181 except StdinNotImplementedError:
182 182 #asume yes if raw input not implemented
183 183 ans = True
184 184
185 185 if ans is False :
186 186 print 'Operation cancelled.'
187 187 return
188 188
189 189 self.shell.set_next_input(contents)
190 190
191 191 @staticmethod
192 192 def _find_edit_target(shell, args, opts, last_call):
193 193 """Utility method used by magic_edit to find what to edit."""
194 194
195 195 def make_filename(arg):
196 196 "Make a filename from the given args"
197 197 arg = unquote_filename(arg)
198 198 try:
199 199 filename = get_py_filename(arg)
200 200 except IOError:
201 201 # If it ends with .py but doesn't already exist, assume we want
202 202 # a new file.
203 203 if arg.endswith('.py'):
204 204 filename = arg
205 205 else:
206 206 filename = None
207 207 return filename
208 208
209 209 # Set a few locals from the options for convenience:
210 210 opts_prev = 'p' in opts
211 211 opts_raw = 'r' in opts
212 212
213 213 # custom exceptions
214 214 class DataIsObject(Exception): pass
215 215
216 216 # Default line number value
217 217 lineno = opts.get('n',None)
218 218
219 219 if opts_prev:
220 220 args = '_%s' % last_call[0]
221 221 if not shell.user_ns.has_key(args):
222 222 args = last_call[1]
223 223
224 # use last_call to remember the state of the previous call, but don't
225 # let it be clobbered by successive '-p' calls.
226 try:
227 last_call[0] = shell.displayhook.prompt_count
228 if not opts_prev:
229 last_call[1] = args
230 except:
231 pass
232
233 224 # by default this is done with temp files, except when the given
234 225 # arg is a filename
235 226 use_temp = True
236 227
237 228 data = ''
238 229
239 230 # First, see if the arguments should be a filename.
240 231 filename = make_filename(args)
241 232 if filename:
242 233 use_temp = False
243 234 elif args:
244 235 # Mode where user specifies ranges of lines, like in %macro.
245 236 data = shell.extract_input_lines(args, opts_raw)
246 237 if not data:
247 238 try:
248 239 # Load the parameter given as a variable. If not a string,
249 240 # process it as an object instead (below)
250 241
251 242 #print '*** args',args,'type',type(args) # dbg
252 243 data = eval(args, shell.user_ns)
253 244 if not isinstance(data, basestring):
254 245 raise DataIsObject
255 246
256 247 except (NameError,SyntaxError):
257 248 # given argument is not a variable, try as a filename
258 249 filename = make_filename(args)
259 250 if filename is None:
260 251 warn("Argument given (%s) can't be found as a variable "
261 252 "or as a filename." % args)
262 253 return
263 254 use_temp = False
264 255
265 256 except DataIsObject:
266 257 # macros have a special edit function
267 258 if isinstance(data, Macro):
268 259 raise MacroToEdit(data)
269 260
270 261 # For objects, try to edit the file where they are defined
271 262 filename = find_file(data)
272 263 if filename:
273 264 if 'fakemodule' in filename.lower() and \
274 265 inspect.isclass(data):
275 266 # class created by %edit? Try to find source
276 267 # by looking for method definitions instead, the
277 268 # __module__ in those classes is FakeModule.
278 269 attrs = [getattr(data, aname) for aname in dir(data)]
279 270 for attr in attrs:
280 271 if not inspect.ismethod(attr):
281 272 continue
282 273 filename = find_file(attr)
283 274 if filename and \
284 275 'fakemodule' not in filename.lower():
285 276 # change the attribute to be the edit
286 277 # target instead
287 278 data = attr
288 279 break
289 280
290 281 datafile = 1
291 282 if filename is None:
292 283 filename = make_filename(args)
293 284 datafile = 1
294 285 warn('Could not find file where `%s` is defined.\n'
295 286 'Opening a file named `%s`' % (args, filename))
296 287 # Now, make sure we can actually read the source (if it was
297 288 # in a temp file it's gone by now).
298 289 if datafile:
299 290 if lineno is None:
300 291 lineno = find_source_lines(data)
301 292 if lineno is None:
302 293 filename = make_filename(args)
303 294 if filename is None:
304 295 warn('The file `%s` where `%s` was defined '
305 296 'cannot be read.' % (filename, data))
306 297 return
307 298 use_temp = False
308 299
309 300 if use_temp:
310 301 filename = shell.mktempfile(data)
311 302 print 'IPython will make a temporary file named:',filename
312 303
304 # use last_call to remember the state of the previous call, but don't
305 # let it be clobbered by successive '-p' calls.
306 try:
307 last_call[0] = shell.displayhook.prompt_count
308 if not opts_prev:
309 last_call[1] = args
310 except:
311 pass
312
313
313 314 return filename, lineno, use_temp
314 315
315 316 def _edit_macro(self,mname,macro):
316 317 """open an editor with the macro data in a file"""
317 318 filename = self.shell.mktempfile(macro.value)
318 319 self.shell.hooks.editor(filename)
319 320
320 321 # and make a new macro object, to replace the old one
321 322 mfile = open(filename)
322 323 mvalue = mfile.read()
323 324 mfile.close()
324 325 self.shell.user_ns[mname] = Macro(mvalue)
325 326
326 327 @line_magic
327 328 def ed(self, parameter_s=''):
328 329 """Alias to %edit."""
329 330 return self.edit(parameter_s)
330 331
331 332 @skip_doctest
332 333 @line_magic
333 334 def edit(self, parameter_s='',last_call=['','']):
334 335 """Bring up an editor and execute the resulting code.
335 336
336 337 Usage:
337 338 %edit [options] [args]
338 339
339 340 %edit runs IPython's editor hook. The default version of this hook is
340 341 set to call the editor specified by your $EDITOR environment variable.
341 342 If this isn't found, it will default to vi under Linux/Unix and to
342 343 notepad under Windows. See the end of this docstring for how to change
343 344 the editor hook.
344 345
345 346 You can also set the value of this editor via the
346 347 ``TerminalInteractiveShell.editor`` option in your configuration file.
347 348 This is useful if you wish to use a different editor from your typical
348 349 default with IPython (and for Windows users who typically don't set
349 350 environment variables).
350 351
351 352 This command allows you to conveniently edit multi-line code right in
352 353 your IPython session.
353 354
354 355 If called without arguments, %edit opens up an empty editor with a
355 356 temporary file and will execute the contents of this file when you
356 357 close it (don't forget to save it!).
357 358
358 359
359 360 Options:
360 361
361 362 -n <number>: open the editor at a specified line number. By default,
362 363 the IPython editor hook uses the unix syntax 'editor +N filename', but
363 364 you can configure this by providing your own modified hook if your
364 365 favorite editor supports line-number specifications with a different
365 366 syntax.
366 367
367 368 -p: this will call the editor with the same data as the previous time
368 369 it was used, regardless of how long ago (in your current session) it
369 370 was.
370 371
371 372 -r: use 'raw' input. This option only applies to input taken from the
372 373 user's history. By default, the 'processed' history is used, so that
373 374 magics are loaded in their transformed version to valid Python. If
374 375 this option is given, the raw input as typed as the command line is
375 376 used instead. When you exit the editor, it will be executed by
376 377 IPython's own processor.
377 378
378 379 -x: do not execute the edited code immediately upon exit. This is
379 380 mainly useful if you are editing programs which need to be called with
380 381 command line arguments, which you can then do using %run.
381 382
382 383
383 384 Arguments:
384 385
385 386 If arguments are given, the following possibilities exist:
386 387
387 388 - If the argument is a filename, IPython will load that into the
388 389 editor. It will execute its contents with execfile() when you exit,
389 390 loading any code in the file into your interactive namespace.
390 391
391 392 - The arguments are ranges of input history, e.g. "7 ~1/4-6".
392 393 The syntax is the same as in the %history magic.
393 394
394 395 - If the argument is a string variable, its contents are loaded
395 396 into the editor. You can thus edit any string which contains
396 397 python code (including the result of previous edits).
397 398
398 399 - If the argument is the name of an object (other than a string),
399 400 IPython will try to locate the file where it was defined and open the
400 401 editor at the point where it is defined. You can use `%edit function`
401 402 to load an editor exactly at the point where 'function' is defined,
402 403 edit it and have the file be executed automatically.
403 404
404 405 - If the object is a macro (see %macro for details), this opens up your
405 406 specified editor with a temporary file containing the macro's data.
406 407 Upon exit, the macro is reloaded with the contents of the file.
407 408
408 409 Note: opening at an exact line is only supported under Unix, and some
409 410 editors (like kedit and gedit up to Gnome 2.8) do not understand the
410 411 '+NUMBER' parameter necessary for this feature. Good editors like
411 412 (X)Emacs, vi, jed, pico and joe all do.
412 413
413 414 After executing your code, %edit will return as output the code you
414 415 typed in the editor (except when it was an existing file). This way
415 416 you can reload the code in further invocations of %edit as a variable,
416 417 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
417 418 the output.
418 419
419 420 Note that %edit is also available through the alias %ed.
420 421
421 422 This is an example of creating a simple function inside the editor and
422 423 then modifying it. First, start up the editor::
423 424
424 425 In [1]: ed
425 426 Editing... done. Executing edited code...
426 427 Out[1]: 'def foo():\\n print "foo() was defined in an editing
427 428 session"\\n'
428 429
429 430 We can then call the function foo()::
430 431
431 432 In [2]: foo()
432 433 foo() was defined in an editing session
433 434
434 435 Now we edit foo. IPython automatically loads the editor with the
435 436 (temporary) file where foo() was previously defined::
436 437
437 438 In [3]: ed foo
438 439 Editing... done. Executing edited code...
439 440
440 441 And if we call foo() again we get the modified version::
441 442
442 443 In [4]: foo()
443 444 foo() has now been changed!
444 445
445 446 Here is an example of how to edit a code snippet successive
446 447 times. First we call the editor::
447 448
448 449 In [5]: ed
449 450 Editing... done. Executing edited code...
450 451 hello
451 452 Out[5]: "print 'hello'\\n"
452 453
453 454 Now we call it again with the previous output (stored in _)::
454 455
455 456 In [6]: ed _
456 457 Editing... done. Executing edited code...
457 458 hello world
458 459 Out[6]: "print 'hello world'\\n"
459 460
460 461 Now we call it with the output #8 (stored in _8, also as Out[8])::
461 462
462 463 In [7]: ed _8
463 464 Editing... done. Executing edited code...
464 465 hello again
465 466 Out[7]: "print 'hello again'\\n"
466 467
467 468
468 469 Changing the default editor hook:
469 470
470 471 If you wish to write your own editor hook, you can put it in a
471 472 configuration file which you load at startup time. The default hook
472 473 is defined in the IPython.core.hooks module, and you can use that as a
473 474 starting example for further modifications. That file also has
474 475 general instructions on how to set a new hook for use once you've
475 476 defined it."""
476 477 opts,args = self.parse_options(parameter_s,'prxn:')
477 478
478 479 try:
479 480 filename, lineno, is_temp = self._find_edit_target(self.shell,
480 481 args, opts, last_call)
481 482 except MacroToEdit as e:
482 483 self._edit_macro(args, e.args[0])
483 484 return
484 485
485 486 # do actual editing here
486 487 print 'Editing...',
487 488 sys.stdout.flush()
488 489 try:
489 490 # Quote filenames that may have spaces in them
490 491 if ' ' in filename:
491 492 filename = "'%s'" % filename
492 493 self.shell.hooks.editor(filename,lineno)
493 494 except TryNext:
494 495 warn('Could not open editor')
495 496 return
496 497
497 498 # XXX TODO: should this be generalized for all string vars?
498 499 # For now, this is special-cased to blocks created by cpaste
499 500 if args.strip() == 'pasted_block':
500 501 self.shell.user_ns['pasted_block'] = file_read(filename)
501 502
502 503 if 'x' in opts: # -x prevents actual execution
503 504 print
504 505 else:
505 506 print 'done. Executing edited code...'
506 507 if 'r' in opts: # Untranslated IPython code
507 508 self.shell.run_cell(file_read(filename),
508 509 store_history=False)
509 510 else:
510 511 self.shell.safe_execfile(filename, self.shell.user_ns,
511 512 self.shell.user_ns)
512 513
513 514 if is_temp:
514 515 try:
515 516 return open(filename).read()
516 517 except IOError,msg:
517 518 if msg.filename == filename:
518 519 warn('File not found. Did you forget to save?')
519 520 return
520 521 else:
521 522 self.shell.showtraceback()
General Comments 0
You need to be logged in to leave comments. Login now