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