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