Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/IPython/core/magics/osm.py: 19%

356 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-04-20 06:09 +0000

1"""Implementation of magic functions for interaction with the OS. 

2 

3Note: this module is named 'osm' instead of 'os' to avoid a collision with the 

4builtin. 

5""" 

6# Copyright (c) IPython Development Team. 

7# Distributed under the terms of the Modified BSD License. 

8 

9import io 

10import os 

11import pathlib 

12import re 

13import sys 

14from pprint import pformat 

15 

16from IPython.core import magic_arguments 

17from IPython.core import oinspect 

18from IPython.core import page 

19from IPython.core.alias import AliasError, Alias 

20from IPython.core.error import UsageError 

21from IPython.core.magic import ( 

22 Magics, compress_dhist, magics_class, line_magic, cell_magic, line_cell_magic 

23) 

24from IPython.testing.skipdoctest import skip_doctest 

25from IPython.utils.openpy import source_to_unicode 

26from IPython.utils.process import abbrev_cwd 

27from IPython.utils.terminal import set_term_title 

28from traitlets import Bool 

29from warnings import warn 

30 

31 

32@magics_class 

33class OSMagics(Magics): 

34 """Magics to interact with the underlying OS (shell-type functionality). 

35 """ 

36 

37 cd_force_quiet = Bool(False, 

38 help="Force %cd magic to be quiet even if -q is not passed." 

39 ).tag(config=True) 

40 

41 def __init__(self, shell=None, **kwargs): 

42 

43 # Now define isexec in a cross platform manner. 

44 self.is_posix = False 

45 self.execre = None 

46 if os.name == 'posix': 

47 self.is_posix = True 

48 else: 

49 try: 

50 winext = os.environ['pathext'].replace(';','|').replace('.','') 

51 except KeyError: 

52 winext = 'exe|com|bat|py' 

53 try: 

54 self.execre = re.compile(r'(.*)\.(%s)$' % winext,re.IGNORECASE) 

55 except re.error: 

56 warn("Seems like your pathext environmental " 

57 "variable is malformed. Please check it to " 

58 "enable a proper handle of file extensions " 

59 "managed for your system") 

60 winext = 'exe|com|bat|py' 

61 self.execre = re.compile(r'(.*)\.(%s)$' % winext,re.IGNORECASE) 

62 

63 # call up the chain 

64 super().__init__(shell=shell, **kwargs) 

65 

66 

67 def _isexec_POSIX(self, file): 

68 """ 

69 Test for executable on a POSIX system 

70 """ 

71 if os.access(file.path, os.X_OK): 

72 # will fail on maxOS if access is not X_OK 

73 return file.is_file() 

74 return False 

75 

76 

77 

78 def _isexec_WIN(self, file): 

79 """ 

80 Test for executable file on non POSIX system 

81 """ 

82 return file.is_file() and self.execre.match(file.name) is not None 

83 

84 def isexec(self, file): 

85 """ 

86 Test for executable file on non POSIX system 

87 """ 

88 if self.is_posix: 

89 return self._isexec_POSIX(file) 

90 else: 

91 return self._isexec_WIN(file) 

92 

93 

94 @skip_doctest 

95 @line_magic 

96 def alias(self, parameter_s=''): 

97 """Define an alias for a system command. 

98 

99 '%alias alias_name cmd' defines 'alias_name' as an alias for 'cmd' 

100 

101 Then, typing 'alias_name params' will execute the system command 'cmd 

102 params' (from your underlying operating system). 

103 

104 Aliases have lower precedence than magic functions and Python normal 

105 variables, so if 'foo' is both a Python variable and an alias, the 

106 alias can not be executed until 'del foo' removes the Python variable. 

107 

108 You can use the %l specifier in an alias definition to represent the 

109 whole line when the alias is called. For example:: 

110 

111 In [2]: alias bracket echo "Input in brackets: <%l>" 

112 In [3]: bracket hello world 

113 Input in brackets: <hello world> 

114 

115 You can also define aliases with parameters using %s specifiers (one 

116 per parameter):: 

117 

118 In [1]: alias parts echo first %s second %s 

119 In [2]: %parts A B 

120 first A second B 

121 In [3]: %parts A 

122 Incorrect number of arguments: 2 expected. 

123 parts is an alias to: 'echo first %s second %s' 

124 

125 Note that %l and %s are mutually exclusive. You can only use one or 

126 the other in your aliases. 

127 

128 Aliases expand Python variables just like system calls using ! or !! 

129 do: all expressions prefixed with '$' get expanded. For details of 

130 the semantic rules, see PEP-215: 

131 https://peps.python.org/pep-0215/. This is the library used by 

132 IPython for variable expansion. If you want to access a true shell 

133 variable, an extra $ is necessary to prevent its expansion by 

134 IPython:: 

135 

136 In [6]: alias show echo 

137 In [7]: PATH='A Python string' 

138 In [8]: show $PATH 

139 A Python string 

140 In [9]: show $$PATH 

141 /usr/local/lf9560/bin:/usr/local/intel/compiler70/ia32/bin:... 

142 

143 You can use the alias facility to access all of $PATH. See the %rehashx 

144 function, which automatically creates aliases for the contents of your 

145 $PATH. 

146 

147 If called with no parameters, %alias prints the current alias table 

148 for your system. For posix systems, the default aliases are 'cat', 

149 'cp', 'mv', 'rm', 'rmdir', and 'mkdir', and other platform-specific 

150 aliases are added. For windows-based systems, the default aliases are 

151 'copy', 'ddir', 'echo', 'ls', 'ldir', 'mkdir', 'ren', and 'rmdir'. 

152 

153 You can see the definition of alias by adding a question mark in the 

154 end:: 

155 

156 In [1]: cat? 

157 Repr: <alias cat for 'cat'>""" 

158 

159 par = parameter_s.strip() 

160 if not par: 

161 aliases = sorted(self.shell.alias_manager.aliases) 

162 # stored = self.shell.db.get('stored_aliases', {} ) 

163 # for k, v in stored: 

164 # atab.append(k, v[0]) 

165 

166 print("Total number of aliases:", len(aliases)) 

167 sys.stdout.flush() 

168 return aliases 

169 

170 # Now try to define a new one 

171 try: 

172 alias,cmd = par.split(None, 1) 

173 except TypeError: 

174 print(oinspect.getdoc(self.alias)) 

175 return 

176 

177 try: 

178 self.shell.alias_manager.define_alias(alias, cmd) 

179 except AliasError as e: 

180 print(e) 

181 # end magic_alias 

182 

183 @line_magic 

184 def unalias(self, parameter_s=''): 

185 """Remove an alias""" 

186 

187 aname = parameter_s.strip() 

188 try: 

189 self.shell.alias_manager.undefine_alias(aname) 

190 except ValueError as e: 

191 print(e) 

192 return 

193 

194 stored = self.shell.db.get('stored_aliases', {} ) 

195 if aname in stored: 

196 print("Removing %stored alias",aname) 

197 del stored[aname] 

198 self.shell.db['stored_aliases'] = stored 

199 

200 @line_magic 

201 def rehashx(self, parameter_s=''): 

202 """Update the alias table with all executable files in $PATH. 

203 

204 rehashx explicitly checks that every entry in $PATH is a file 

205 with execute access (os.X_OK). 

206 

207 Under Windows, it checks executability as a match against a 

208 '|'-separated string of extensions, stored in the IPython config 

209 variable win_exec_ext. This defaults to 'exe|com|bat'. 

210 

211 This function also resets the root module cache of module completer, 

212 used on slow filesystems. 

213 """ 

214 from IPython.core.alias import InvalidAliasError 

215 

216 # for the benefit of module completer in ipy_completers.py 

217 del self.shell.db['rootmodules_cache'] 

218 

219 path = [os.path.abspath(os.path.expanduser(p)) for p in 

220 os.environ.get('PATH','').split(os.pathsep)] 

221 

222 syscmdlist = [] 

223 savedir = os.getcwd() 

224 

225 # Now walk the paths looking for executables to alias. 

226 try: 

227 # write the whole loop for posix/Windows so we don't have an if in 

228 # the innermost part 

229 if self.is_posix: 

230 for pdir in path: 

231 try: 

232 os.chdir(pdir) 

233 except OSError: 

234 continue 

235 

236 # for python 3.6+ rewrite to: with os.scandir(pdir) as dirlist: 

237 dirlist = os.scandir(path=pdir) 

238 for ff in dirlist: 

239 if self.isexec(ff): 

240 fname = ff.name 

241 try: 

242 # Removes dots from the name since ipython 

243 # will assume names with dots to be python. 

244 if not self.shell.alias_manager.is_alias(fname): 

245 self.shell.alias_manager.define_alias( 

246 fname.replace('.',''), fname) 

247 except InvalidAliasError: 

248 pass 

249 else: 

250 syscmdlist.append(fname) 

251 else: 

252 no_alias = Alias.blacklist 

253 for pdir in path: 

254 try: 

255 os.chdir(pdir) 

256 except OSError: 

257 continue 

258 

259 # for python 3.6+ rewrite to: with os.scandir(pdir) as dirlist: 

260 dirlist = os.scandir(pdir) 

261 for ff in dirlist: 

262 fname = ff.name 

263 base, ext = os.path.splitext(fname) 

264 if self.isexec(ff) and base.lower() not in no_alias: 

265 if ext.lower() == '.exe': 

266 fname = base 

267 try: 

268 # Removes dots from the name since ipython 

269 # will assume names with dots to be python. 

270 self.shell.alias_manager.define_alias( 

271 base.lower().replace('.',''), fname) 

272 except InvalidAliasError: 

273 pass 

274 syscmdlist.append(fname) 

275 

276 self.shell.db['syscmdlist'] = syscmdlist 

277 finally: 

278 os.chdir(savedir) 

279 

280 @skip_doctest 

281 @line_magic 

282 def pwd(self, parameter_s=''): 

283 """Return the current working directory path. 

284 

285 Examples 

286 -------- 

287 :: 

288 

289 In [9]: pwd 

290 Out[9]: '/home/tsuser/sprint/ipython' 

291 """ 

292 try: 

293 return os.getcwd() 

294 except FileNotFoundError as e: 

295 raise UsageError("CWD no longer exists - please use %cd to change directory.") from e 

296 

297 @skip_doctest 

298 @line_magic 

299 def cd(self, parameter_s=''): 

300 """Change the current working directory. 

301 

302 This command automatically maintains an internal list of directories 

303 you visit during your IPython session, in the variable ``_dh``. The 

304 command :magic:`%dhist` shows this history nicely formatted. You can 

305 also do ``cd -<tab>`` to see directory history conveniently. 

306 Usage: 

307 

308 - ``cd 'dir'``: changes to directory 'dir'. 

309 - ``cd -``: changes to the last visited directory. 

310 - ``cd -<n>``: changes to the n-th directory in the directory history. 

311 - ``cd --foo``: change to directory that matches 'foo' in history 

312 - ``cd -b <bookmark_name>``: jump to a bookmark set by %bookmark 

313 - Hitting a tab key after ``cd -b`` allows you to tab-complete 

314 bookmark names. 

315 

316 .. note:: 

317 ``cd <bookmark_name>`` is enough if there is no directory 

318 ``<bookmark_name>``, but a bookmark with the name exists. 

319 

320 Options: 

321 

322 -q Be quiet. Do not print the working directory after the 

323 cd command is executed. By default IPython's cd 

324 command does print this directory, since the default 

325 prompts do not display path information. 

326 

327 .. note:: 

328 Note that ``!cd`` doesn't work for this purpose because the shell 

329 where ``!command`` runs is immediately discarded after executing 

330 'command'. 

331 

332 Examples 

333 -------- 

334 :: 

335 

336 In [10]: cd parent/child 

337 /home/tsuser/parent/child 

338 """ 

339 

340 try: 

341 oldcwd = os.getcwd() 

342 except FileNotFoundError: 

343 # Happens if the CWD has been deleted. 

344 oldcwd = None 

345 

346 numcd = re.match(r'(-)(\d+)$',parameter_s) 

347 # jump in directory history by number 

348 if numcd: 

349 nn = int(numcd.group(2)) 

350 try: 

351 ps = self.shell.user_ns['_dh'][nn] 

352 except IndexError: 

353 print('The requested directory does not exist in history.') 

354 return 

355 else: 

356 opts = {} 

357 elif parameter_s.startswith('--'): 

358 ps = None 

359 fallback = None 

360 pat = parameter_s[2:] 

361 dh = self.shell.user_ns['_dh'] 

362 # first search only by basename (last component) 

363 for ent in reversed(dh): 

364 if pat in os.path.basename(ent) and os.path.isdir(ent): 

365 ps = ent 

366 break 

367 

368 if fallback is None and pat in ent and os.path.isdir(ent): 

369 fallback = ent 

370 

371 # if we have no last part match, pick the first full path match 

372 if ps is None: 

373 ps = fallback 

374 

375 if ps is None: 

376 print("No matching entry in directory history") 

377 return 

378 else: 

379 opts = {} 

380 

381 

382 else: 

383 opts, ps = self.parse_options(parameter_s, 'qb', mode='string') 

384 # jump to previous 

385 if ps == '-': 

386 try: 

387 ps = self.shell.user_ns['_dh'][-2] 

388 except IndexError as e: 

389 raise UsageError('%cd -: No previous directory to change to.') from e 

390 # jump to bookmark if needed 

391 else: 

392 if not os.path.isdir(ps) or 'b' in opts: 

393 bkms = self.shell.db.get('bookmarks', {}) 

394 

395 if ps in bkms: 

396 target = bkms[ps] 

397 print('(bookmark:%s) -> %s' % (ps, target)) 

398 ps = target 

399 else: 

400 if 'b' in opts: 

401 raise UsageError("Bookmark '%s' not found. " 

402 "Use '%%bookmark -l' to see your bookmarks." % ps) 

403 

404 # at this point ps should point to the target dir 

405 if ps: 

406 try: 

407 os.chdir(os.path.expanduser(ps)) 

408 if hasattr(self.shell, 'term_title') and self.shell.term_title: 

409 set_term_title(self.shell.term_title_format.format(cwd=abbrev_cwd())) 

410 except OSError: 

411 print(sys.exc_info()[1]) 

412 else: 

413 cwd = pathlib.Path.cwd() 

414 dhist = self.shell.user_ns['_dh'] 

415 if oldcwd != cwd: 

416 dhist.append(cwd) 

417 self.shell.db['dhist'] = compress_dhist(dhist)[-100:] 

418 

419 else: 

420 os.chdir(self.shell.home_dir) 

421 if hasattr(self.shell, 'term_title') and self.shell.term_title: 

422 set_term_title(self.shell.term_title_format.format(cwd="~")) 

423 cwd = pathlib.Path.cwd() 

424 dhist = self.shell.user_ns['_dh'] 

425 

426 if oldcwd != cwd: 

427 dhist.append(cwd) 

428 self.shell.db['dhist'] = compress_dhist(dhist)[-100:] 

429 if not 'q' in opts and not self.cd_force_quiet and self.shell.user_ns['_dh']: 

430 print(self.shell.user_ns['_dh'][-1]) 

431 

432 @line_magic 

433 def env(self, parameter_s=''): 

434 """Get, set, or list environment variables. 

435 

436 Usage:\\ 

437 

438 :``%env``: lists all environment variables/values 

439 :``%env var``: get value for var 

440 :``%env var val``: set value for var 

441 :``%env var=val``: set value for var 

442 :``%env var=$val``: set value for var, using python expansion if possible 

443 """ 

444 if parameter_s.strip(): 

445 split = '=' if '=' in parameter_s else ' ' 

446 bits = parameter_s.split(split) 

447 if len(bits) == 1: 

448 key = parameter_s.strip() 

449 if key in os.environ: 

450 return os.environ[key] 

451 else: 

452 err = "Environment does not have key: {0}".format(key) 

453 raise UsageError(err) 

454 if len(bits) > 1: 

455 return self.set_env(parameter_s) 

456 env = dict(os.environ) 

457 # hide likely secrets when printing the whole environment 

458 for key in list(env): 

459 if any(s in key.lower() for s in ('key', 'token', 'secret')): 

460 env[key] = '<hidden>' 

461 

462 return env 

463 

464 @line_magic 

465 def set_env(self, parameter_s): 

466 """Set environment variables. Assumptions are that either "val" is a 

467 name in the user namespace, or val is something that evaluates to a 

468 string. 

469 

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 

474 """ 

475 split = '=' if '=' in parameter_s else ' ' 

476 bits = parameter_s.split(split, 1) 

477 if not parameter_s.strip() or len(bits)<2: 

478 raise UsageError("usage is 'set_env var=val'") 

479 var = bits[0].strip() 

480 val = bits[1].strip() 

481 if re.match(r'.*\s.*', var): 

482 # an environment variable with whitespace is almost certainly 

483 # not what the user intended. what's more likely is the wrong 

484 # split was chosen, ie for "set_env cmd_args A=B", we chose 

485 # '=' for the split and should have chosen ' '. to get around 

486 # this, users should just assign directly to os.environ or use 

487 # standard magic {var} expansion. 

488 err = "refusing to set env var with whitespace: '{0}'" 

489 err = err.format(val) 

490 raise UsageError(err) 

491 os.environ[var] = val 

492 print('env: {0}={1}'.format(var,val)) 

493 

494 @line_magic 

495 def pushd(self, parameter_s=''): 

496 """Place the current dir on stack and change directory. 

497 

498 Usage:\\ 

499 %pushd ['dirname'] 

500 """ 

501 

502 dir_s = self.shell.dir_stack 

503 tgt = os.path.expanduser(parameter_s) 

504 cwd = os.getcwd().replace(self.shell.home_dir,'~') 

505 if tgt: 

506 self.cd(parameter_s) 

507 dir_s.insert(0,cwd) 

508 return self.shell.run_line_magic('dirs', '') 

509 

510 @line_magic 

511 def popd(self, parameter_s=''): 

512 """Change to directory popped off the top of the stack. 

513 """ 

514 if not self.shell.dir_stack: 

515 raise UsageError("%popd on empty stack") 

516 top = self.shell.dir_stack.pop(0) 

517 self.cd(top) 

518 print("popd ->",top) 

519 

520 @line_magic 

521 def dirs(self, parameter_s=''): 

522 """Return the current directory stack.""" 

523 

524 return self.shell.dir_stack 

525 

526 @line_magic 

527 def dhist(self, parameter_s=''): 

528 """Print your history of visited directories. 

529 

530 %dhist -> print full history\\ 

531 %dhist n -> print last n entries only\\ 

532 %dhist n1 n2 -> print entries between n1 and n2 (n2 not included)\\ 

533 

534 This history is automatically maintained by the %cd command, and 

535 always available as the global list variable _dh. You can use %cd -<n> 

536 to go to directory number <n>. 

537 

538 Note that most of time, you should view directory history by entering 

539 cd -<TAB>. 

540 

541 """ 

542 

543 dh = self.shell.user_ns['_dh'] 

544 if parameter_s: 

545 try: 

546 args = map(int,parameter_s.split()) 

547 except: 

548 self.arg_err(self.dhist) 

549 return 

550 if len(args) == 1: 

551 ini,fin = max(len(dh)-(args[0]),0),len(dh) 

552 elif len(args) == 2: 

553 ini,fin = args 

554 fin = min(fin, len(dh)) 

555 else: 

556 self.arg_err(self.dhist) 

557 return 

558 else: 

559 ini,fin = 0,len(dh) 

560 print('Directory history (kept in _dh)') 

561 for i in range(ini, fin): 

562 print("%d: %s" % (i, dh[i])) 

563 

564 @skip_doctest 

565 @line_magic 

566 def sc(self, parameter_s=''): 

567 """Shell capture - run shell command and capture output (DEPRECATED use !). 

568 

569 DEPRECATED. Suboptimal, retained for backwards compatibility. 

570 

571 You should use the form 'var = !command' instead. Example: 

572 

573 "%sc -l myfiles = ls ~" should now be written as 

574 

575 "myfiles = !ls ~" 

576 

577 myfiles.s, myfiles.l and myfiles.n still apply as documented 

578 below. 

579 

580 -- 

581 %sc [options] varname=command 

582 

583 IPython will run the given command using commands.getoutput(), and 

584 will then update the user's interactive namespace with a variable 

585 called varname, containing the value of the call. Your command can 

586 contain shell wildcards, pipes, etc. 

587 

588 The '=' sign in the syntax is mandatory, and the variable name you 

589 supply must follow Python's standard conventions for valid names. 

590 

591 (A special format without variable name exists for internal use) 

592 

593 Options: 

594 

595 -l: list output. Split the output on newlines into a list before 

596 assigning it to the given variable. By default the output is stored 

597 as a single string. 

598 

599 -v: verbose. Print the contents of the variable. 

600 

601 In most cases you should not need to split as a list, because the 

602 returned value is a special type of string which can automatically 

603 provide its contents either as a list (split on newlines) or as a 

604 space-separated string. These are convenient, respectively, either 

605 for sequential processing or to be passed to a shell command. 

606 

607 For example:: 

608 

609 # Capture into variable a 

610 In [1]: sc a=ls *py 

611 

612 # a is a string with embedded newlines 

613 In [2]: a 

614 Out[2]: 'setup.py\\nwin32_manual_post_install.py' 

615 

616 # which can be seen as a list: 

617 In [3]: a.l 

618 Out[3]: ['setup.py', 'win32_manual_post_install.py'] 

619 

620 # or as a whitespace-separated string: 

621 In [4]: a.s 

622 Out[4]: 'setup.py win32_manual_post_install.py' 

623 

624 # a.s is useful to pass as a single command line: 

625 In [5]: !wc -l $a.s 

626 146 setup.py 

627 130 win32_manual_post_install.py 

628 276 total 

629 

630 # while the list form is useful to loop over: 

631 In [6]: for f in a.l: 

632 ...: !wc -l $f 

633 ...: 

634 146 setup.py 

635 130 win32_manual_post_install.py 

636 

637 Similarly, the lists returned by the -l option are also special, in 

638 the sense that you can equally invoke the .s attribute on them to 

639 automatically get a whitespace-separated string from their contents:: 

640 

641 In [7]: sc -l b=ls *py 

642 

643 In [8]: b 

644 Out[8]: ['setup.py', 'win32_manual_post_install.py'] 

645 

646 In [9]: b.s 

647 Out[9]: 'setup.py win32_manual_post_install.py' 

648 

649 In summary, both the lists and strings used for output capture have 

650 the following special attributes:: 

651 

652 .l (or .list) : value as list. 

653 .n (or .nlstr): value as newline-separated string. 

654 .s (or .spstr): value as space-separated string. 

655 """ 

656 

657 opts,args = self.parse_options(parameter_s, 'lv') 

658 # Try to get a variable name and command to run 

659 try: 

660 # the variable name must be obtained from the parse_options 

661 # output, which uses shlex.split to strip options out. 

662 var,_ = args.split('=', 1) 

663 var = var.strip() 

664 # But the command has to be extracted from the original input 

665 # parameter_s, not on what parse_options returns, to avoid the 

666 # quote stripping which shlex.split performs on it. 

667 _,cmd = parameter_s.split('=', 1) 

668 except ValueError: 

669 var,cmd = '','' 

670 # If all looks ok, proceed 

671 split = 'l' in opts 

672 out = self.shell.getoutput(cmd, split=split) 

673 if 'v' in opts: 

674 print('%s ==\n%s' % (var, pformat(out))) 

675 if var: 

676 self.shell.user_ns.update({var:out}) 

677 else: 

678 return out 

679 

680 @line_cell_magic 

681 def sx(self, line='', cell=None): 

682 """Shell execute - run shell command and capture output (!! is short-hand). 

683 

684 %sx command 

685 

686 IPython will run the given command using commands.getoutput(), and 

687 return the result formatted as a list (split on '\\n'). Since the 

688 output is _returned_, it will be stored in ipython's regular output 

689 cache Out[N] and in the '_N' automatic variables. 

690 

691 Notes: 

692 

693 1) If an input line begins with '!!', then %sx is automatically 

694 invoked. That is, while:: 

695 

696 !ls 

697 

698 causes ipython to simply issue system('ls'), typing:: 

699 

700 !!ls 

701 

702 is a shorthand equivalent to:: 

703 

704 %sx ls 

705 

706 2) %sx differs from %sc in that %sx automatically splits into a list, 

707 like '%sc -l'. The reason for this is to make it as easy as possible 

708 to process line-oriented shell output via further python commands. 

709 %sc is meant to provide much finer control, but requires more 

710 typing. 

711 

712 3) Just like %sc -l, this is a list with special attributes: 

713 :: 

714 

715 .l (or .list) : value as list. 

716 .n (or .nlstr): value as newline-separated string. 

717 .s (or .spstr): value as whitespace-separated string. 

718 

719 This is very useful when trying to use such lists as arguments to 

720 system commands.""" 

721 

722 if cell is None: 

723 # line magic 

724 return self.shell.getoutput(line) 

725 else: 

726 opts,args = self.parse_options(line, '', 'out=') 

727 output = self.shell.getoutput(cell) 

728 out_name = opts.get('out', opts.get('o')) 

729 if out_name: 

730 self.shell.user_ns[out_name] = output 

731 else: 

732 return output 

733 

734 system = line_cell_magic('system')(sx) 

735 bang = cell_magic('!')(sx) 

736 

737 @line_magic 

738 def bookmark(self, parameter_s=''): 

739 """Manage IPython's bookmark system. 

740 

741 %bookmark <name> - set bookmark to current dir 

742 %bookmark <name> <dir> - set bookmark to <dir> 

743 %bookmark -l - list all bookmarks 

744 %bookmark -d <name> - remove bookmark 

745 %bookmark -r - remove all bookmarks 

746 

747 You can later on access a bookmarked folder with:: 

748 

749 %cd -b <name> 

750 

751 or simply '%cd <name>' if there is no directory called <name> AND 

752 there is such a bookmark defined. 

753 

754 Your bookmarks persist through IPython sessions, but they are 

755 associated with each profile.""" 

756 

757 opts,args = self.parse_options(parameter_s,'drl',mode='list') 

758 if len(args) > 2: 

759 raise UsageError("%bookmark: too many arguments") 

760 

761 bkms = self.shell.db.get('bookmarks',{}) 

762 

763 if 'd' in opts: 

764 try: 

765 todel = args[0] 

766 except IndexError as e: 

767 raise UsageError( 

768 "%bookmark -d: must provide a bookmark to delete") from e 

769 else: 

770 try: 

771 del bkms[todel] 

772 except KeyError as e: 

773 raise UsageError( 

774 "%%bookmark -d: Can't delete bookmark '%s'" % todel) from e 

775 

776 elif 'r' in opts: 

777 bkms = {} 

778 elif 'l' in opts: 

779 bks = sorted(bkms) 

780 if bks: 

781 size = max(map(len, bks)) 

782 else: 

783 size = 0 

784 fmt = '%-'+str(size)+'s -> %s' 

785 print('Current bookmarks:') 

786 for bk in bks: 

787 print(fmt % (bk, bkms[bk])) 

788 else: 

789 if not args: 

790 raise UsageError("%bookmark: You must specify the bookmark name") 

791 elif len(args)==1: 

792 bkms[args[0]] = os.getcwd() 

793 elif len(args)==2: 

794 bkms[args[0]] = args[1] 

795 self.shell.db['bookmarks'] = bkms 

796 

797 @line_magic 

798 def pycat(self, parameter_s=''): 

799 """Show a syntax-highlighted file through a pager. 

800 

801 This magic is similar to the cat utility, but it will assume the file 

802 to be Python source and will show it with syntax highlighting. 

803 

804 This magic command can either take a local filename, an url, 

805 an history range (see %history) or a macro as argument. 

806 

807 If no parameter is given, prints out history of current session up to 

808 this point. :: 

809 

810 %pycat myscript.py 

811 %pycat 7-27 

812 %pycat myMacro 

813 %pycat http://www.example.com/myscript.py 

814 """ 

815 try: 

816 cont = self.shell.find_user_code(parameter_s, skip_encoding_cookie=False) 

817 except (ValueError, IOError): 

818 print("Error: no such file, variable, URL, history range or macro") 

819 return 

820 

821 page.page(self.shell.pycolorize(source_to_unicode(cont))) 

822 

823 @magic_arguments.magic_arguments() 

824 @magic_arguments.argument( 

825 '-a', '--append', action='store_true', default=False, 

826 help='Append contents of the cell to an existing file. ' 

827 'The file will be created if it does not exist.' 

828 ) 

829 @magic_arguments.argument( 

830 'filename', type=str, 

831 help='file to write' 

832 ) 

833 @cell_magic 

834 def writefile(self, line, cell): 

835 """Write the contents of the cell to a file. 

836 

837 The file will be overwritten unless the -a (--append) flag is specified. 

838 """ 

839 args = magic_arguments.parse_argstring(self.writefile, line) 

840 if re.match(r'^(\'.*\')|(".*")$', args.filename): 

841 filename = os.path.expanduser(args.filename[1:-1]) 

842 else: 

843 filename = os.path.expanduser(args.filename) 

844 

845 if os.path.exists(filename): 

846 if args.append: 

847 print("Appending to %s" % filename) 

848 else: 

849 print("Overwriting %s" % filename) 

850 else: 

851 print("Writing %s" % filename) 

852 

853 mode = 'a' if args.append else 'w' 

854 with io.open(filename, mode, encoding='utf-8') as f: 

855 f.write(cell)