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