##// END OF EJS Templates
better docstring for the -r option
Martín Gaitán -
Show More
@@ -1,610 +1,614 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 -r : specify ranges of lines to load from the source
215 -r <lines>: Specify lines or ranges of lines to load from the source.
216 Ranges could be specified as x-y (x..y) or in python-style x:y
217 (x..(y-1)). Both limits x and y can be left blank (meaning the
218 beginning and end of the file, respectively).
219
216 220 -y : Don't ask confirmation for loading source above 200 000 characters.
217 221
218 222 This magic command can either take a local filename, a URL, an history
219 223 range (see %history) or a macro as argument, it will prompt for
220 224 confirmation before loading source with more than 200 000 characters, unless
221 225 -y flag is passed or if the frontend does not support raw_input::
222 226
223 227 %load myscript.py
224 228 %load 7-27
225 229 %load myMacro
226 230 %load http://www.example.com/myscript.py
227 231 %load -r 5-10 myscript.py
228 %load -r 10-20,30,40-50 foo.py
232 %load -r 10-20,30,40: foo.py
229 233 """
230 234 opts,args = self.parse_options(arg_s,'yr:')
231 235
232 236 if not args:
233 237 raise UsageError('Missing filename, URL, input history range, '
234 238 'or macro.')
235 239
236 240 contents = self.shell.find_user_code(args)
237 241
238 242 if 'r' in opts:
239 243 ranges = opts['r'].replace(',', ' ')
240 244 lines = contents.split('\n')
241 245 slices = extract_code_ranges(ranges)
242 246 contents = [lines[slice(*slc)] for slc in slices]
243 247 contents = '\n'.join(chain.from_iterable(contents))
244 248
245 249 l = len(contents)
246 250
247 251
248 252 # 200 000 is ~ 2500 full 80 caracter lines
249 253 # so in average, more than 5000 lines
250 254 if l > 200000 and 'y' not in opts:
251 255 try:
252 256 ans = self.shell.ask_yes_no(("The text you're trying to load seems pretty big"\
253 257 " (%d characters). Continue (y/[N]) ?" % l), default='n' )
254 258 except StdinNotImplementedError:
255 259 #asume yes if raw input not implemented
256 260 ans = True
257 261
258 262 if ans is False :
259 263 print 'Operation cancelled.'
260 264 return
261 265
262 266 self.shell.set_next_input(contents)
263 267
264 268 @staticmethod
265 269 def _find_edit_target(shell, args, opts, last_call):
266 270 """Utility method used by magic_edit to find what to edit."""
267 271
268 272 def make_filename(arg):
269 273 "Make a filename from the given args"
270 274 arg = unquote_filename(arg)
271 275 try:
272 276 filename = get_py_filename(arg)
273 277 except IOError:
274 278 # If it ends with .py but doesn't already exist, assume we want
275 279 # a new file.
276 280 if arg.endswith('.py'):
277 281 filename = arg
278 282 else:
279 283 filename = None
280 284 return filename
281 285
282 286 # Set a few locals from the options for convenience:
283 287 opts_prev = 'p' in opts
284 288 opts_raw = 'r' in opts
285 289
286 290 # custom exceptions
287 291 class DataIsObject(Exception): pass
288 292
289 293 # Default line number value
290 294 lineno = opts.get('n',None)
291 295
292 296 if opts_prev:
293 297 args = '_%s' % last_call[0]
294 298 if args not in shell.user_ns:
295 299 args = last_call[1]
296 300
297 301 # by default this is done with temp files, except when the given
298 302 # arg is a filename
299 303 use_temp = True
300 304
301 305 data = ''
302 306
303 307 # First, see if the arguments should be a filename.
304 308 filename = make_filename(args)
305 309 if filename:
306 310 use_temp = False
307 311 elif args:
308 312 # Mode where user specifies ranges of lines, like in %macro.
309 313 data = shell.extract_input_lines(args, opts_raw)
310 314 if not data:
311 315 try:
312 316 # Load the parameter given as a variable. If not a string,
313 317 # process it as an object instead (below)
314 318
315 319 #print '*** args',args,'type',type(args) # dbg
316 320 data = eval(args, shell.user_ns)
317 321 if not isinstance(data, basestring):
318 322 raise DataIsObject
319 323
320 324 except (NameError,SyntaxError):
321 325 # given argument is not a variable, try as a filename
322 326 filename = make_filename(args)
323 327 if filename is None:
324 328 warn("Argument given (%s) can't be found as a variable "
325 329 "or as a filename." % args)
326 330 return (None, None, None)
327 331 use_temp = False
328 332
329 333 except DataIsObject:
330 334 # macros have a special edit function
331 335 if isinstance(data, Macro):
332 336 raise MacroToEdit(data)
333 337
334 338 # For objects, try to edit the file where they are defined
335 339 filename = find_file(data)
336 340 if filename:
337 341 if 'fakemodule' in filename.lower() and \
338 342 inspect.isclass(data):
339 343 # class created by %edit? Try to find source
340 344 # by looking for method definitions instead, the
341 345 # __module__ in those classes is FakeModule.
342 346 attrs = [getattr(data, aname) for aname in dir(data)]
343 347 for attr in attrs:
344 348 if not inspect.ismethod(attr):
345 349 continue
346 350 filename = find_file(attr)
347 351 if filename and \
348 352 'fakemodule' not in filename.lower():
349 353 # change the attribute to be the edit
350 354 # target instead
351 355 data = attr
352 356 break
353 357
354 358 m = ipython_input_pat.match(os.path.basename(filename))
355 359 if m:
356 360 raise InteractivelyDefined(int(m.groups()[0]))
357 361
358 362 datafile = 1
359 363 if filename is None:
360 364 filename = make_filename(args)
361 365 datafile = 1
362 366 if filename is not None:
363 367 # only warn about this if we get a real name
364 368 warn('Could not find file where `%s` is defined.\n'
365 369 'Opening a file named `%s`' % (args, filename))
366 370 # Now, make sure we can actually read the source (if it was
367 371 # in a temp file it's gone by now).
368 372 if datafile:
369 373 if lineno is None:
370 374 lineno = find_source_lines(data)
371 375 if lineno is None:
372 376 filename = make_filename(args)
373 377 if filename is None:
374 378 warn('The file where `%s` was defined '
375 379 'cannot be read or found.' % data)
376 380 return (None, None, None)
377 381 use_temp = False
378 382
379 383 if use_temp:
380 384 filename = shell.mktempfile(data)
381 385 print 'IPython will make a temporary file named:',filename
382 386
383 387 # use last_call to remember the state of the previous call, but don't
384 388 # let it be clobbered by successive '-p' calls.
385 389 try:
386 390 last_call[0] = shell.displayhook.prompt_count
387 391 if not opts_prev:
388 392 last_call[1] = args
389 393 except:
390 394 pass
391 395
392 396
393 397 return filename, lineno, use_temp
394 398
395 399 def _edit_macro(self,mname,macro):
396 400 """open an editor with the macro data in a file"""
397 401 filename = self.shell.mktempfile(macro.value)
398 402 self.shell.hooks.editor(filename)
399 403
400 404 # and make a new macro object, to replace the old one
401 405 mfile = open(filename)
402 406 mvalue = mfile.read()
403 407 mfile.close()
404 408 self.shell.user_ns[mname] = Macro(mvalue)
405 409
406 410 @skip_doctest
407 411 @line_magic
408 412 def edit(self, parameter_s='',last_call=['','']):
409 413 """Bring up an editor and execute the resulting code.
410 414
411 415 Usage:
412 416 %edit [options] [args]
413 417
414 418 %edit runs IPython's editor hook. The default version of this hook is
415 419 set to call the editor specified by your $EDITOR environment variable.
416 420 If this isn't found, it will default to vi under Linux/Unix and to
417 421 notepad under Windows. See the end of this docstring for how to change
418 422 the editor hook.
419 423
420 424 You can also set the value of this editor via the
421 425 ``TerminalInteractiveShell.editor`` option in your configuration file.
422 426 This is useful if you wish to use a different editor from your typical
423 427 default with IPython (and for Windows users who typically don't set
424 428 environment variables).
425 429
426 430 This command allows you to conveniently edit multi-line code right in
427 431 your IPython session.
428 432
429 433 If called without arguments, %edit opens up an empty editor with a
430 434 temporary file and will execute the contents of this file when you
431 435 close it (don't forget to save it!).
432 436
433 437
434 438 Options:
435 439
436 440 -n <number>: open the editor at a specified line number. By default,
437 441 the IPython editor hook uses the unix syntax 'editor +N filename', but
438 442 you can configure this by providing your own modified hook if your
439 443 favorite editor supports line-number specifications with a different
440 444 syntax.
441 445
442 446 -p: this will call the editor with the same data as the previous time
443 447 it was used, regardless of how long ago (in your current session) it
444 448 was.
445 449
446 450 -r: use 'raw' input. This option only applies to input taken from the
447 451 user's history. By default, the 'processed' history is used, so that
448 452 magics are loaded in their transformed version to valid Python. If
449 453 this option is given, the raw input as typed as the command line is
450 454 used instead. When you exit the editor, it will be executed by
451 455 IPython's own processor.
452 456
453 457 -x: do not execute the edited code immediately upon exit. This is
454 458 mainly useful if you are editing programs which need to be called with
455 459 command line arguments, which you can then do using %run.
456 460
457 461
458 462 Arguments:
459 463
460 464 If arguments are given, the following possibilities exist:
461 465
462 466 - If the argument is a filename, IPython will load that into the
463 467 editor. It will execute its contents with execfile() when you exit,
464 468 loading any code in the file into your interactive namespace.
465 469
466 470 - The arguments are ranges of input history, e.g. "7 ~1/4-6".
467 471 The syntax is the same as in the %history magic.
468 472
469 473 - If the argument is a string variable, its contents are loaded
470 474 into the editor. You can thus edit any string which contains
471 475 python code (including the result of previous edits).
472 476
473 477 - If the argument is the name of an object (other than a string),
474 478 IPython will try to locate the file where it was defined and open the
475 479 editor at the point where it is defined. You can use `%edit function`
476 480 to load an editor exactly at the point where 'function' is defined,
477 481 edit it and have the file be executed automatically.
478 482
479 483 - If the object is a macro (see %macro for details), this opens up your
480 484 specified editor with a temporary file containing the macro's data.
481 485 Upon exit, the macro is reloaded with the contents of the file.
482 486
483 487 Note: opening at an exact line is only supported under Unix, and some
484 488 editors (like kedit and gedit up to Gnome 2.8) do not understand the
485 489 '+NUMBER' parameter necessary for this feature. Good editors like
486 490 (X)Emacs, vi, jed, pico and joe all do.
487 491
488 492 After executing your code, %edit will return as output the code you
489 493 typed in the editor (except when it was an existing file). This way
490 494 you can reload the code in further invocations of %edit as a variable,
491 495 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
492 496 the output.
493 497
494 498 Note that %edit is also available through the alias %ed.
495 499
496 500 This is an example of creating a simple function inside the editor and
497 501 then modifying it. First, start up the editor::
498 502
499 503 In [1]: edit
500 504 Editing... done. Executing edited code...
501 505 Out[1]: 'def foo():\\n print "foo() was defined in an editing
502 506 session"\\n'
503 507
504 508 We can then call the function foo()::
505 509
506 510 In [2]: foo()
507 511 foo() was defined in an editing session
508 512
509 513 Now we edit foo. IPython automatically loads the editor with the
510 514 (temporary) file where foo() was previously defined::
511 515
512 516 In [3]: edit foo
513 517 Editing... done. Executing edited code...
514 518
515 519 And if we call foo() again we get the modified version::
516 520
517 521 In [4]: foo()
518 522 foo() has now been changed!
519 523
520 524 Here is an example of how to edit a code snippet successive
521 525 times. First we call the editor::
522 526
523 527 In [5]: edit
524 528 Editing... done. Executing edited code...
525 529 hello
526 530 Out[5]: "print 'hello'\\n"
527 531
528 532 Now we call it again with the previous output (stored in _)::
529 533
530 534 In [6]: edit _
531 535 Editing... done. Executing edited code...
532 536 hello world
533 537 Out[6]: "print 'hello world'\\n"
534 538
535 539 Now we call it with the output #8 (stored in _8, also as Out[8])::
536 540
537 541 In [7]: edit _8
538 542 Editing... done. Executing edited code...
539 543 hello again
540 544 Out[7]: "print 'hello again'\\n"
541 545
542 546
543 547 Changing the default editor hook:
544 548
545 549 If you wish to write your own editor hook, you can put it in a
546 550 configuration file which you load at startup time. The default hook
547 551 is defined in the IPython.core.hooks module, and you can use that as a
548 552 starting example for further modifications. That file also has
549 553 general instructions on how to set a new hook for use once you've
550 554 defined it."""
551 555 opts,args = self.parse_options(parameter_s,'prxn:')
552 556
553 557 try:
554 558 filename, lineno, is_temp = self._find_edit_target(self.shell,
555 559 args, opts, last_call)
556 560 except MacroToEdit as e:
557 561 self._edit_macro(args, e.args[0])
558 562 return
559 563 except InteractivelyDefined as e:
560 564 print "Editing In[%i]" % e.index
561 565 args = str(e.index)
562 566 filename, lineno, is_temp = self._find_edit_target(self.shell,
563 567 args, opts, last_call)
564 568 if filename is None:
565 569 # nothing was found, warnings have already been issued,
566 570 # just give up.
567 571 return
568 572
569 573 # do actual editing here
570 574 print 'Editing...',
571 575 sys.stdout.flush()
572 576 try:
573 577 # Quote filenames that may have spaces in them
574 578 if ' ' in filename:
575 579 filename = "'%s'" % filename
576 580 self.shell.hooks.editor(filename,lineno)
577 581 except TryNext:
578 582 warn('Could not open editor')
579 583 return
580 584
581 585 # XXX TODO: should this be generalized for all string vars?
582 586 # For now, this is special-cased to blocks created by cpaste
583 587 if args.strip() == 'pasted_block':
584 588 with open(filename, 'r') as f:
585 589 self.shell.user_ns['pasted_block'] = f.read()
586 590
587 591 if 'x' in opts: # -x prevents actual execution
588 592 print
589 593 else:
590 594 print 'done. Executing edited code...'
591 595 with preserve_keys(self.shell.user_ns, '__file__'):
592 596 if not is_temp:
593 597 self.shell.user_ns['__file__'] = filename
594 598 if 'r' in opts: # Untranslated IPython code
595 599 with open(filename, 'r') as f:
596 600 source = f.read()
597 601 self.shell.run_cell(source, store_history=False)
598 602 else:
599 603 self.shell.safe_execfile(filename, self.shell.user_ns,
600 604 self.shell.user_ns)
601 605
602 606 if is_temp:
603 607 try:
604 608 return open(filename).read()
605 609 except IOError as msg:
606 610 if msg.filename == filename:
607 611 warn('File not found. Did you forget to save?')
608 612 return
609 613 else:
610 614 self.shell.showtraceback()
General Comments 0
You need to be logged in to leave comments. Login now