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