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