##// END OF EJS Templates
convert sourcecode to unicode before colorizing in %pycat
Jörgen Stenarson -
Show More
@@ -1,724 +1,724 b''
1 1 """Implementation of magic functions for interaction with the OS.
2 2
3 3 Note: this module is named 'osm' instead of 'os' to avoid a collision with the
4 4 builtin.
5 5 """
6 6 #-----------------------------------------------------------------------------
7 7 # Copyright (c) 2012 The IPython Development Team.
8 8 #
9 9 # Distributed under the terms of the Modified BSD License.
10 10 #
11 11 # The full license is in the file COPYING.txt, distributed with this software.
12 12 #-----------------------------------------------------------------------------
13 13
14 14 #-----------------------------------------------------------------------------
15 15 # Imports
16 16 #-----------------------------------------------------------------------------
17 17
18 18 # Stdlib
19 19 import io
20 20 import os
21 21 import re
22 22 import sys
23 23 from pprint import pformat
24 24
25 25 # Our own packages
26 26 from IPython.core import magic_arguments
27 27 from IPython.core import oinspect
28 28 from IPython.core import page
29 29 from IPython.core.error import UsageError, StdinNotImplementedError
30 30 from IPython.core.magic import (
31 31 Magics, compress_dhist, magics_class, line_magic, cell_magic, line_cell_magic
32 32 )
33 33 from IPython.testing.skipdoctest import skip_doctest
34 from IPython.utils.io import file_read, nlprint
34 from IPython.utils.io import file_read, nlprint, source_to_unicode
35 35 from IPython.utils.path import get_py_filename, unquote_filename
36 36 from IPython.utils.process import abbrev_cwd
37 37 from IPython.utils.terminal import set_term_title
38 38 #-----------------------------------------------------------------------------
39 39 # Magic implementation classes
40 40 #-----------------------------------------------------------------------------
41 41 @magics_class
42 42 class OSMagics(Magics):
43 43 """Magics to interact with the underlying OS (shell-type functionality).
44 44 """
45 45
46 46 @skip_doctest
47 47 @line_magic
48 48 def alias(self, parameter_s=''):
49 49 """Define an alias for a system command.
50 50
51 51 '%alias alias_name cmd' defines 'alias_name' as an alias for 'cmd'
52 52
53 53 Then, typing 'alias_name params' will execute the system command 'cmd
54 54 params' (from your underlying operating system).
55 55
56 56 Aliases have lower precedence than magic functions and Python normal
57 57 variables, so if 'foo' is both a Python variable and an alias, the
58 58 alias can not be executed until 'del foo' removes the Python variable.
59 59
60 60 You can use the %l specifier in an alias definition to represent the
61 61 whole line when the alias is called. For example::
62 62
63 63 In [2]: alias bracket echo "Input in brackets: <%l>"
64 64 In [3]: bracket hello world
65 65 Input in brackets: <hello world>
66 66
67 67 You can also define aliases with parameters using %s specifiers (one
68 68 per parameter)::
69 69
70 70 In [1]: alias parts echo first %s second %s
71 71 In [2]: %parts A B
72 72 first A second B
73 73 In [3]: %parts A
74 74 Incorrect number of arguments: 2 expected.
75 75 parts is an alias to: 'echo first %s second %s'
76 76
77 77 Note that %l and %s are mutually exclusive. You can only use one or
78 78 the other in your aliases.
79 79
80 80 Aliases expand Python variables just like system calls using ! or !!
81 81 do: all expressions prefixed with '$' get expanded. For details of
82 82 the semantic rules, see PEP-215:
83 83 http://www.python.org/peps/pep-0215.html. This is the library used by
84 84 IPython for variable expansion. If you want to access a true shell
85 85 variable, an extra $ is necessary to prevent its expansion by
86 86 IPython::
87 87
88 88 In [6]: alias show echo
89 89 In [7]: PATH='A Python string'
90 90 In [8]: show $PATH
91 91 A Python string
92 92 In [9]: show $$PATH
93 93 /usr/local/lf9560/bin:/usr/local/intel/compiler70/ia32/bin:...
94 94
95 95 You can use the alias facility to acess all of $PATH. See the %rehash
96 96 and %rehashx functions, which automatically create aliases for the
97 97 contents of your $PATH.
98 98
99 99 If called with no parameters, %alias prints the current alias table."""
100 100
101 101 par = parameter_s.strip()
102 102 if not par:
103 103 aliases = sorted(self.shell.alias_manager.aliases)
104 104 # stored = self.shell.db.get('stored_aliases', {} )
105 105 # for k, v in stored:
106 106 # atab.append(k, v[0])
107 107
108 108 print "Total number of aliases:", len(aliases)
109 109 sys.stdout.flush()
110 110 return aliases
111 111
112 112 # Now try to define a new one
113 113 try:
114 114 alias,cmd = par.split(None, 1)
115 115 except:
116 116 print oinspect.getdoc(self.alias)
117 117 else:
118 118 self.shell.alias_manager.soft_define_alias(alias, cmd)
119 119 # end magic_alias
120 120
121 121 @line_magic
122 122 def unalias(self, parameter_s=''):
123 123 """Remove an alias"""
124 124
125 125 aname = parameter_s.strip()
126 126 self.shell.alias_manager.undefine_alias(aname)
127 127 stored = self.shell.db.get('stored_aliases', {} )
128 128 if aname in stored:
129 129 print "Removing %stored alias",aname
130 130 del stored[aname]
131 131 self.shell.db['stored_aliases'] = stored
132 132
133 133 @line_magic
134 134 def rehashx(self, parameter_s=''):
135 135 """Update the alias table with all executable files in $PATH.
136 136
137 137 This version explicitly checks that every entry in $PATH is a file
138 138 with execute access (os.X_OK), so it is much slower than %rehash.
139 139
140 140 Under Windows, it checks executability as a match against a
141 141 '|'-separated string of extensions, stored in the IPython config
142 142 variable win_exec_ext. This defaults to 'exe|com|bat'.
143 143
144 144 This function also resets the root module cache of module completer,
145 145 used on slow filesystems.
146 146 """
147 147 from IPython.core.alias import InvalidAliasError
148 148
149 149 # for the benefit of module completer in ipy_completers.py
150 150 del self.shell.db['rootmodules']
151 151
152 152 path = [os.path.abspath(os.path.expanduser(p)) for p in
153 153 os.environ.get('PATH','').split(os.pathsep)]
154 154 path = filter(os.path.isdir,path)
155 155
156 156 syscmdlist = []
157 157 # Now define isexec in a cross platform manner.
158 158 if os.name == 'posix':
159 159 isexec = lambda fname:os.path.isfile(fname) and \
160 160 os.access(fname,os.X_OK)
161 161 else:
162 162 try:
163 163 winext = os.environ['pathext'].replace(';','|').replace('.','')
164 164 except KeyError:
165 165 winext = 'exe|com|bat|py'
166 166 if 'py' not in winext:
167 167 winext += '|py'
168 168 execre = re.compile(r'(.*)\.(%s)$' % winext,re.IGNORECASE)
169 169 isexec = lambda fname:os.path.isfile(fname) and execre.match(fname)
170 170 savedir = os.getcwdu()
171 171
172 172 # Now walk the paths looking for executables to alias.
173 173 try:
174 174 # write the whole loop for posix/Windows so we don't have an if in
175 175 # the innermost part
176 176 if os.name == 'posix':
177 177 for pdir in path:
178 178 os.chdir(pdir)
179 179 for ff in os.listdir(pdir):
180 180 if isexec(ff):
181 181 try:
182 182 # Removes dots from the name since ipython
183 183 # will assume names with dots to be python.
184 184 self.shell.alias_manager.define_alias(
185 185 ff.replace('.',''), ff)
186 186 except InvalidAliasError:
187 187 pass
188 188 else:
189 189 syscmdlist.append(ff)
190 190 else:
191 191 no_alias = self.shell.alias_manager.no_alias
192 192 for pdir in path:
193 193 os.chdir(pdir)
194 194 for ff in os.listdir(pdir):
195 195 base, ext = os.path.splitext(ff)
196 196 if isexec(ff) and base.lower() not in no_alias:
197 197 if ext.lower() == '.exe':
198 198 ff = base
199 199 try:
200 200 # Removes dots from the name since ipython
201 201 # will assume names with dots to be python.
202 202 self.shell.alias_manager.define_alias(
203 203 base.lower().replace('.',''), ff)
204 204 except InvalidAliasError:
205 205 pass
206 206 syscmdlist.append(ff)
207 207 self.shell.db['syscmdlist'] = syscmdlist
208 208 finally:
209 209 os.chdir(savedir)
210 210
211 211 @skip_doctest
212 212 @line_magic
213 213 def pwd(self, parameter_s=''):
214 214 """Return the current working directory path.
215 215
216 216 Examples
217 217 --------
218 218 ::
219 219
220 220 In [9]: pwd
221 221 Out[9]: '/home/tsuser/sprint/ipython'
222 222 """
223 223 return os.getcwdu()
224 224
225 225 @skip_doctest
226 226 @line_magic
227 227 def cd(self, parameter_s=''):
228 228 """Change the current working directory.
229 229
230 230 This command automatically maintains an internal list of directories
231 231 you visit during your IPython session, in the variable _dh. The
232 232 command %dhist shows this history nicely formatted. You can also
233 233 do 'cd -<tab>' to see directory history conveniently.
234 234
235 235 Usage:
236 236
237 237 cd 'dir': changes to directory 'dir'.
238 238
239 239 cd -: changes to the last visited directory.
240 240
241 241 cd -<n>: changes to the n-th directory in the directory history.
242 242
243 243 cd --foo: change to directory that matches 'foo' in history
244 244
245 245 cd -b <bookmark_name>: jump to a bookmark set by %bookmark
246 246 (note: cd <bookmark_name> is enough if there is no
247 247 directory <bookmark_name>, but a bookmark with the name exists.)
248 248 'cd -b <tab>' allows you to tab-complete bookmark names.
249 249
250 250 Options:
251 251
252 252 -q: quiet. Do not print the working directory after the cd command is
253 253 executed. By default IPython's cd command does print this directory,
254 254 since the default prompts do not display path information.
255 255
256 256 Note that !cd doesn't work for this purpose because the shell where
257 257 !command runs is immediately discarded after executing 'command'.
258 258
259 259 Examples
260 260 --------
261 261 ::
262 262
263 263 In [10]: cd parent/child
264 264 /home/tsuser/parent/child
265 265 """
266 266
267 267 oldcwd = os.getcwdu()
268 268 numcd = re.match(r'(-)(\d+)$',parameter_s)
269 269 # jump in directory history by number
270 270 if numcd:
271 271 nn = int(numcd.group(2))
272 272 try:
273 273 ps = self.shell.user_ns['_dh'][nn]
274 274 except IndexError:
275 275 print 'The requested directory does not exist in history.'
276 276 return
277 277 else:
278 278 opts = {}
279 279 elif parameter_s.startswith('--'):
280 280 ps = None
281 281 fallback = None
282 282 pat = parameter_s[2:]
283 283 dh = self.shell.user_ns['_dh']
284 284 # first search only by basename (last component)
285 285 for ent in reversed(dh):
286 286 if pat in os.path.basename(ent) and os.path.isdir(ent):
287 287 ps = ent
288 288 break
289 289
290 290 if fallback is None and pat in ent and os.path.isdir(ent):
291 291 fallback = ent
292 292
293 293 # if we have no last part match, pick the first full path match
294 294 if ps is None:
295 295 ps = fallback
296 296
297 297 if ps is None:
298 298 print "No matching entry in directory history"
299 299 return
300 300 else:
301 301 opts = {}
302 302
303 303
304 304 else:
305 305 #turn all non-space-escaping backslashes to slashes,
306 306 # for c:\windows\directory\names\
307 307 parameter_s = re.sub(r'\\(?! )','/', parameter_s)
308 308 opts,ps = self.parse_options(parameter_s,'qb',mode='string')
309 309 # jump to previous
310 310 if ps == '-':
311 311 try:
312 312 ps = self.shell.user_ns['_dh'][-2]
313 313 except IndexError:
314 314 raise UsageError('%cd -: No previous directory to change to.')
315 315 # jump to bookmark if needed
316 316 else:
317 317 if not os.path.isdir(ps) or 'b' in opts:
318 318 bkms = self.shell.db.get('bookmarks', {})
319 319
320 320 if ps in bkms:
321 321 target = bkms[ps]
322 322 print '(bookmark:%s) -> %s' % (ps, target)
323 323 ps = target
324 324 else:
325 325 if 'b' in opts:
326 326 raise UsageError("Bookmark '%s' not found. "
327 327 "Use '%%bookmark -l' to see your bookmarks." % ps)
328 328
329 329 # strip extra quotes on Windows, because os.chdir doesn't like them
330 330 ps = unquote_filename(ps)
331 331 # at this point ps should point to the target dir
332 332 if ps:
333 333 try:
334 334 os.chdir(os.path.expanduser(ps))
335 335 if hasattr(self.shell, 'term_title') and self.shell.term_title:
336 336 set_term_title('IPython: ' + abbrev_cwd())
337 337 except OSError:
338 338 print sys.exc_info()[1]
339 339 else:
340 340 cwd = os.getcwdu()
341 341 dhist = self.shell.user_ns['_dh']
342 342 if oldcwd != cwd:
343 343 dhist.append(cwd)
344 344 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
345 345
346 346 else:
347 347 os.chdir(self.shell.home_dir)
348 348 if hasattr(self.shell, 'term_title') and self.shell.term_title:
349 349 set_term_title('IPython: ' + '~')
350 350 cwd = os.getcwdu()
351 351 dhist = self.shell.user_ns['_dh']
352 352
353 353 if oldcwd != cwd:
354 354 dhist.append(cwd)
355 355 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
356 356 if not 'q' in opts and self.shell.user_ns['_dh']:
357 357 print self.shell.user_ns['_dh'][-1]
358 358
359 359
360 360 @line_magic
361 361 def env(self, parameter_s=''):
362 362 """List environment variables."""
363 363
364 364 return dict(os.environ)
365 365
366 366 @line_magic
367 367 def pushd(self, parameter_s=''):
368 368 """Place the current dir on stack and change directory.
369 369
370 370 Usage:\\
371 371 %pushd ['dirname']
372 372 """
373 373
374 374 dir_s = self.shell.dir_stack
375 375 tgt = os.path.expanduser(unquote_filename(parameter_s))
376 376 cwd = os.getcwdu().replace(self.shell.home_dir,'~')
377 377 if tgt:
378 378 self.cd(parameter_s)
379 379 dir_s.insert(0,cwd)
380 380 return self.shell.magic('dirs')
381 381
382 382 @line_magic
383 383 def popd(self, parameter_s=''):
384 384 """Change to directory popped off the top of the stack.
385 385 """
386 386 if not self.shell.dir_stack:
387 387 raise UsageError("%popd on empty stack")
388 388 top = self.shell.dir_stack.pop(0)
389 389 self.cd(top)
390 390 print "popd ->",top
391 391
392 392 @line_magic
393 393 def dirs(self, parameter_s=''):
394 394 """Return the current directory stack."""
395 395
396 396 return self.shell.dir_stack
397 397
398 398 @line_magic
399 399 def dhist(self, parameter_s=''):
400 400 """Print your history of visited directories.
401 401
402 402 %dhist -> print full history\\
403 403 %dhist n -> print last n entries only\\
404 404 %dhist n1 n2 -> print entries between n1 and n2 (n1 not included)\\
405 405
406 406 This history is automatically maintained by the %cd command, and
407 407 always available as the global list variable _dh. You can use %cd -<n>
408 408 to go to directory number <n>.
409 409
410 410 Note that most of time, you should view directory history by entering
411 411 cd -<TAB>.
412 412
413 413 """
414 414
415 415 dh = self.shell.user_ns['_dh']
416 416 if parameter_s:
417 417 try:
418 418 args = map(int,parameter_s.split())
419 419 except:
420 420 self.arg_err(self.dhist)
421 421 return
422 422 if len(args) == 1:
423 423 ini,fin = max(len(dh)-(args[0]),0),len(dh)
424 424 elif len(args) == 2:
425 425 ini,fin = args
426 426 else:
427 427 self.arg_err(self.dhist)
428 428 return
429 429 else:
430 430 ini,fin = 0,len(dh)
431 431 nlprint(dh,
432 432 header = 'Directory history (kept in _dh)',
433 433 start=ini,stop=fin)
434 434
435 435 @skip_doctest
436 436 @line_magic
437 437 def sc(self, parameter_s=''):
438 438 """Shell capture - run shell command and capture output (DEPRECATED use !).
439 439
440 440 DEPRECATED. Suboptimal, retained for backwards compatibility.
441 441
442 442 You should use the form 'var = !command' instead. Example:
443 443
444 444 "%sc -l myfiles = ls ~" should now be written as
445 445
446 446 "myfiles = !ls ~"
447 447
448 448 myfiles.s, myfiles.l and myfiles.n still apply as documented
449 449 below.
450 450
451 451 --
452 452 %sc [options] varname=command
453 453
454 454 IPython will run the given command using commands.getoutput(), and
455 455 will then update the user's interactive namespace with a variable
456 456 called varname, containing the value of the call. Your command can
457 457 contain shell wildcards, pipes, etc.
458 458
459 459 The '=' sign in the syntax is mandatory, and the variable name you
460 460 supply must follow Python's standard conventions for valid names.
461 461
462 462 (A special format without variable name exists for internal use)
463 463
464 464 Options:
465 465
466 466 -l: list output. Split the output on newlines into a list before
467 467 assigning it to the given variable. By default the output is stored
468 468 as a single string.
469 469
470 470 -v: verbose. Print the contents of the variable.
471 471
472 472 In most cases you should not need to split as a list, because the
473 473 returned value is a special type of string which can automatically
474 474 provide its contents either as a list (split on newlines) or as a
475 475 space-separated string. These are convenient, respectively, either
476 476 for sequential processing or to be passed to a shell command.
477 477
478 478 For example::
479 479
480 480 # Capture into variable a
481 481 In [1]: sc a=ls *py
482 482
483 483 # a is a string with embedded newlines
484 484 In [2]: a
485 485 Out[2]: 'setup.py\\nwin32_manual_post_install.py'
486 486
487 487 # which can be seen as a list:
488 488 In [3]: a.l
489 489 Out[3]: ['setup.py', 'win32_manual_post_install.py']
490 490
491 491 # or as a whitespace-separated string:
492 492 In [4]: a.s
493 493 Out[4]: 'setup.py win32_manual_post_install.py'
494 494
495 495 # a.s is useful to pass as a single command line:
496 496 In [5]: !wc -l $a.s
497 497 146 setup.py
498 498 130 win32_manual_post_install.py
499 499 276 total
500 500
501 501 # while the list form is useful to loop over:
502 502 In [6]: for f in a.l:
503 503 ...: !wc -l $f
504 504 ...:
505 505 146 setup.py
506 506 130 win32_manual_post_install.py
507 507
508 508 Similarly, the lists returned by the -l option are also special, in
509 509 the sense that you can equally invoke the .s attribute on them to
510 510 automatically get a whitespace-separated string from their contents::
511 511
512 512 In [7]: sc -l b=ls *py
513 513
514 514 In [8]: b
515 515 Out[8]: ['setup.py', 'win32_manual_post_install.py']
516 516
517 517 In [9]: b.s
518 518 Out[9]: 'setup.py win32_manual_post_install.py'
519 519
520 520 In summary, both the lists and strings used for output capture have
521 521 the following special attributes::
522 522
523 523 .l (or .list) : value as list.
524 524 .n (or .nlstr): value as newline-separated string.
525 525 .s (or .spstr): value as space-separated string.
526 526 """
527 527
528 528 opts,args = self.parse_options(parameter_s, 'lv')
529 529 # Try to get a variable name and command to run
530 530 try:
531 531 # the variable name must be obtained from the parse_options
532 532 # output, which uses shlex.split to strip options out.
533 533 var,_ = args.split('=', 1)
534 534 var = var.strip()
535 535 # But the command has to be extracted from the original input
536 536 # parameter_s, not on what parse_options returns, to avoid the
537 537 # quote stripping which shlex.split performs on it.
538 538 _,cmd = parameter_s.split('=', 1)
539 539 except ValueError:
540 540 var,cmd = '',''
541 541 # If all looks ok, proceed
542 542 split = 'l' in opts
543 543 out = self.shell.getoutput(cmd, split=split)
544 544 if 'v' in opts:
545 545 print '%s ==\n%s' % (var, pformat(out))
546 546 if var:
547 547 self.shell.user_ns.update({var:out})
548 548 else:
549 549 return out
550 550
551 551 @line_cell_magic
552 552 def sx(self, line='', cell=None):
553 553 """Shell execute - run shell command and capture output (!! is short-hand).
554 554
555 555 %sx command
556 556
557 557 IPython will run the given command using commands.getoutput(), and
558 558 return the result formatted as a list (split on '\\n'). Since the
559 559 output is _returned_, it will be stored in ipython's regular output
560 560 cache Out[N] and in the '_N' automatic variables.
561 561
562 562 Notes:
563 563
564 564 1) If an input line begins with '!!', then %sx is automatically
565 565 invoked. That is, while::
566 566
567 567 !ls
568 568
569 569 causes ipython to simply issue system('ls'), typing::
570 570
571 571 !!ls
572 572
573 573 is a shorthand equivalent to::
574 574
575 575 %sx ls
576 576
577 577 2) %sx differs from %sc in that %sx automatically splits into a list,
578 578 like '%sc -l'. The reason for this is to make it as easy as possible
579 579 to process line-oriented shell output via further python commands.
580 580 %sc is meant to provide much finer control, but requires more
581 581 typing.
582 582
583 583 3) Just like %sc -l, this is a list with special attributes:
584 584 ::
585 585
586 586 .l (or .list) : value as list.
587 587 .n (or .nlstr): value as newline-separated string.
588 588 .s (or .spstr): value as whitespace-separated string.
589 589
590 590 This is very useful when trying to use such lists as arguments to
591 591 system commands."""
592 592
593 593 if cell is None:
594 594 # line magic
595 595 return self.shell.getoutput(line)
596 596 else:
597 597 opts,args = self.parse_options(line, '', 'out=')
598 598 output = self.shell.getoutput(cell)
599 599 out_name = opts.get('out', opts.get('o'))
600 600 if out_name:
601 601 self.shell.user_ns[out_name] = output
602 602 else:
603 603 return output
604 604
605 605 system = line_cell_magic('system')(sx)
606 606 bang = cell_magic('!')(sx)
607 607
608 608 @line_magic
609 609 def bookmark(self, parameter_s=''):
610 610 """Manage IPython's bookmark system.
611 611
612 612 %bookmark <name> - set bookmark to current dir
613 613 %bookmark <name> <dir> - set bookmark to <dir>
614 614 %bookmark -l - list all bookmarks
615 615 %bookmark -d <name> - remove bookmark
616 616 %bookmark -r - remove all bookmarks
617 617
618 618 You can later on access a bookmarked folder with::
619 619
620 620 %cd -b <name>
621 621
622 622 or simply '%cd <name>' if there is no directory called <name> AND
623 623 there is such a bookmark defined.
624 624
625 625 Your bookmarks persist through IPython sessions, but they are
626 626 associated with each profile."""
627 627
628 628 opts,args = self.parse_options(parameter_s,'drl',mode='list')
629 629 if len(args) > 2:
630 630 raise UsageError("%bookmark: too many arguments")
631 631
632 632 bkms = self.shell.db.get('bookmarks',{})
633 633
634 634 if 'd' in opts:
635 635 try:
636 636 todel = args[0]
637 637 except IndexError:
638 638 raise UsageError(
639 639 "%bookmark -d: must provide a bookmark to delete")
640 640 else:
641 641 try:
642 642 del bkms[todel]
643 643 except KeyError:
644 644 raise UsageError(
645 645 "%%bookmark -d: Can't delete bookmark '%s'" % todel)
646 646
647 647 elif 'r' in opts:
648 648 bkms = {}
649 649 elif 'l' in opts:
650 650 bks = bkms.keys()
651 651 bks.sort()
652 652 if bks:
653 653 size = max(map(len, bks))
654 654 else:
655 655 size = 0
656 656 fmt = '%-'+str(size)+'s -> %s'
657 657 print 'Current bookmarks:'
658 658 for bk in bks:
659 659 print fmt % (bk, bkms[bk])
660 660 else:
661 661 if not args:
662 662 raise UsageError("%bookmark: You must specify the bookmark name")
663 663 elif len(args)==1:
664 664 bkms[args[0]] = os.getcwdu()
665 665 elif len(args)==2:
666 666 bkms[args[0]] = args[1]
667 667 self.shell.db['bookmarks'] = bkms
668 668
669 669 @line_magic
670 670 def pycat(self, parameter_s=''):
671 671 """Show a syntax-highlighted file through a pager.
672 672
673 673 This magic is similar to the cat utility, but it will assume the file
674 674 to be Python source and will show it with syntax highlighting.
675 675
676 676 This magic command can either take a local filename, an url,
677 677 an history range (see %history) or a macro as argument ::
678 678
679 679 %pycat myscript.py
680 680 %pycat 7-27
681 681 %pycat myMacro
682 682 %pycat http://www.example.com/myscript.py
683 683 """
684 684 if not parameter_s:
685 685 raise UsageError('Missing filename, URL, input history range, '
686 686 'or macro.')
687 687
688 688 try :
689 689 cont = self.shell.find_user_code(parameter_s)
690 690 except (ValueError, IOError):
691 691 print "Error: no such file, variable, URL, history range or macro"
692 692 return
693 693
694 page.page(self.shell.pycolorize(cont))
694 page.page(self.shell.pycolorize(source_to_unicode(cont)))
695 695
696 696 @magic_arguments.magic_arguments()
697 697 @magic_arguments.argument(
698 698 '-a', '--amend', action='store_true', default=False,
699 699 help='Open file for amending if it exists'
700 700 )
701 701 @magic_arguments.argument(
702 702 'filename', type=unicode,
703 703 help='file to write'
704 704 )
705 705 @cell_magic
706 706 def file(self, line, cell):
707 707 """Write the contents of the cell to a file.
708 708
709 709 For frontends that do not support stdin (Notebook), -f is implied.
710 710 """
711 711 args = magic_arguments.parse_argstring(self.file, line)
712 712 filename = unquote_filename(args.filename)
713 713
714 714 if os.path.exists(filename):
715 715 if args.amend:
716 716 print "Amending to %s" % filename
717 717 else:
718 718 print "Overwriting %s" % filename
719 719 else:
720 720 print "Writing %s" % filename
721 721
722 722 mode = 'a' if args.amend else 'w'
723 723 with io.open(filename, mode, encoding='utf-8') as f:
724 724 f.write(cell)
@@ -1,384 +1,402 b''
1 1 # encoding: utf-8
2 2 """
3 3 IO related utilities.
4 4 """
5 5
6 6 #-----------------------------------------------------------------------------
7 7 # Copyright (C) 2008-2011 The IPython Development Team
8 8 #
9 9 # Distributed under the terms of the BSD License. The full license is in
10 10 # the file COPYING, distributed as part of this software.
11 11 #-----------------------------------------------------------------------------
12 12 from __future__ import print_function
13 13
14 14 #-----------------------------------------------------------------------------
15 15 # Imports
16 16 #-----------------------------------------------------------------------------
17 import re
17 18 import os
18 19 import sys
19 20 import tempfile
20 21 from StringIO import StringIO
21 22
22 23 #-----------------------------------------------------------------------------
23 24 # Code
24 25 #-----------------------------------------------------------------------------
25 26
26 27
27 28 class IOStream:
28 29
29 30 def __init__(self,stream, fallback=None):
30 31 if not hasattr(stream,'write') or not hasattr(stream,'flush'):
31 32 if fallback is not None:
32 33 stream = fallback
33 34 else:
34 35 raise ValueError("fallback required, but not specified")
35 36 self.stream = stream
36 37 self._swrite = stream.write
37 38
38 39 # clone all methods not overridden:
39 40 def clone(meth):
40 41 return not hasattr(self, meth) and not meth.startswith('_')
41 42 for meth in filter(clone, dir(stream)):
42 43 setattr(self, meth, getattr(stream, meth))
43 44
44 45 def write(self,data):
45 46 try:
46 47 self._swrite(data)
47 48 except:
48 49 try:
49 50 # print handles some unicode issues which may trip a plain
50 51 # write() call. Emulate write() by using an empty end
51 52 # argument.
52 53 print(data, end='', file=self.stream)
53 54 except:
54 55 # if we get here, something is seriously broken.
55 56 print('ERROR - failed to write data to stream:', self.stream,
56 57 file=sys.stderr)
57 58
58 59 def writelines(self, lines):
59 60 if isinstance(lines, basestring):
60 61 lines = [lines]
61 62 for line in lines:
62 63 self.write(line)
63 64
64 65 # This class used to have a writeln method, but regular files and streams
65 66 # in Python don't have this method. We need to keep this completely
66 67 # compatible so we removed it.
67 68
68 69 @property
69 70 def closed(self):
70 71 return self.stream.closed
71 72
72 73 def close(self):
73 74 pass
74 75
75 76 # setup stdin/stdout/stderr to sys.stdin/sys.stdout/sys.stderr
76 77 devnull = open(os.devnull, 'a')
77 78 stdin = IOStream(sys.stdin, fallback=devnull)
78 79 stdout = IOStream(sys.stdout, fallback=devnull)
79 80 stderr = IOStream(sys.stderr, fallback=devnull)
80 81
81 82 class IOTerm:
82 83 """ Term holds the file or file-like objects for handling I/O operations.
83 84
84 85 These are normally just sys.stdin, sys.stdout and sys.stderr but for
85 86 Windows they can can replaced to allow editing the strings before they are
86 87 displayed."""
87 88
88 89 # In the future, having IPython channel all its I/O operations through
89 90 # this class will make it easier to embed it into other environments which
90 91 # are not a normal terminal (such as a GUI-based shell)
91 92 def __init__(self, stdin=None, stdout=None, stderr=None):
92 93 mymodule = sys.modules[__name__]
93 94 self.stdin = IOStream(stdin, mymodule.stdin)
94 95 self.stdout = IOStream(stdout, mymodule.stdout)
95 96 self.stderr = IOStream(stderr, mymodule.stderr)
96 97
97 98
98 99 class Tee(object):
99 100 """A class to duplicate an output stream to stdout/err.
100 101
101 102 This works in a manner very similar to the Unix 'tee' command.
102 103
103 104 When the object is closed or deleted, it closes the original file given to
104 105 it for duplication.
105 106 """
106 107 # Inspired by:
107 108 # http://mail.python.org/pipermail/python-list/2007-May/442737.html
108 109
109 110 def __init__(self, file_or_name, mode="w", channel='stdout'):
110 111 """Construct a new Tee object.
111 112
112 113 Parameters
113 114 ----------
114 115 file_or_name : filename or open filehandle (writable)
115 116 File that will be duplicated
116 117
117 118 mode : optional, valid mode for open().
118 119 If a filename was give, open with this mode.
119 120
120 121 channel : str, one of ['stdout', 'stderr']
121 122 """
122 123 if channel not in ['stdout', 'stderr']:
123 124 raise ValueError('Invalid channel spec %s' % channel)
124 125
125 126 if hasattr(file_or_name, 'write') and hasattr(file_or_name, 'seek'):
126 127 self.file = file_or_name
127 128 else:
128 129 self.file = open(file_or_name, mode)
129 130 self.channel = channel
130 131 self.ostream = getattr(sys, channel)
131 132 setattr(sys, channel, self)
132 133 self._closed = False
133 134
134 135 def close(self):
135 136 """Close the file and restore the channel."""
136 137 self.flush()
137 138 setattr(sys, self.channel, self.ostream)
138 139 self.file.close()
139 140 self._closed = True
140 141
141 142 def write(self, data):
142 143 """Write data to both channels."""
143 144 self.file.write(data)
144 145 self.ostream.write(data)
145 146 self.ostream.flush()
146 147
147 148 def flush(self):
148 149 """Flush both channels."""
149 150 self.file.flush()
150 151 self.ostream.flush()
151 152
152 153 def __del__(self):
153 154 if not self._closed:
154 155 self.close()
155 156
156 157
158 def source_to_unicode(txt):
159 """Converts string with python source code to unicode
160 """
161 if isinstance(txt, unicode):
162 return txt
163
164 reg = re.compile("#.*coding[:=]\s*([-\w.]+)")
165 for row in txt.split("\n", 2)[:2]: #We only need to check the first two lines
166 result = reg.match(row)
167 if result:
168 coding = result.groups()[0]
169 break
170 else:
171 coding = "ascii"
172 return txt.decode(coding, errors="replace")
173
174
157 175 def file_read(filename):
158 176 """Read a file and close it. Returns the file source."""
159 177 fobj = open(filename,'r');
160 178 source = fobj.read();
161 179 fobj.close()
162 180 return source
163 181
164 182
165 183 def file_readlines(filename):
166 184 """Read a file and close it. Returns the file source using readlines()."""
167 185 fobj = open(filename,'r');
168 186 lines = fobj.readlines();
169 187 fobj.close()
170 188 return lines
171 189
172 190
173 191 def raw_input_multi(header='', ps1='==> ', ps2='..> ',terminate_str = '.'):
174 192 """Take multiple lines of input.
175 193
176 194 A list with each line of input as a separate element is returned when a
177 195 termination string is entered (defaults to a single '.'). Input can also
178 196 terminate via EOF (^D in Unix, ^Z-RET in Windows).
179 197
180 198 Lines of input which end in \\ are joined into single entries (and a
181 199 secondary continuation prompt is issued as long as the user terminates
182 200 lines with \\). This allows entering very long strings which are still
183 201 meant to be treated as single entities.
184 202 """
185 203
186 204 try:
187 205 if header:
188 206 header += '\n'
189 207 lines = [raw_input(header + ps1)]
190 208 except EOFError:
191 209 return []
192 210 terminate = [terminate_str]
193 211 try:
194 212 while lines[-1:] != terminate:
195 213 new_line = raw_input(ps1)
196 214 while new_line.endswith('\\'):
197 215 new_line = new_line[:-1] + raw_input(ps2)
198 216 lines.append(new_line)
199 217
200 218 return lines[:-1] # don't return the termination command
201 219 except EOFError:
202 220 print()
203 221 return lines
204 222
205 223
206 224 def raw_input_ext(prompt='', ps2='... '):
207 225 """Similar to raw_input(), but accepts extended lines if input ends with \\."""
208 226
209 227 line = raw_input(prompt)
210 228 while line.endswith('\\'):
211 229 line = line[:-1] + raw_input(ps2)
212 230 return line
213 231
214 232
215 233 def ask_yes_no(prompt,default=None):
216 234 """Asks a question and returns a boolean (y/n) answer.
217 235
218 236 If default is given (one of 'y','n'), it is used if the user input is
219 237 empty. Otherwise the question is repeated until an answer is given.
220 238
221 239 An EOF is treated as the default answer. If there is no default, an
222 240 exception is raised to prevent infinite loops.
223 241
224 242 Valid answers are: y/yes/n/no (match is not case sensitive)."""
225 243
226 244 answers = {'y':True,'n':False,'yes':True,'no':False}
227 245 ans = None
228 246 while ans not in answers.keys():
229 247 try:
230 248 ans = raw_input(prompt+' ').lower()
231 249 if not ans: # response was an empty string
232 250 ans = default
233 251 except KeyboardInterrupt:
234 252 pass
235 253 except EOFError:
236 254 if default in answers.keys():
237 255 ans = default
238 256 print()
239 257 else:
240 258 raise
241 259
242 260 return answers[ans]
243 261
244 262
245 263 class NLprinter:
246 264 """Print an arbitrarily nested list, indicating index numbers.
247 265
248 266 An instance of this class called nlprint is available and callable as a
249 267 function.
250 268
251 269 nlprint(list,indent=' ',sep=': ') -> prints indenting each level by 'indent'
252 270 and using 'sep' to separate the index from the value. """
253 271
254 272 def __init__(self):
255 273 self.depth = 0
256 274
257 275 def __call__(self,lst,pos='',**kw):
258 276 """Prints the nested list numbering levels."""
259 277 kw.setdefault('indent',' ')
260 278 kw.setdefault('sep',': ')
261 279 kw.setdefault('start',0)
262 280 kw.setdefault('stop',len(lst))
263 281 # we need to remove start and stop from kw so they don't propagate
264 282 # into a recursive call for a nested list.
265 283 start = kw['start']; del kw['start']
266 284 stop = kw['stop']; del kw['stop']
267 285 if self.depth == 0 and 'header' in kw.keys():
268 286 print(kw['header'])
269 287
270 288 for idx in range(start,stop):
271 289 elem = lst[idx]
272 290 newpos = pos + str(idx)
273 291 if type(elem)==type([]):
274 292 self.depth += 1
275 293 self.__call__(elem, newpos+",", **kw)
276 294 self.depth -= 1
277 295 else:
278 296 print(kw['indent']*self.depth + newpos + kw["sep"] + repr(elem))
279 297
280 298 nlprint = NLprinter()
281 299
282 300
283 301 def temp_pyfile(src, ext='.py'):
284 302 """Make a temporary python file, return filename and filehandle.
285 303
286 304 Parameters
287 305 ----------
288 306 src : string or list of strings (no need for ending newlines if list)
289 307 Source code to be written to the file.
290 308
291 309 ext : optional, string
292 310 Extension for the generated file.
293 311
294 312 Returns
295 313 -------
296 314 (filename, open filehandle)
297 315 It is the caller's responsibility to close the open file and unlink it.
298 316 """
299 317 fname = tempfile.mkstemp(ext)[1]
300 318 f = open(fname,'w')
301 319 f.write(src)
302 320 f.flush()
303 321 return fname, f
304 322
305 323
306 324 def raw_print(*args, **kw):
307 325 """Raw print to sys.__stdout__, otherwise identical interface to print()."""
308 326
309 327 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
310 328 file=sys.__stdout__)
311 329 sys.__stdout__.flush()
312 330
313 331
314 332 def raw_print_err(*args, **kw):
315 333 """Raw print to sys.__stderr__, otherwise identical interface to print()."""
316 334
317 335 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
318 336 file=sys.__stderr__)
319 337 sys.__stderr__.flush()
320 338
321 339
322 340 # Short aliases for quick debugging, do NOT use these in production code.
323 341 rprint = raw_print
324 342 rprinte = raw_print_err
325 343
326 344
327 345 class CapturedIO(object):
328 346 """Simple object for containing captured stdout/err StringIO objects"""
329 347
330 348 def __init__(self, stdout, stderr):
331 349 self._stdout = stdout
332 350 self._stderr = stderr
333 351
334 352 def __str__(self):
335 353 return self.stdout
336 354
337 355 @property
338 356 def stdout(self):
339 357 if not self._stdout:
340 358 return ''
341 359 return self._stdout.getvalue()
342 360
343 361 @property
344 362 def stderr(self):
345 363 if not self._stderr:
346 364 return ''
347 365 return self._stderr.getvalue()
348 366
349 367 def show(self):
350 368 """write my output to sys.stdout/err as appropriate"""
351 369 sys.stdout.write(self.stdout)
352 370 sys.stderr.write(self.stderr)
353 371 sys.stdout.flush()
354 372 sys.stderr.flush()
355 373
356 374 __call__ = show
357 375
358 376
359 377 class capture_output(object):
360 378 """context manager for capturing stdout/err"""
361 379 stdout = True
362 380 stderr = True
363 381
364 382 def __init__(self, stdout=True, stderr=True):
365 383 self.stdout = stdout
366 384 self.stderr = stderr
367 385
368 386 def __enter__(self):
369 387 self.sys_stdout = sys.stdout
370 388 self.sys_stderr = sys.stderr
371 389
372 390 stdout = stderr = False
373 391 if self.stdout:
374 392 stdout = sys.stdout = StringIO()
375 393 if self.stderr:
376 394 stderr = sys.stderr = StringIO()
377 395
378 396 return CapturedIO(stdout, stderr)
379 397
380 398 def __exit__(self, exc_type, exc_value, traceback):
381 399 sys.stdout = self.sys_stdout
382 400 sys.stderr = self.sys_stderr
383 401
384 402
General Comments 0
You need to be logged in to leave comments. Login now