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