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