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