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