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