##// END OF EJS Templates
Merge pull request #12343 from btel/patch-1...
Matthias Bussonnier -
r25774:5886f9a3 merge
parent child Browse files
Show More
@@ -1,849 +1,849 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 # Copyright (c) IPython Development Team.
7 7 # Distributed under the terms of the Modified BSD License.
8 8
9 9 import io
10 10 import os
11 11 import re
12 12 import sys
13 13 from pprint import pformat
14 14
15 15 from IPython.core import magic_arguments
16 16 from IPython.core import oinspect
17 17 from IPython.core import page
18 18 from IPython.core.alias import AliasError, Alias
19 19 from IPython.core.error import UsageError
20 20 from IPython.core.magic import (
21 21 Magics, compress_dhist, magics_class, line_magic, cell_magic, line_cell_magic
22 22 )
23 23 from IPython.testing.skipdoctest import skip_doctest
24 24 from IPython.utils.openpy import source_to_unicode
25 25 from IPython.utils.process import abbrev_cwd
26 26 from IPython.utils.terminal import set_term_title
27 27 from traitlets import Bool
28 28
29 29
30 30 @magics_class
31 31 class OSMagics(Magics):
32 32 """Magics to interact with the underlying OS (shell-type functionality).
33 33 """
34 34
35 35 cd_force_quiet = Bool(False,
36 36 help="Force %cd magic to be quiet even if -q is not passed."
37 37 ).tag(config=True)
38 38
39 39 def __init__(self, shell=None, **kwargs):
40 40
41 41 # Now define isexec in a cross platform manner.
42 42 self.is_posix = False
43 43 self.execre = None
44 44 if os.name == 'posix':
45 45 self.is_posix = True
46 46 else:
47 47 try:
48 48 winext = os.environ['pathext'].replace(';','|').replace('.','')
49 49 except KeyError:
50 50 winext = 'exe|com|bat|py'
51 51
52 52 self.execre = re.compile(r'(.*)\.(%s)$' % winext,re.IGNORECASE)
53 53
54 54 # call up the chain
55 55 super().__init__(shell=shell, **kwargs)
56 56
57 57
58 58 @skip_doctest
59 59 def _isexec_POSIX(self, file):
60 60 """
61 61 Test for executable on a POSIX system
62 62 """
63 63 if os.access(file.path, os.X_OK):
64 64 # will fail on maxOS if access is not X_OK
65 65 return file.is_file()
66 66 return False
67 67
68 68
69 69
70 70 @skip_doctest
71 71 def _isexec_WIN(self, file):
72 72 """
73 73 Test for executable file on non POSIX system
74 74 """
75 75 return file.is_file() and self.execre.match(file.name) is not None
76 76
77 77 @skip_doctest
78 78 def isexec(self, file):
79 79 """
80 80 Test for executable file on non POSIX system
81 81 """
82 82 if self.is_posix:
83 83 return self._isexec_POSIX(file)
84 84 else:
85 85 return self._isexec_WIN(file)
86 86
87 87
88 88 @skip_doctest
89 89 @line_magic
90 90 def alias(self, parameter_s=''):
91 91 """Define an alias for a system command.
92 92
93 93 '%alias alias_name cmd' defines 'alias_name' as an alias for 'cmd'
94 94
95 95 Then, typing 'alias_name params' will execute the system command 'cmd
96 96 params' (from your underlying operating system).
97 97
98 98 Aliases have lower precedence than magic functions and Python normal
99 99 variables, so if 'foo' is both a Python variable and an alias, the
100 100 alias can not be executed until 'del foo' removes the Python variable.
101 101
102 102 You can use the %l specifier in an alias definition to represent the
103 103 whole line when the alias is called. For example::
104 104
105 105 In [2]: alias bracket echo "Input in brackets: <%l>"
106 106 In [3]: bracket hello world
107 107 Input in brackets: <hello world>
108 108
109 109 You can also define aliases with parameters using %s specifiers (one
110 110 per parameter)::
111 111
112 112 In [1]: alias parts echo first %s second %s
113 113 In [2]: %parts A B
114 114 first A second B
115 115 In [3]: %parts A
116 116 Incorrect number of arguments: 2 expected.
117 117 parts is an alias to: 'echo first %s second %s'
118 118
119 119 Note that %l and %s are mutually exclusive. You can only use one or
120 120 the other in your aliases.
121 121
122 122 Aliases expand Python variables just like system calls using ! or !!
123 123 do: all expressions prefixed with '$' get expanded. For details of
124 124 the semantic rules, see PEP-215:
125 125 http://www.python.org/peps/pep-0215.html. This is the library used by
126 126 IPython for variable expansion. If you want to access a true shell
127 127 variable, an extra $ is necessary to prevent its expansion by
128 128 IPython::
129 129
130 130 In [6]: alias show echo
131 131 In [7]: PATH='A Python string'
132 132 In [8]: show $PATH
133 133 A Python string
134 134 In [9]: show $$PATH
135 135 /usr/local/lf9560/bin:/usr/local/intel/compiler70/ia32/bin:...
136 136
137 137 You can use the alias facility to access all of $PATH. See the %rehashx
138 138 function, which automatically creates aliases for the contents of your
139 139 $PATH.
140 140
141 141 If called with no parameters, %alias prints the current alias table
142 142 for your system. For posix systems, the default aliases are 'cat',
143 143 'cp', 'mv', 'rm', 'rmdir', and 'mkdir', and other platform-specific
144 144 aliases are added. For windows-based systems, the default aliases are
145 145 'copy', 'ddir', 'echo', 'ls', 'ldir', 'mkdir', 'ren', and 'rmdir'.
146 146
147 147 You can see the definition of alias by adding a question mark in the
148 148 end::
149 149
150 150 In [1]: cat?
151 151 Repr: <alias cat for 'cat'>"""
152 152
153 153 par = parameter_s.strip()
154 154 if not par:
155 155 aliases = sorted(self.shell.alias_manager.aliases)
156 156 # stored = self.shell.db.get('stored_aliases', {} )
157 157 # for k, v in stored:
158 158 # atab.append(k, v[0])
159 159
160 160 print("Total number of aliases:", len(aliases))
161 161 sys.stdout.flush()
162 162 return aliases
163 163
164 164 # Now try to define a new one
165 165 try:
166 166 alias,cmd = par.split(None, 1)
167 167 except TypeError:
168 168 print(oinspect.getdoc(self.alias))
169 169 return
170 170
171 171 try:
172 172 self.shell.alias_manager.define_alias(alias, cmd)
173 173 except AliasError as e:
174 174 print(e)
175 175 # end magic_alias
176 176
177 177 @line_magic
178 178 def unalias(self, parameter_s=''):
179 179 """Remove an alias"""
180 180
181 181 aname = parameter_s.strip()
182 182 try:
183 183 self.shell.alias_manager.undefine_alias(aname)
184 184 except ValueError as e:
185 185 print(e)
186 186 return
187 187
188 188 stored = self.shell.db.get('stored_aliases', {} )
189 189 if aname in stored:
190 190 print("Removing %stored alias",aname)
191 191 del stored[aname]
192 192 self.shell.db['stored_aliases'] = stored
193 193
194 194 @line_magic
195 195 def rehashx(self, parameter_s=''):
196 196 """Update the alias table with all executable files in $PATH.
197 197
198 198 rehashx explicitly checks that every entry in $PATH is a file
199 199 with execute access (os.X_OK).
200 200
201 201 Under Windows, it checks executability as a match against a
202 202 '|'-separated string of extensions, stored in the IPython config
203 203 variable win_exec_ext. This defaults to 'exe|com|bat'.
204 204
205 205 This function also resets the root module cache of module completer,
206 206 used on slow filesystems.
207 207 """
208 208 from IPython.core.alias import InvalidAliasError
209 209
210 210 # for the benefit of module completer in ipy_completers.py
211 211 del self.shell.db['rootmodules_cache']
212 212
213 213 path = [os.path.abspath(os.path.expanduser(p)) for p in
214 214 os.environ.get('PATH','').split(os.pathsep)]
215 215
216 216 syscmdlist = []
217 217 savedir = os.getcwd()
218 218
219 219 # Now walk the paths looking for executables to alias.
220 220 try:
221 221 # write the whole loop for posix/Windows so we don't have an if in
222 222 # the innermost part
223 223 if self.is_posix:
224 224 for pdir in path:
225 225 try:
226 226 os.chdir(pdir)
227 227 except OSError:
228 228 continue
229 229
230 230 # for python 3.6+ rewrite to: with os.scandir(pdir) as dirlist:
231 231 dirlist = os.scandir(path=pdir)
232 232 for ff in dirlist:
233 233 if self.isexec(ff):
234 234 fname = ff.name
235 235 try:
236 236 # Removes dots from the name since ipython
237 237 # will assume names with dots to be python.
238 238 if not self.shell.alias_manager.is_alias(fname):
239 239 self.shell.alias_manager.define_alias(
240 240 fname.replace('.',''), fname)
241 241 except InvalidAliasError:
242 242 pass
243 243 else:
244 244 syscmdlist.append(fname)
245 245 else:
246 246 no_alias = Alias.blacklist
247 247 for pdir in path:
248 248 try:
249 249 os.chdir(pdir)
250 250 except OSError:
251 251 continue
252 252
253 253 # for python 3.6+ rewrite to: with os.scandir(pdir) as dirlist:
254 254 dirlist = os.scandir(pdir)
255 255 for ff in dirlist:
256 256 fname = ff.name
257 257 base, ext = os.path.splitext(fname)
258 258 if self.isexec(ff) and base.lower() not in no_alias:
259 259 if ext.lower() == '.exe':
260 260 fname = base
261 261 try:
262 262 # Removes dots from the name since ipython
263 263 # will assume names with dots to be python.
264 264 self.shell.alias_manager.define_alias(
265 265 base.lower().replace('.',''), fname)
266 266 except InvalidAliasError:
267 267 pass
268 268 syscmdlist.append(fname)
269 269
270 270 self.shell.db['syscmdlist'] = syscmdlist
271 271 finally:
272 272 os.chdir(savedir)
273 273
274 274 @skip_doctest
275 275 @line_magic
276 276 def pwd(self, parameter_s=''):
277 277 """Return the current working directory path.
278 278
279 279 Examples
280 280 --------
281 281 ::
282 282
283 283 In [9]: pwd
284 284 Out[9]: '/home/tsuser/sprint/ipython'
285 285 """
286 286 try:
287 287 return os.getcwd()
288 288 except FileNotFoundError:
289 289 raise UsageError("CWD no longer exists - please use %cd to change directory.")
290 290
291 291 @skip_doctest
292 292 @line_magic
293 293 def cd(self, parameter_s=''):
294 294 """Change the current working directory.
295 295
296 296 This command automatically maintains an internal list of directories
297 297 you visit during your IPython session, in the variable _dh. The
298 298 command %dhist shows this history nicely formatted. You can also
299 299 do 'cd -<tab>' to see directory history conveniently.
300 300
301 301 Usage:
302 302
303 303 cd 'dir': changes to directory 'dir'.
304 304
305 305 cd -: changes to the last visited directory.
306 306
307 307 cd -<n>: changes to the n-th directory in the directory history.
308 308
309 309 cd --foo: change to directory that matches 'foo' in history
310 310
311 311 cd -b <bookmark_name>: jump to a bookmark set by %bookmark
312 312 (note: cd <bookmark_name> is enough if there is no
313 313 directory <bookmark_name>, but a bookmark with the name exists.)
314 314 'cd -b <tab>' allows you to tab-complete bookmark names.
315 315
316 316 Options:
317 317
318 318 -q: quiet. Do not print the working directory after the cd command is
319 319 executed. By default IPython's cd command does print this directory,
320 320 since the default prompts do not display path information.
321 321
322 322 Note that !cd doesn't work for this purpose because the shell where
323 323 !command runs is immediately discarded after executing 'command'.
324 324
325 325 Examples
326 326 --------
327 327 ::
328 328
329 329 In [10]: cd parent/child
330 330 /home/tsuser/parent/child
331 331 """
332 332
333 333 try:
334 334 oldcwd = os.getcwd()
335 335 except FileNotFoundError:
336 336 # Happens if the CWD has been deleted.
337 337 oldcwd = None
338 338
339 339 numcd = re.match(r'(-)(\d+)$',parameter_s)
340 340 # jump in directory history by number
341 341 if numcd:
342 342 nn = int(numcd.group(2))
343 343 try:
344 344 ps = self.shell.user_ns['_dh'][nn]
345 345 except IndexError:
346 346 print('The requested directory does not exist in history.')
347 347 return
348 348 else:
349 349 opts = {}
350 350 elif parameter_s.startswith('--'):
351 351 ps = None
352 352 fallback = None
353 353 pat = parameter_s[2:]
354 354 dh = self.shell.user_ns['_dh']
355 355 # first search only by basename (last component)
356 356 for ent in reversed(dh):
357 357 if pat in os.path.basename(ent) and os.path.isdir(ent):
358 358 ps = ent
359 359 break
360 360
361 361 if fallback is None and pat in ent and os.path.isdir(ent):
362 362 fallback = ent
363 363
364 364 # if we have no last part match, pick the first full path match
365 365 if ps is None:
366 366 ps = fallback
367 367
368 368 if ps is None:
369 369 print("No matching entry in directory history")
370 370 return
371 371 else:
372 372 opts = {}
373 373
374 374
375 375 else:
376 376 opts, ps = self.parse_options(parameter_s, 'qb', mode='string')
377 377 # jump to previous
378 378 if ps == '-':
379 379 try:
380 380 ps = self.shell.user_ns['_dh'][-2]
381 381 except IndexError:
382 382 raise UsageError('%cd -: No previous directory to change to.')
383 383 # jump to bookmark if needed
384 384 else:
385 385 if not os.path.isdir(ps) or 'b' in opts:
386 386 bkms = self.shell.db.get('bookmarks', {})
387 387
388 388 if ps in bkms:
389 389 target = bkms[ps]
390 390 print('(bookmark:%s) -> %s' % (ps, target))
391 391 ps = target
392 392 else:
393 393 if 'b' in opts:
394 394 raise UsageError("Bookmark '%s' not found. "
395 395 "Use '%%bookmark -l' to see your bookmarks." % ps)
396 396
397 397 # at this point ps should point to the target dir
398 398 if ps:
399 399 try:
400 400 os.chdir(os.path.expanduser(ps))
401 401 if hasattr(self.shell, 'term_title') and self.shell.term_title:
402 402 set_term_title(self.shell.term_title_format.format(cwd=abbrev_cwd()))
403 403 except OSError:
404 404 print(sys.exc_info()[1])
405 405 else:
406 406 cwd = os.getcwd()
407 407 dhist = self.shell.user_ns['_dh']
408 408 if oldcwd != cwd:
409 409 dhist.append(cwd)
410 410 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
411 411
412 412 else:
413 413 os.chdir(self.shell.home_dir)
414 414 if hasattr(self.shell, 'term_title') and self.shell.term_title:
415 415 set_term_title(self.shell.term_title_format.format(cwd="~"))
416 416 cwd = os.getcwd()
417 417 dhist = self.shell.user_ns['_dh']
418 418
419 419 if oldcwd != cwd:
420 420 dhist.append(cwd)
421 421 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
422 422 if not 'q' in opts and not self.cd_force_quiet and self.shell.user_ns['_dh']:
423 423 print(self.shell.user_ns['_dh'][-1])
424 424
425 425 @line_magic
426 426 def env(self, parameter_s=''):
427 427 """Get, set, or list environment variables.
428 428
429 429 Usage:\\
430 430
431 431 %env: lists all environment variables/values
432 432 %env var: get value for var
433 433 %env var val: set value for var
434 434 %env var=val: set value for var
435 435 %env var=$val: set value for var, using python expansion if possible
436 436 """
437 437 if parameter_s.strip():
438 438 split = '=' if '=' in parameter_s else ' '
439 439 bits = parameter_s.split(split)
440 440 if len(bits) == 1:
441 441 key = parameter_s.strip()
442 442 if key in os.environ:
443 443 return os.environ[key]
444 444 else:
445 445 err = "Environment does not have key: {0}".format(key)
446 446 raise UsageError(err)
447 447 if len(bits) > 1:
448 448 return self.set_env(parameter_s)
449 449 env = dict(os.environ)
450 450 # hide likely secrets when printing the whole environment
451 451 for key in list(env):
452 452 if any(s in key.lower() for s in ('key', 'token', 'secret')):
453 453 env[key] = '<hidden>'
454 454
455 455 return env
456 456
457 457 @line_magic
458 458 def set_env(self, parameter_s):
459 459 """Set environment variables. Assumptions are that either "val" is a
460 460 name in the user namespace, or val is something that evaluates to a
461 461 string.
462 462
463 463 Usage:\\
464 464 %set_env var val: set value for var
465 465 %set_env var=val: set value for var
466 466 %set_env var=$val: set value for var, using python expansion if possible
467 467 """
468 468 split = '=' if '=' in parameter_s else ' '
469 469 bits = parameter_s.split(split, 1)
470 470 if not parameter_s.strip() or len(bits)<2:
471 471 raise UsageError("usage is 'set_env var=val'")
472 472 var = bits[0].strip()
473 473 val = bits[1].strip()
474 474 if re.match(r'.*\s.*', var):
475 475 # an environment variable with whitespace is almost certainly
476 476 # not what the user intended. what's more likely is the wrong
477 477 # split was chosen, ie for "set_env cmd_args A=B", we chose
478 478 # '=' for the split and should have chosen ' '. to get around
479 479 # this, users should just assign directly to os.environ or use
480 480 # standard magic {var} expansion.
481 481 err = "refusing to set env var with whitespace: '{0}'"
482 482 err = err.format(val)
483 483 raise UsageError(err)
484 484 os.environ[var] = val
485 485 print('env: {0}={1}'.format(var,val))
486 486
487 487 @line_magic
488 488 def pushd(self, parameter_s=''):
489 489 """Place the current dir on stack and change directory.
490 490
491 491 Usage:\\
492 492 %pushd ['dirname']
493 493 """
494 494
495 495 dir_s = self.shell.dir_stack
496 496 tgt = os.path.expanduser(parameter_s)
497 497 cwd = os.getcwd().replace(self.shell.home_dir,'~')
498 498 if tgt:
499 499 self.cd(parameter_s)
500 500 dir_s.insert(0,cwd)
501 return self.shell.magic('dirs')
501 return self.shell.run_line_magic('dirs', '')
502 502
503 503 @line_magic
504 504 def popd(self, parameter_s=''):
505 505 """Change to directory popped off the top of the stack.
506 506 """
507 507 if not self.shell.dir_stack:
508 508 raise UsageError("%popd on empty stack")
509 509 top = self.shell.dir_stack.pop(0)
510 510 self.cd(top)
511 511 print("popd ->",top)
512 512
513 513 @line_magic
514 514 def dirs(self, parameter_s=''):
515 515 """Return the current directory stack."""
516 516
517 517 return self.shell.dir_stack
518 518
519 519 @line_magic
520 520 def dhist(self, parameter_s=''):
521 521 """Print your history of visited directories.
522 522
523 523 %dhist -> print full history\\
524 524 %dhist n -> print last n entries only\\
525 525 %dhist n1 n2 -> print entries between n1 and n2 (n2 not included)\\
526 526
527 527 This history is automatically maintained by the %cd command, and
528 528 always available as the global list variable _dh. You can use %cd -<n>
529 529 to go to directory number <n>.
530 530
531 531 Note that most of time, you should view directory history by entering
532 532 cd -<TAB>.
533 533
534 534 """
535 535
536 536 dh = self.shell.user_ns['_dh']
537 537 if parameter_s:
538 538 try:
539 539 args = map(int,parameter_s.split())
540 540 except:
541 541 self.arg_err(self.dhist)
542 542 return
543 543 if len(args) == 1:
544 544 ini,fin = max(len(dh)-(args[0]),0),len(dh)
545 545 elif len(args) == 2:
546 546 ini,fin = args
547 547 fin = min(fin, len(dh))
548 548 else:
549 549 self.arg_err(self.dhist)
550 550 return
551 551 else:
552 552 ini,fin = 0,len(dh)
553 553 print('Directory history (kept in _dh)')
554 554 for i in range(ini, fin):
555 555 print("%d: %s" % (i, dh[i]))
556 556
557 557 @skip_doctest
558 558 @line_magic
559 559 def sc(self, parameter_s=''):
560 560 """Shell capture - run shell command and capture output (DEPRECATED use !).
561 561
562 562 DEPRECATED. Suboptimal, retained for backwards compatibility.
563 563
564 564 You should use the form 'var = !command' instead. Example:
565 565
566 566 "%sc -l myfiles = ls ~" should now be written as
567 567
568 568 "myfiles = !ls ~"
569 569
570 570 myfiles.s, myfiles.l and myfiles.n still apply as documented
571 571 below.
572 572
573 573 --
574 574 %sc [options] varname=command
575 575
576 576 IPython will run the given command using commands.getoutput(), and
577 577 will then update the user's interactive namespace with a variable
578 578 called varname, containing the value of the call. Your command can
579 579 contain shell wildcards, pipes, etc.
580 580
581 581 The '=' sign in the syntax is mandatory, and the variable name you
582 582 supply must follow Python's standard conventions for valid names.
583 583
584 584 (A special format without variable name exists for internal use)
585 585
586 586 Options:
587 587
588 588 -l: list output. Split the output on newlines into a list before
589 589 assigning it to the given variable. By default the output is stored
590 590 as a single string.
591 591
592 592 -v: verbose. Print the contents of the variable.
593 593
594 594 In most cases you should not need to split as a list, because the
595 595 returned value is a special type of string which can automatically
596 596 provide its contents either as a list (split on newlines) or as a
597 597 space-separated string. These are convenient, respectively, either
598 598 for sequential processing or to be passed to a shell command.
599 599
600 600 For example::
601 601
602 602 # Capture into variable a
603 603 In [1]: sc a=ls *py
604 604
605 605 # a is a string with embedded newlines
606 606 In [2]: a
607 607 Out[2]: 'setup.py\\nwin32_manual_post_install.py'
608 608
609 609 # which can be seen as a list:
610 610 In [3]: a.l
611 611 Out[3]: ['setup.py', 'win32_manual_post_install.py']
612 612
613 613 # or as a whitespace-separated string:
614 614 In [4]: a.s
615 615 Out[4]: 'setup.py win32_manual_post_install.py'
616 616
617 617 # a.s is useful to pass as a single command line:
618 618 In [5]: !wc -l $a.s
619 619 146 setup.py
620 620 130 win32_manual_post_install.py
621 621 276 total
622 622
623 623 # while the list form is useful to loop over:
624 624 In [6]: for f in a.l:
625 625 ...: !wc -l $f
626 626 ...:
627 627 146 setup.py
628 628 130 win32_manual_post_install.py
629 629
630 630 Similarly, the lists returned by the -l option are also special, in
631 631 the sense that you can equally invoke the .s attribute on them to
632 632 automatically get a whitespace-separated string from their contents::
633 633
634 634 In [7]: sc -l b=ls *py
635 635
636 636 In [8]: b
637 637 Out[8]: ['setup.py', 'win32_manual_post_install.py']
638 638
639 639 In [9]: b.s
640 640 Out[9]: 'setup.py win32_manual_post_install.py'
641 641
642 642 In summary, both the lists and strings used for output capture have
643 643 the following special attributes::
644 644
645 645 .l (or .list) : value as list.
646 646 .n (or .nlstr): value as newline-separated string.
647 647 .s (or .spstr): value as space-separated string.
648 648 """
649 649
650 650 opts,args = self.parse_options(parameter_s, 'lv')
651 651 # Try to get a variable name and command to run
652 652 try:
653 653 # the variable name must be obtained from the parse_options
654 654 # output, which uses shlex.split to strip options out.
655 655 var,_ = args.split('=', 1)
656 656 var = var.strip()
657 657 # But the command has to be extracted from the original input
658 658 # parameter_s, not on what parse_options returns, to avoid the
659 659 # quote stripping which shlex.split performs on it.
660 660 _,cmd = parameter_s.split('=', 1)
661 661 except ValueError:
662 662 var,cmd = '',''
663 663 # If all looks ok, proceed
664 664 split = 'l' in opts
665 665 out = self.shell.getoutput(cmd, split=split)
666 666 if 'v' in opts:
667 667 print('%s ==\n%s' % (var, pformat(out)))
668 668 if var:
669 669 self.shell.user_ns.update({var:out})
670 670 else:
671 671 return out
672 672
673 673 @line_cell_magic
674 674 def sx(self, line='', cell=None):
675 675 """Shell execute - run shell command and capture output (!! is short-hand).
676 676
677 677 %sx command
678 678
679 679 IPython will run the given command using commands.getoutput(), and
680 680 return the result formatted as a list (split on '\\n'). Since the
681 681 output is _returned_, it will be stored in ipython's regular output
682 682 cache Out[N] and in the '_N' automatic variables.
683 683
684 684 Notes:
685 685
686 686 1) If an input line begins with '!!', then %sx is automatically
687 687 invoked. That is, while::
688 688
689 689 !ls
690 690
691 691 causes ipython to simply issue system('ls'), typing::
692 692
693 693 !!ls
694 694
695 695 is a shorthand equivalent to::
696 696
697 697 %sx ls
698 698
699 699 2) %sx differs from %sc in that %sx automatically splits into a list,
700 700 like '%sc -l'. The reason for this is to make it as easy as possible
701 701 to process line-oriented shell output via further python commands.
702 702 %sc is meant to provide much finer control, but requires more
703 703 typing.
704 704
705 705 3) Just like %sc -l, this is a list with special attributes:
706 706 ::
707 707
708 708 .l (or .list) : value as list.
709 709 .n (or .nlstr): value as newline-separated string.
710 710 .s (or .spstr): value as whitespace-separated string.
711 711
712 712 This is very useful when trying to use such lists as arguments to
713 713 system commands."""
714 714
715 715 if cell is None:
716 716 # line magic
717 717 return self.shell.getoutput(line)
718 718 else:
719 719 opts,args = self.parse_options(line, '', 'out=')
720 720 output = self.shell.getoutput(cell)
721 721 out_name = opts.get('out', opts.get('o'))
722 722 if out_name:
723 723 self.shell.user_ns[out_name] = output
724 724 else:
725 725 return output
726 726
727 727 system = line_cell_magic('system')(sx)
728 728 bang = cell_magic('!')(sx)
729 729
730 730 @line_magic
731 731 def bookmark(self, parameter_s=''):
732 732 """Manage IPython's bookmark system.
733 733
734 734 %bookmark <name> - set bookmark to current dir
735 735 %bookmark <name> <dir> - set bookmark to <dir>
736 736 %bookmark -l - list all bookmarks
737 737 %bookmark -d <name> - remove bookmark
738 738 %bookmark -r - remove all bookmarks
739 739
740 740 You can later on access a bookmarked folder with::
741 741
742 742 %cd -b <name>
743 743
744 744 or simply '%cd <name>' if there is no directory called <name> AND
745 745 there is such a bookmark defined.
746 746
747 747 Your bookmarks persist through IPython sessions, but they are
748 748 associated with each profile."""
749 749
750 750 opts,args = self.parse_options(parameter_s,'drl',mode='list')
751 751 if len(args) > 2:
752 752 raise UsageError("%bookmark: too many arguments")
753 753
754 754 bkms = self.shell.db.get('bookmarks',{})
755 755
756 756 if 'd' in opts:
757 757 try:
758 758 todel = args[0]
759 759 except IndexError:
760 760 raise UsageError(
761 761 "%bookmark -d: must provide a bookmark to delete")
762 762 else:
763 763 try:
764 764 del bkms[todel]
765 765 except KeyError:
766 766 raise UsageError(
767 767 "%%bookmark -d: Can't delete bookmark '%s'" % todel)
768 768
769 769 elif 'r' in opts:
770 770 bkms = {}
771 771 elif 'l' in opts:
772 772 bks = sorted(bkms)
773 773 if bks:
774 774 size = max(map(len, bks))
775 775 else:
776 776 size = 0
777 777 fmt = '%-'+str(size)+'s -> %s'
778 778 print('Current bookmarks:')
779 779 for bk in bks:
780 780 print(fmt % (bk, bkms[bk]))
781 781 else:
782 782 if not args:
783 783 raise UsageError("%bookmark: You must specify the bookmark name")
784 784 elif len(args)==1:
785 785 bkms[args[0]] = os.getcwd()
786 786 elif len(args)==2:
787 787 bkms[args[0]] = args[1]
788 788 self.shell.db['bookmarks'] = bkms
789 789
790 790 @line_magic
791 791 def pycat(self, parameter_s=''):
792 792 """Show a syntax-highlighted file through a pager.
793 793
794 794 This magic is similar to the cat utility, but it will assume the file
795 795 to be Python source and will show it with syntax highlighting.
796 796
797 797 This magic command can either take a local filename, an url,
798 798 an history range (see %history) or a macro as argument ::
799 799
800 800 %pycat myscript.py
801 801 %pycat 7-27
802 802 %pycat myMacro
803 803 %pycat http://www.example.com/myscript.py
804 804 """
805 805 if not parameter_s:
806 806 raise UsageError('Missing filename, URL, input history range, '
807 807 'or macro.')
808 808
809 809 try :
810 810 cont = self.shell.find_user_code(parameter_s, skip_encoding_cookie=False)
811 811 except (ValueError, IOError):
812 812 print("Error: no such file, variable, URL, history range or macro")
813 813 return
814 814
815 815 page.page(self.shell.pycolorize(source_to_unicode(cont)))
816 816
817 817 @magic_arguments.magic_arguments()
818 818 @magic_arguments.argument(
819 819 '-a', '--append', action='store_true', default=False,
820 820 help='Append contents of the cell to an existing file. '
821 821 'The file will be created if it does not exist.'
822 822 )
823 823 @magic_arguments.argument(
824 824 'filename', type=str,
825 825 help='file to write'
826 826 )
827 827 @cell_magic
828 828 def writefile(self, line, cell):
829 829 """Write the contents of the cell to a file.
830 830
831 831 The file will be overwritten unless the -a (--append) flag is specified.
832 832 """
833 833 args = magic_arguments.parse_argstring(self.writefile, line)
834 834 if re.match(r'^(\'.*\')|(".*")$', args.filename):
835 835 filename = os.path.expanduser(args.filename[1:-1])
836 836 else:
837 837 filename = os.path.expanduser(args.filename)
838 838
839 839 if os.path.exists(filename):
840 840 if args.append:
841 841 print("Appending to %s" % filename)
842 842 else:
843 843 print("Overwriting %s" % filename)
844 844 else:
845 845 print("Writing %s" % filename)
846 846
847 847 mode = 'a' if args.append else 'w'
848 848 with io.open(filename, mode, encoding='utf-8') as f:
849 849 f.write(cell)
General Comments 0
You need to be logged in to leave comments. Login now