##// END OF EJS Templates
Merge pull request #6953 from mattvonrocketstein/issue3992...
Matthias Bussonnier -
r18941:f5839c2f merge
parent child Browse files
Show More
@@ -1,740 +1,778 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 from __future__ import print_function
7 7 #-----------------------------------------------------------------------------
8 8 # Copyright (c) 2012 The IPython Development Team.
9 9 #
10 10 # Distributed under the terms of the Modified BSD License.
11 11 #
12 12 # The full license is in the file COPYING.txt, distributed with this software.
13 13 #-----------------------------------------------------------------------------
14 14
15 15 #-----------------------------------------------------------------------------
16 16 # Imports
17 17 #-----------------------------------------------------------------------------
18 18
19 19 # Stdlib
20 20 import io
21 21 import os
22 22 import re
23 23 import sys
24 24 from pprint import pformat
25 25
26 26 # Our own packages
27 27 from IPython.core import magic_arguments
28 28 from IPython.core import oinspect
29 29 from IPython.core import page
30 30 from IPython.core.alias import AliasError, Alias
31 31 from IPython.core.error import UsageError
32 32 from IPython.core.magic import (
33 33 Magics, compress_dhist, magics_class, line_magic, cell_magic, line_cell_magic
34 34 )
35 35 from IPython.testing.skipdoctest import skip_doctest
36 36 from IPython.utils.openpy import source_to_unicode
37 37 from IPython.utils.path import unquote_filename
38 38 from IPython.utils.process import abbrev_cwd
39 39 from IPython.utils import py3compat
40 40 from IPython.utils.py3compat import unicode_type
41 41 from IPython.utils.terminal import set_term_title
42 42
43 43 #-----------------------------------------------------------------------------
44 44 # Magic implementation classes
45 45 #-----------------------------------------------------------------------------
46 46 @magics_class
47 47 class OSMagics(Magics):
48 48 """Magics to interact with the underlying OS (shell-type functionality).
49 49 """
50 50
51 51 @skip_doctest
52 52 @line_magic
53 53 def alias(self, parameter_s=''):
54 54 """Define an alias for a system command.
55 55
56 56 '%alias alias_name cmd' defines 'alias_name' as an alias for 'cmd'
57 57
58 58 Then, typing 'alias_name params' will execute the system command 'cmd
59 59 params' (from your underlying operating system).
60 60
61 61 Aliases have lower precedence than magic functions and Python normal
62 62 variables, so if 'foo' is both a Python variable and an alias, the
63 63 alias can not be executed until 'del foo' removes the Python variable.
64 64
65 65 You can use the %l specifier in an alias definition to represent the
66 66 whole line when the alias is called. For example::
67 67
68 68 In [2]: alias bracket echo "Input in brackets: <%l>"
69 69 In [3]: bracket hello world
70 70 Input in brackets: <hello world>
71 71
72 72 You can also define aliases with parameters using %s specifiers (one
73 73 per parameter)::
74 74
75 75 In [1]: alias parts echo first %s second %s
76 76 In [2]: %parts A B
77 77 first A second B
78 78 In [3]: %parts A
79 79 Incorrect number of arguments: 2 expected.
80 80 parts is an alias to: 'echo first %s second %s'
81 81
82 82 Note that %l and %s are mutually exclusive. You can only use one or
83 83 the other in your aliases.
84 84
85 85 Aliases expand Python variables just like system calls using ! or !!
86 86 do: all expressions prefixed with '$' get expanded. For details of
87 87 the semantic rules, see PEP-215:
88 88 http://www.python.org/peps/pep-0215.html. This is the library used by
89 89 IPython for variable expansion. If you want to access a true shell
90 90 variable, an extra $ is necessary to prevent its expansion by
91 91 IPython::
92 92
93 93 In [6]: alias show echo
94 94 In [7]: PATH='A Python string'
95 95 In [8]: show $PATH
96 96 A Python string
97 97 In [9]: show $$PATH
98 98 /usr/local/lf9560/bin:/usr/local/intel/compiler70/ia32/bin:...
99 99
100 100 You can use the alias facility to acess all of $PATH. See the %rehash
101 101 and %rehashx functions, which automatically create aliases for the
102 102 contents of your $PATH.
103 103
104 104 If called with no parameters, %alias prints the current alias table."""
105 105
106 106 par = parameter_s.strip()
107 107 if not par:
108 108 aliases = sorted(self.shell.alias_manager.aliases)
109 109 # stored = self.shell.db.get('stored_aliases', {} )
110 110 # for k, v in stored:
111 111 # atab.append(k, v[0])
112 112
113 113 print("Total number of aliases:", len(aliases))
114 114 sys.stdout.flush()
115 115 return aliases
116 116
117 117 # Now try to define a new one
118 118 try:
119 119 alias,cmd = par.split(None, 1)
120 120 except TypeError:
121 121 print(oinspect.getdoc(self.alias))
122 122 return
123 123
124 124 try:
125 125 self.shell.alias_manager.define_alias(alias, cmd)
126 126 except AliasError as e:
127 127 print(e)
128 128 # end magic_alias
129 129
130 130 @line_magic
131 131 def unalias(self, parameter_s=''):
132 132 """Remove an alias"""
133 133
134 134 aname = parameter_s.strip()
135 135 try:
136 136 self.shell.alias_manager.undefine_alias(aname)
137 137 except ValueError as e:
138 138 print(e)
139 139 return
140 140
141 141 stored = self.shell.db.get('stored_aliases', {} )
142 142 if aname in stored:
143 143 print("Removing %stored alias",aname)
144 144 del stored[aname]
145 145 self.shell.db['stored_aliases'] = stored
146 146
147 147 @line_magic
148 148 def rehashx(self, parameter_s=''):
149 149 """Update the alias table with all executable files in $PATH.
150 150
151 151 This version explicitly checks that every entry in $PATH is a file
152 152 with execute access (os.X_OK), so it is much slower than %rehash.
153 153
154 154 Under Windows, it checks executability as a match against a
155 155 '|'-separated string of extensions, stored in the IPython config
156 156 variable win_exec_ext. This defaults to 'exe|com|bat'.
157 157
158 158 This function also resets the root module cache of module completer,
159 159 used on slow filesystems.
160 160 """
161 161 from IPython.core.alias import InvalidAliasError
162 162
163 163 # for the benefit of module completer in ipy_completers.py
164 164 del self.shell.db['rootmodules_cache']
165 165
166 166 path = [os.path.abspath(os.path.expanduser(p)) for p in
167 167 os.environ.get('PATH','').split(os.pathsep)]
168 168 path = filter(os.path.isdir,path)
169 169
170 170 syscmdlist = []
171 171 # Now define isexec in a cross platform manner.
172 172 if os.name == 'posix':
173 173 isexec = lambda fname:os.path.isfile(fname) and \
174 174 os.access(fname,os.X_OK)
175 175 else:
176 176 try:
177 177 winext = os.environ['pathext'].replace(';','|').replace('.','')
178 178 except KeyError:
179 179 winext = 'exe|com|bat|py'
180 180 if 'py' not in winext:
181 181 winext += '|py'
182 182 execre = re.compile(r'(.*)\.(%s)$' % winext,re.IGNORECASE)
183 183 isexec = lambda fname:os.path.isfile(fname) and execre.match(fname)
184 184 savedir = py3compat.getcwd()
185 185
186 186 # Now walk the paths looking for executables to alias.
187 187 try:
188 188 # write the whole loop for posix/Windows so we don't have an if in
189 189 # the innermost part
190 190 if os.name == 'posix':
191 191 for pdir in path:
192 192 os.chdir(pdir)
193 193 for ff in os.listdir(pdir):
194 194 if isexec(ff):
195 195 try:
196 196 # Removes dots from the name since ipython
197 197 # will assume names with dots to be python.
198 198 if not self.shell.alias_manager.is_alias(ff):
199 199 self.shell.alias_manager.define_alias(
200 200 ff.replace('.',''), ff)
201 201 except InvalidAliasError:
202 202 pass
203 203 else:
204 204 syscmdlist.append(ff)
205 205 else:
206 206 no_alias = Alias.blacklist
207 207 for pdir in path:
208 208 os.chdir(pdir)
209 209 for ff in os.listdir(pdir):
210 210 base, ext = os.path.splitext(ff)
211 211 if isexec(ff) and base.lower() not in no_alias:
212 212 if ext.lower() == '.exe':
213 213 ff = base
214 214 try:
215 215 # Removes dots from the name since ipython
216 216 # will assume names with dots to be python.
217 217 self.shell.alias_manager.define_alias(
218 218 base.lower().replace('.',''), ff)
219 219 except InvalidAliasError:
220 220 pass
221 221 syscmdlist.append(ff)
222 222 self.shell.db['syscmdlist'] = syscmdlist
223 223 finally:
224 224 os.chdir(savedir)
225 225
226 226 @skip_doctest
227 227 @line_magic
228 228 def pwd(self, parameter_s=''):
229 229 """Return the current working directory path.
230 230
231 231 Examples
232 232 --------
233 233 ::
234 234
235 235 In [9]: pwd
236 236 Out[9]: '/home/tsuser/sprint/ipython'
237 237 """
238 238 return py3compat.getcwd()
239 239
240 240 @skip_doctest
241 241 @line_magic
242 242 def cd(self, parameter_s=''):
243 243 """Change the current working directory.
244 244
245 245 This command automatically maintains an internal list of directories
246 246 you visit during your IPython session, in the variable _dh. The
247 247 command %dhist shows this history nicely formatted. You can also
248 248 do 'cd -<tab>' to see directory history conveniently.
249 249
250 250 Usage:
251 251
252 252 cd 'dir': changes to directory 'dir'.
253 253
254 254 cd -: changes to the last visited directory.
255 255
256 256 cd -<n>: changes to the n-th directory in the directory history.
257 257
258 258 cd --foo: change to directory that matches 'foo' in history
259 259
260 260 cd -b <bookmark_name>: jump to a bookmark set by %bookmark
261 261 (note: cd <bookmark_name> is enough if there is no
262 262 directory <bookmark_name>, but a bookmark with the name exists.)
263 263 'cd -b <tab>' allows you to tab-complete bookmark names.
264 264
265 265 Options:
266 266
267 267 -q: quiet. Do not print the working directory after the cd command is
268 268 executed. By default IPython's cd command does print this directory,
269 269 since the default prompts do not display path information.
270 270
271 271 Note that !cd doesn't work for this purpose because the shell where
272 272 !command runs is immediately discarded after executing 'command'.
273 273
274 274 Examples
275 275 --------
276 276 ::
277 277
278 278 In [10]: cd parent/child
279 279 /home/tsuser/parent/child
280 280 """
281 281
282 282 oldcwd = py3compat.getcwd()
283 283 numcd = re.match(r'(-)(\d+)$',parameter_s)
284 284 # jump in directory history by number
285 285 if numcd:
286 286 nn = int(numcd.group(2))
287 287 try:
288 288 ps = self.shell.user_ns['_dh'][nn]
289 289 except IndexError:
290 290 print('The requested directory does not exist in history.')
291 291 return
292 292 else:
293 293 opts = {}
294 294 elif parameter_s.startswith('--'):
295 295 ps = None
296 296 fallback = None
297 297 pat = parameter_s[2:]
298 298 dh = self.shell.user_ns['_dh']
299 299 # first search only by basename (last component)
300 300 for ent in reversed(dh):
301 301 if pat in os.path.basename(ent) and os.path.isdir(ent):
302 302 ps = ent
303 303 break
304 304
305 305 if fallback is None and pat in ent and os.path.isdir(ent):
306 306 fallback = ent
307 307
308 308 # if we have no last part match, pick the first full path match
309 309 if ps is None:
310 310 ps = fallback
311 311
312 312 if ps is None:
313 313 print("No matching entry in directory history")
314 314 return
315 315 else:
316 316 opts = {}
317 317
318 318
319 319 else:
320 320 #turn all non-space-escaping backslashes to slashes,
321 321 # for c:\windows\directory\names\
322 322 parameter_s = re.sub(r'\\(?! )','/', parameter_s)
323 323 opts,ps = self.parse_options(parameter_s,'qb',mode='string')
324 324 # jump to previous
325 325 if ps == '-':
326 326 try:
327 327 ps = self.shell.user_ns['_dh'][-2]
328 328 except IndexError:
329 329 raise UsageError('%cd -: No previous directory to change to.')
330 330 # jump to bookmark if needed
331 331 else:
332 332 if not os.path.isdir(ps) or 'b' in opts:
333 333 bkms = self.shell.db.get('bookmarks', {})
334 334
335 335 if ps in bkms:
336 336 target = bkms[ps]
337 337 print('(bookmark:%s) -> %s' % (ps, target))
338 338 ps = target
339 339 else:
340 340 if 'b' in opts:
341 341 raise UsageError("Bookmark '%s' not found. "
342 342 "Use '%%bookmark -l' to see your bookmarks." % ps)
343 343
344 344 # strip extra quotes on Windows, because os.chdir doesn't like them
345 345 ps = unquote_filename(ps)
346 346 # at this point ps should point to the target dir
347 347 if ps:
348 348 try:
349 349 os.chdir(os.path.expanduser(ps))
350 350 if hasattr(self.shell, 'term_title') and self.shell.term_title:
351 351 set_term_title('IPython: ' + abbrev_cwd())
352 352 except OSError:
353 353 print(sys.exc_info()[1])
354 354 else:
355 355 cwd = py3compat.getcwd()
356 356 dhist = self.shell.user_ns['_dh']
357 357 if oldcwd != cwd:
358 358 dhist.append(cwd)
359 359 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
360 360
361 361 else:
362 362 os.chdir(self.shell.home_dir)
363 363 if hasattr(self.shell, 'term_title') and self.shell.term_title:
364 364 set_term_title('IPython: ' + '~')
365 365 cwd = py3compat.getcwd()
366 366 dhist = self.shell.user_ns['_dh']
367 367
368 368 if oldcwd != cwd:
369 369 dhist.append(cwd)
370 370 self.shell.db['dhist'] = compress_dhist(dhist)[-100:]
371 371 if not 'q' in opts and self.shell.user_ns['_dh']:
372 372 print(self.shell.user_ns['_dh'][-1])
373 373
374
375 374 @line_magic
376 375 def env(self, parameter_s=''):
377 376 """List environment variables."""
378
377 if parameter_s.strip():
378 split = '=' if '=' in parameter_s else ' '
379 bits = parameter_s.split(split)
380 if len(bits) == 1:
381 key = parameter_s.strip()
382 if key in os.environ:
383 return os.environ[key]
384 else:
385 err = "Environment does not have key: {0}".format(key)
386 raise UsageError(err)
387 if len(bits) > 1:
388 return self.set_env(parameter_s)
379 389 return dict(os.environ)
380 390
381 391 @line_magic
392 def set_env(self, parameter_s):
393 """Set environment variables. Assumptions are that either "val" is a
394 name in the user namespace, or val is something that evaluates to a
395 string.
396
397 Usage:\\
398 %set_env var val
399 """
400 split = '=' if '=' in parameter_s else ' '
401 bits = parameter_s.split(split, 1)
402 if not parameter_s.strip() or len(bits)<2:
403 raise UsageError("usage is 'set_env var=val'")
404 var = bits[0].strip()
405 val = bits[1].strip()
406 if re.match(r'.*\s.*', var):
407 # an environment variable with whitespace is almost certainly
408 # not what the user intended. what's more likely is the wrong
409 # split was chosen, ie for "set_env cmd_args A=B", we chose
410 # '=' for the split and should have chosen ' '. to get around
411 # this, users should just assign directly to os.environ or use
412 # standard magic {var} expansion.
413 err = "refusing to set env var with whitespace: '{0}'"
414 err = err.format(val)
415 raise UsageError(err)
416 os.environ[var] = val
417 print('env: {0}={1}'.format(var,val))
418
419 @line_magic
382 420 def pushd(self, parameter_s=''):
383 421 """Place the current dir on stack and change directory.
384 422
385 423 Usage:\\
386 424 %pushd ['dirname']
387 425 """
388 426
389 427 dir_s = self.shell.dir_stack
390 428 tgt = os.path.expanduser(unquote_filename(parameter_s))
391 429 cwd = py3compat.getcwd().replace(self.shell.home_dir,'~')
392 430 if tgt:
393 431 self.cd(parameter_s)
394 432 dir_s.insert(0,cwd)
395 433 return self.shell.magic('dirs')
396 434
397 435 @line_magic
398 436 def popd(self, parameter_s=''):
399 437 """Change to directory popped off the top of the stack.
400 438 """
401 439 if not self.shell.dir_stack:
402 440 raise UsageError("%popd on empty stack")
403 441 top = self.shell.dir_stack.pop(0)
404 442 self.cd(top)
405 443 print("popd ->",top)
406 444
407 445 @line_magic
408 446 def dirs(self, parameter_s=''):
409 447 """Return the current directory stack."""
410 448
411 449 return self.shell.dir_stack
412 450
413 451 @line_magic
414 452 def dhist(self, parameter_s=''):
415 453 """Print your history of visited directories.
416 454
417 455 %dhist -> print full history\\
418 456 %dhist n -> print last n entries only\\
419 457 %dhist n1 n2 -> print entries between n1 and n2 (n2 not included)\\
420 458
421 459 This history is automatically maintained by the %cd command, and
422 460 always available as the global list variable _dh. You can use %cd -<n>
423 461 to go to directory number <n>.
424 462
425 463 Note that most of time, you should view directory history by entering
426 464 cd -<TAB>.
427 465
428 466 """
429 467
430 468 dh = self.shell.user_ns['_dh']
431 469 if parameter_s:
432 470 try:
433 471 args = map(int,parameter_s.split())
434 472 except:
435 473 self.arg_err(self.dhist)
436 474 return
437 475 if len(args) == 1:
438 476 ini,fin = max(len(dh)-(args[0]),0),len(dh)
439 477 elif len(args) == 2:
440 478 ini,fin = args
441 479 fin = min(fin, len(dh))
442 480 else:
443 481 self.arg_err(self.dhist)
444 482 return
445 483 else:
446 484 ini,fin = 0,len(dh)
447 485 print('Directory history (kept in _dh)')
448 486 for i in range(ini, fin):
449 487 print("%d: %s" % (i, dh[i]))
450 488
451 489 @skip_doctest
452 490 @line_magic
453 491 def sc(self, parameter_s=''):
454 492 """Shell capture - run shell command and capture output (DEPRECATED use !).
455 493
456 494 DEPRECATED. Suboptimal, retained for backwards compatibility.
457 495
458 496 You should use the form 'var = !command' instead. Example:
459 497
460 498 "%sc -l myfiles = ls ~" should now be written as
461 499
462 500 "myfiles = !ls ~"
463 501
464 502 myfiles.s, myfiles.l and myfiles.n still apply as documented
465 503 below.
466 504
467 505 --
468 506 %sc [options] varname=command
469 507
470 508 IPython will run the given command using commands.getoutput(), and
471 509 will then update the user's interactive namespace with a variable
472 510 called varname, containing the value of the call. Your command can
473 511 contain shell wildcards, pipes, etc.
474 512
475 513 The '=' sign in the syntax is mandatory, and the variable name you
476 514 supply must follow Python's standard conventions for valid names.
477 515
478 516 (A special format without variable name exists for internal use)
479 517
480 518 Options:
481 519
482 520 -l: list output. Split the output on newlines into a list before
483 521 assigning it to the given variable. By default the output is stored
484 522 as a single string.
485 523
486 524 -v: verbose. Print the contents of the variable.
487 525
488 526 In most cases you should not need to split as a list, because the
489 527 returned value is a special type of string which can automatically
490 528 provide its contents either as a list (split on newlines) or as a
491 529 space-separated string. These are convenient, respectively, either
492 530 for sequential processing or to be passed to a shell command.
493 531
494 532 For example::
495 533
496 534 # Capture into variable a
497 535 In [1]: sc a=ls *py
498 536
499 537 # a is a string with embedded newlines
500 538 In [2]: a
501 539 Out[2]: 'setup.py\\nwin32_manual_post_install.py'
502 540
503 541 # which can be seen as a list:
504 542 In [3]: a.l
505 543 Out[3]: ['setup.py', 'win32_manual_post_install.py']
506 544
507 545 # or as a whitespace-separated string:
508 546 In [4]: a.s
509 547 Out[4]: 'setup.py win32_manual_post_install.py'
510 548
511 549 # a.s is useful to pass as a single command line:
512 550 In [5]: !wc -l $a.s
513 551 146 setup.py
514 552 130 win32_manual_post_install.py
515 553 276 total
516 554
517 555 # while the list form is useful to loop over:
518 556 In [6]: for f in a.l:
519 557 ...: !wc -l $f
520 558 ...:
521 559 146 setup.py
522 560 130 win32_manual_post_install.py
523 561
524 562 Similarly, the lists returned by the -l option are also special, in
525 563 the sense that you can equally invoke the .s attribute on them to
526 564 automatically get a whitespace-separated string from their contents::
527 565
528 566 In [7]: sc -l b=ls *py
529 567
530 568 In [8]: b
531 569 Out[8]: ['setup.py', 'win32_manual_post_install.py']
532 570
533 571 In [9]: b.s
534 572 Out[9]: 'setup.py win32_manual_post_install.py'
535 573
536 574 In summary, both the lists and strings used for output capture have
537 575 the following special attributes::
538 576
539 577 .l (or .list) : value as list.
540 578 .n (or .nlstr): value as newline-separated string.
541 579 .s (or .spstr): value as space-separated string.
542 580 """
543 581
544 582 opts,args = self.parse_options(parameter_s, 'lv')
545 583 # Try to get a variable name and command to run
546 584 try:
547 585 # the variable name must be obtained from the parse_options
548 586 # output, which uses shlex.split to strip options out.
549 587 var,_ = args.split('=', 1)
550 588 var = var.strip()
551 589 # But the command has to be extracted from the original input
552 590 # parameter_s, not on what parse_options returns, to avoid the
553 591 # quote stripping which shlex.split performs on it.
554 592 _,cmd = parameter_s.split('=', 1)
555 593 except ValueError:
556 594 var,cmd = '',''
557 595 # If all looks ok, proceed
558 596 split = 'l' in opts
559 597 out = self.shell.getoutput(cmd, split=split)
560 598 if 'v' in opts:
561 599 print('%s ==\n%s' % (var, pformat(out)))
562 600 if var:
563 601 self.shell.user_ns.update({var:out})
564 602 else:
565 603 return out
566 604
567 605 @line_cell_magic
568 606 def sx(self, line='', cell=None):
569 607 """Shell execute - run shell command and capture output (!! is short-hand).
570 608
571 609 %sx command
572 610
573 611 IPython will run the given command using commands.getoutput(), and
574 612 return the result formatted as a list (split on '\\n'). Since the
575 613 output is _returned_, it will be stored in ipython's regular output
576 614 cache Out[N] and in the '_N' automatic variables.
577 615
578 616 Notes:
579 617
580 618 1) If an input line begins with '!!', then %sx is automatically
581 619 invoked. That is, while::
582 620
583 621 !ls
584 622
585 623 causes ipython to simply issue system('ls'), typing::
586 624
587 625 !!ls
588 626
589 627 is a shorthand equivalent to::
590 628
591 629 %sx ls
592 630
593 631 2) %sx differs from %sc in that %sx automatically splits into a list,
594 632 like '%sc -l'. The reason for this is to make it as easy as possible
595 633 to process line-oriented shell output via further python commands.
596 634 %sc is meant to provide much finer control, but requires more
597 635 typing.
598 636
599 637 3) Just like %sc -l, this is a list with special attributes:
600 638 ::
601 639
602 640 .l (or .list) : value as list.
603 641 .n (or .nlstr): value as newline-separated string.
604 642 .s (or .spstr): value as whitespace-separated string.
605 643
606 644 This is very useful when trying to use such lists as arguments to
607 645 system commands."""
608 646
609 647 if cell is None:
610 648 # line magic
611 649 return self.shell.getoutput(line)
612 650 else:
613 651 opts,args = self.parse_options(line, '', 'out=')
614 652 output = self.shell.getoutput(cell)
615 653 out_name = opts.get('out', opts.get('o'))
616 654 if out_name:
617 655 self.shell.user_ns[out_name] = output
618 656 else:
619 657 return output
620 658
621 659 system = line_cell_magic('system')(sx)
622 660 bang = cell_magic('!')(sx)
623 661
624 662 @line_magic
625 663 def bookmark(self, parameter_s=''):
626 664 """Manage IPython's bookmark system.
627 665
628 666 %bookmark <name> - set bookmark to current dir
629 667 %bookmark <name> <dir> - set bookmark to <dir>
630 668 %bookmark -l - list all bookmarks
631 669 %bookmark -d <name> - remove bookmark
632 670 %bookmark -r - remove all bookmarks
633 671
634 672 You can later on access a bookmarked folder with::
635 673
636 674 %cd -b <name>
637 675
638 676 or simply '%cd <name>' if there is no directory called <name> AND
639 677 there is such a bookmark defined.
640 678
641 679 Your bookmarks persist through IPython sessions, but they are
642 680 associated with each profile."""
643 681
644 682 opts,args = self.parse_options(parameter_s,'drl',mode='list')
645 683 if len(args) > 2:
646 684 raise UsageError("%bookmark: too many arguments")
647 685
648 686 bkms = self.shell.db.get('bookmarks',{})
649 687
650 688 if 'd' in opts:
651 689 try:
652 690 todel = args[0]
653 691 except IndexError:
654 692 raise UsageError(
655 693 "%bookmark -d: must provide a bookmark to delete")
656 694 else:
657 695 try:
658 696 del bkms[todel]
659 697 except KeyError:
660 698 raise UsageError(
661 699 "%%bookmark -d: Can't delete bookmark '%s'" % todel)
662 700
663 701 elif 'r' in opts:
664 702 bkms = {}
665 703 elif 'l' in opts:
666 704 bks = sorted(bkms)
667 705 if bks:
668 706 size = max(map(len, bks))
669 707 else:
670 708 size = 0
671 709 fmt = '%-'+str(size)+'s -> %s'
672 710 print('Current bookmarks:')
673 711 for bk in bks:
674 712 print(fmt % (bk, bkms[bk]))
675 713 else:
676 714 if not args:
677 715 raise UsageError("%bookmark: You must specify the bookmark name")
678 716 elif len(args)==1:
679 717 bkms[args[0]] = py3compat.getcwd()
680 718 elif len(args)==2:
681 719 bkms[args[0]] = args[1]
682 720 self.shell.db['bookmarks'] = bkms
683 721
684 722 @line_magic
685 723 def pycat(self, parameter_s=''):
686 724 """Show a syntax-highlighted file through a pager.
687 725
688 726 This magic is similar to the cat utility, but it will assume the file
689 727 to be Python source and will show it with syntax highlighting.
690 728
691 729 This magic command can either take a local filename, an url,
692 730 an history range (see %history) or a macro as argument ::
693 731
694 732 %pycat myscript.py
695 733 %pycat 7-27
696 734 %pycat myMacro
697 735 %pycat http://www.example.com/myscript.py
698 736 """
699 737 if not parameter_s:
700 738 raise UsageError('Missing filename, URL, input history range, '
701 739 'or macro.')
702 740
703 741 try :
704 742 cont = self.shell.find_user_code(parameter_s, skip_encoding_cookie=False)
705 743 except (ValueError, IOError):
706 744 print("Error: no such file, variable, URL, history range or macro")
707 745 return
708 746
709 747 page.page(self.shell.pycolorize(source_to_unicode(cont)))
710 748
711 749 @magic_arguments.magic_arguments()
712 750 @magic_arguments.argument(
713 751 '-a', '--append', action='store_true', default=False,
714 752 help='Append contents of the cell to an existing file. '
715 753 'The file will be created if it does not exist.'
716 754 )
717 755 @magic_arguments.argument(
718 756 'filename', type=unicode_type,
719 757 help='file to write'
720 758 )
721 759 @cell_magic
722 760 def writefile(self, line, cell):
723 761 """Write the contents of the cell to a file.
724 762
725 763 The file will be overwritten unless the -a (--append) flag is specified.
726 764 """
727 765 args = magic_arguments.parse_argstring(self.writefile, line)
728 766 filename = os.path.expanduser(unquote_filename(args.filename))
729 767
730 768 if os.path.exists(filename):
731 769 if args.append:
732 770 print("Appending to %s" % filename)
733 771 else:
734 772 print("Overwriting %s" % filename)
735 773 else:
736 774 print("Writing %s" % filename)
737 775
738 776 mode = 'a' if args.append else 'w'
739 777 with io.open(filename, mode, encoding='utf-8') as f:
740 778 f.write(cell)
@@ -1,955 +1,982 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Tests for various magic functions.
3 3
4 4 Needs to be run by nose (to make ipython session available).
5 5 """
6 6 from __future__ import absolute_import
7 7
8 8 import io
9 9 import os
10 10 import sys
11 11 from unittest import TestCase, skipIf
12 12
13 13 try:
14 14 from importlib import invalidate_caches # Required from Python 3.3
15 15 except ImportError:
16 16 def invalidate_caches():
17 17 pass
18 18
19 19 import nose.tools as nt
20 20
21 21 from IPython.core import magic
22 from IPython.core.error import UsageError
22 23 from IPython.core.magic import (Magics, magics_class, line_magic,
23 24 cell_magic, line_cell_magic,
24 25 register_line_magic, register_cell_magic,
25 26 register_line_cell_magic)
26 27 from IPython.core.magics import execution, script, code
27 28 from IPython.testing import decorators as dec
28 29 from IPython.testing import tools as tt
29 30 from IPython.utils import py3compat
30 31 from IPython.utils.io import capture_output
31 32 from IPython.utils.tempdir import TemporaryDirectory
32 33 from IPython.utils.process import find_cmd
33 34
34 35 if py3compat.PY3:
35 36 from io import StringIO
36 37 else:
37 38 from StringIO import StringIO
38 39
39 40
40 41 @magic.magics_class
41 42 class DummyMagics(magic.Magics): pass
42 43
43 44 def test_extract_code_ranges():
44 45 instr = "1 3 5-6 7-9 10:15 17: :10 10- -13 :"
45 46 expected = [(0, 1),
46 47 (2, 3),
47 48 (4, 6),
48 49 (6, 9),
49 50 (9, 14),
50 51 (16, None),
51 52 (None, 9),
52 53 (9, None),
53 54 (None, 13),
54 55 (None, None)]
55 56 actual = list(code.extract_code_ranges(instr))
56 57 nt.assert_equal(actual, expected)
57 58
58 59 def test_extract_symbols():
59 60 source = """import foo\na = 10\ndef b():\n return 42\n\n\nclass A: pass\n\n\n"""
60 61 symbols_args = ["a", "b", "A", "A,b", "A,a", "z"]
61 62 expected = [([], ['a']),
62 63 (["def b():\n return 42\n"], []),
63 64 (["class A: pass\n"], []),
64 65 (["class A: pass\n", "def b():\n return 42\n"], []),
65 66 (["class A: pass\n"], ['a']),
66 67 ([], ['z'])]
67 68 for symbols, exp in zip(symbols_args, expected):
68 69 nt.assert_equal(code.extract_symbols(source, symbols), exp)
69 70
70 71
71 72 def test_extract_symbols_raises_exception_with_non_python_code():
72 73 source = ("=begin A Ruby program :)=end\n"
73 74 "def hello\n"
74 75 "puts 'Hello world'\n"
75 76 "end")
76 77 with nt.assert_raises(SyntaxError):
77 78 code.extract_symbols(source, "hello")
78 79
79 80 def test_config():
80 81 """ test that config magic does not raise
81 82 can happen if Configurable init is moved too early into
82 83 Magics.__init__ as then a Config object will be registerd as a
83 84 magic.
84 85 """
85 86 ## should not raise.
86 87 _ip.magic('config')
87 88
88 89 def test_rehashx():
89 90 # clear up everything
90 91 _ip = get_ipython()
91 92 _ip.alias_manager.clear_aliases()
92 93 del _ip.db['syscmdlist']
93 94
94 95 _ip.magic('rehashx')
95 96 # Practically ALL ipython development systems will have more than 10 aliases
96 97
97 98 nt.assert_true(len(_ip.alias_manager.aliases) > 10)
98 99 for name, cmd in _ip.alias_manager.aliases:
99 100 # we must strip dots from alias names
100 101 nt.assert_not_in('.', name)
101 102
102 103 # rehashx must fill up syscmdlist
103 104 scoms = _ip.db['syscmdlist']
104 105 nt.assert_true(len(scoms) > 10)
105 106
106 107
107 108 def test_magic_parse_options():
108 109 """Test that we don't mangle paths when parsing magic options."""
109 110 ip = get_ipython()
110 111 path = 'c:\\x'
111 112 m = DummyMagics(ip)
112 113 opts = m.parse_options('-f %s' % path,'f:')[0]
113 114 # argv splitting is os-dependent
114 115 if os.name == 'posix':
115 116 expected = 'c:x'
116 117 else:
117 118 expected = path
118 119 nt.assert_equal(opts['f'], expected)
119 120
120 121 def test_magic_parse_long_options():
121 122 """Magic.parse_options can handle --foo=bar long options"""
122 123 ip = get_ipython()
123 124 m = DummyMagics(ip)
124 125 opts, _ = m.parse_options('--foo --bar=bubble', 'a', 'foo', 'bar=')
125 126 nt.assert_in('foo', opts)
126 127 nt.assert_in('bar', opts)
127 128 nt.assert_equal(opts['bar'], "bubble")
128 129
129 130
130 131 @dec.skip_without('sqlite3')
131 132 def doctest_hist_f():
132 133 """Test %hist -f with temporary filename.
133 134
134 135 In [9]: import tempfile
135 136
136 137 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
137 138
138 139 In [11]: %hist -nl -f $tfile 3
139 140
140 141 In [13]: import os; os.unlink(tfile)
141 142 """
142 143
143 144
144 145 @dec.skip_without('sqlite3')
145 146 def doctest_hist_r():
146 147 """Test %hist -r
147 148
148 149 XXX - This test is not recording the output correctly. For some reason, in
149 150 testing mode the raw history isn't getting populated. No idea why.
150 151 Disabling the output checking for now, though at least we do run it.
151 152
152 153 In [1]: 'hist' in _ip.lsmagic()
153 154 Out[1]: True
154 155
155 156 In [2]: x=1
156 157
157 158 In [3]: %hist -rl 2
158 159 x=1 # random
159 160 %hist -r 2
160 161 """
161 162
162 163
163 164 @dec.skip_without('sqlite3')
164 165 def doctest_hist_op():
165 166 """Test %hist -op
166 167
167 168 In [1]: class b(float):
168 169 ...: pass
169 170 ...:
170 171
171 172 In [2]: class s(object):
172 173 ...: def __str__(self):
173 174 ...: return 's'
174 175 ...:
175 176
176 177 In [3]:
177 178
178 179 In [4]: class r(b):
179 180 ...: def __repr__(self):
180 181 ...: return 'r'
181 182 ...:
182 183
183 184 In [5]: class sr(s,r): pass
184 185 ...:
185 186
186 187 In [6]:
187 188
188 189 In [7]: bb=b()
189 190
190 191 In [8]: ss=s()
191 192
192 193 In [9]: rr=r()
193 194
194 195 In [10]: ssrr=sr()
195 196
196 197 In [11]: 4.5
197 198 Out[11]: 4.5
198 199
199 200 In [12]: str(ss)
200 201 Out[12]: 's'
201 202
202 203 In [13]:
203 204
204 205 In [14]: %hist -op
205 206 >>> class b:
206 207 ... pass
207 208 ...
208 209 >>> class s(b):
209 210 ... def __str__(self):
210 211 ... return 's'
211 212 ...
212 213 >>>
213 214 >>> class r(b):
214 215 ... def __repr__(self):
215 216 ... return 'r'
216 217 ...
217 218 >>> class sr(s,r): pass
218 219 >>>
219 220 >>> bb=b()
220 221 >>> ss=s()
221 222 >>> rr=r()
222 223 >>> ssrr=sr()
223 224 >>> 4.5
224 225 4.5
225 226 >>> str(ss)
226 227 's'
227 228 >>>
228 229 """
229 230
230 231 def test_hist_pof():
231 232 ip = get_ipython()
232 233 ip.run_cell(u"1+2", store_history=True)
233 234 #raise Exception(ip.history_manager.session_number)
234 235 #raise Exception(list(ip.history_manager._get_range_session()))
235 236 with TemporaryDirectory() as td:
236 237 tf = os.path.join(td, 'hist.py')
237 238 ip.run_line_magic('history', '-pof %s' % tf)
238 239 assert os.path.isfile(tf)
239 240
240 241
241 242 @dec.skip_without('sqlite3')
242 243 def test_macro():
243 244 ip = get_ipython()
244 245 ip.history_manager.reset() # Clear any existing history.
245 246 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
246 247 for i, cmd in enumerate(cmds, start=1):
247 248 ip.history_manager.store_inputs(i, cmd)
248 249 ip.magic("macro test 1-3")
249 250 nt.assert_equal(ip.user_ns["test"].value, "\n".join(cmds)+"\n")
250 251
251 252 # List macros
252 253 nt.assert_in("test", ip.magic("macro"))
253 254
254 255
255 256 @dec.skip_without('sqlite3')
256 257 def test_macro_run():
257 258 """Test that we can run a multi-line macro successfully."""
258 259 ip = get_ipython()
259 260 ip.history_manager.reset()
260 261 cmds = ["a=10", "a+=1", py3compat.doctest_refactor_print("print a"),
261 262 "%macro test 2-3"]
262 263 for cmd in cmds:
263 264 ip.run_cell(cmd, store_history=True)
264 265 nt.assert_equal(ip.user_ns["test"].value,
265 266 py3compat.doctest_refactor_print("a+=1\nprint a\n"))
266 267 with tt.AssertPrints("12"):
267 268 ip.run_cell("test")
268 269 with tt.AssertPrints("13"):
269 270 ip.run_cell("test")
270 271
271 272
272 273 def test_magic_magic():
273 274 """Test %magic"""
274 275 ip = get_ipython()
275 276 with capture_output() as captured:
276 277 ip.magic("magic")
277 278
278 279 stdout = captured.stdout
279 280 nt.assert_in('%magic', stdout)
280 281 nt.assert_in('IPython', stdout)
281 282 nt.assert_in('Available', stdout)
282 283
283 284
284 285 @dec.skipif_not_numpy
285 286 def test_numpy_reset_array_undec():
286 287 "Test '%reset array' functionality"
287 288 _ip.ex('import numpy as np')
288 289 _ip.ex('a = np.empty(2)')
289 290 nt.assert_in('a', _ip.user_ns)
290 291 _ip.magic('reset -f array')
291 292 nt.assert_not_in('a', _ip.user_ns)
292 293
293 294 def test_reset_out():
294 295 "Test '%reset out' magic"
295 296 _ip.run_cell("parrot = 'dead'", store_history=True)
296 297 # test '%reset -f out', make an Out prompt
297 298 _ip.run_cell("parrot", store_history=True)
298 299 nt.assert_true('dead' in [_ip.user_ns[x] for x in ('_','__','___')])
299 300 _ip.magic('reset -f out')
300 301 nt.assert_false('dead' in [_ip.user_ns[x] for x in ('_','__','___')])
301 302 nt.assert_equal(len(_ip.user_ns['Out']), 0)
302 303
303 304 def test_reset_in():
304 305 "Test '%reset in' magic"
305 306 # test '%reset -f in'
306 307 _ip.run_cell("parrot", store_history=True)
307 308 nt.assert_true('parrot' in [_ip.user_ns[x] for x in ('_i','_ii','_iii')])
308 309 _ip.magic('%reset -f in')
309 310 nt.assert_false('parrot' in [_ip.user_ns[x] for x in ('_i','_ii','_iii')])
310 311 nt.assert_equal(len(set(_ip.user_ns['In'])), 1)
311 312
312 313 def test_reset_dhist():
313 314 "Test '%reset dhist' magic"
314 315 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
315 316 _ip.magic('cd ' + os.path.dirname(nt.__file__))
316 317 _ip.magic('cd -')
317 318 nt.assert_true(len(_ip.user_ns['_dh']) > 0)
318 319 _ip.magic('reset -f dhist')
319 320 nt.assert_equal(len(_ip.user_ns['_dh']), 0)
320 321 _ip.run_cell("_dh = [d for d in tmp]") #restore
321 322
322 323 def test_reset_in_length():
323 324 "Test that '%reset in' preserves In[] length"
324 325 _ip.run_cell("print 'foo'")
325 326 _ip.run_cell("reset -f in")
326 327 nt.assert_equal(len(_ip.user_ns['In']), _ip.displayhook.prompt_count+1)
327 328
328 329 def test_tb_syntaxerror():
329 330 """test %tb after a SyntaxError"""
330 331 ip = get_ipython()
331 332 ip.run_cell("for")
332 333
333 334 # trap and validate stdout
334 335 save_stdout = sys.stdout
335 336 try:
336 337 sys.stdout = StringIO()
337 338 ip.run_cell("%tb")
338 339 out = sys.stdout.getvalue()
339 340 finally:
340 341 sys.stdout = save_stdout
341 342 # trim output, and only check the last line
342 343 last_line = out.rstrip().splitlines()[-1].strip()
343 344 nt.assert_equal(last_line, "SyntaxError: invalid syntax")
344 345
345 346
346 347 def test_time():
347 348 ip = get_ipython()
348 349
349 350 with tt.AssertPrints("Wall time: "):
350 351 ip.run_cell("%time None")
351 352
352 353 ip.run_cell("def f(kmjy):\n"
353 354 " %time print (2*kmjy)")
354 355
355 356 with tt.AssertPrints("Wall time: "):
356 357 with tt.AssertPrints("hihi", suppress=False):
357 358 ip.run_cell("f('hi')")
358 359
359 360
360 361 @dec.skip_win32
361 362 def test_time2():
362 363 ip = get_ipython()
363 364
364 365 with tt.AssertPrints("CPU times: user "):
365 366 ip.run_cell("%time None")
366 367
367 368 def test_time3():
368 369 """Erroneous magic function calls, issue gh-3334"""
369 370 ip = get_ipython()
370 371 ip.user_ns.pop('run', None)
371 372
372 373 with tt.AssertNotPrints("not found", channel='stderr'):
373 374 ip.run_cell("%%time\n"
374 375 "run = 0\n"
375 376 "run += 1")
376 377
377 378 @dec.skipif(sys.version_info[0] >= 3, "no differences with __future__ in py3")
378 379 def test_time_futures():
379 380 "Test %time with __future__ environments"
380 381 ip = get_ipython()
381 382 ip.autocall = 0
382 383 ip.run_cell("from __future__ import division")
383 384 with tt.AssertPrints('0.25'):
384 385 ip.run_line_magic('time', 'print(1/4)')
385 386 ip.compile.reset_compiler_flags()
386 387 with tt.AssertNotPrints('0.25'):
387 388 ip.run_line_magic('time', 'print(1/4)')
388 389
389 390 def test_doctest_mode():
390 391 "Toggle doctest_mode twice, it should be a no-op and run without error"
391 392 _ip.magic('doctest_mode')
392 393 _ip.magic('doctest_mode')
393 394
394 395
395 396 def test_parse_options():
396 397 """Tests for basic options parsing in magics."""
397 398 # These are only the most minimal of tests, more should be added later. At
398 399 # the very least we check that basic text/unicode calls work OK.
399 400 m = DummyMagics(_ip)
400 401 nt.assert_equal(m.parse_options('foo', '')[1], 'foo')
401 402 nt.assert_equal(m.parse_options(u'foo', '')[1], u'foo')
402 403
403 404
404 405 def test_dirops():
405 406 """Test various directory handling operations."""
406 407 # curpath = lambda :os.path.splitdrive(py3compat.getcwd())[1].replace('\\','/')
407 408 curpath = py3compat.getcwd
408 409 startdir = py3compat.getcwd()
409 410 ipdir = os.path.realpath(_ip.ipython_dir)
410 411 try:
411 412 _ip.magic('cd "%s"' % ipdir)
412 413 nt.assert_equal(curpath(), ipdir)
413 414 _ip.magic('cd -')
414 415 nt.assert_equal(curpath(), startdir)
415 416 _ip.magic('pushd "%s"' % ipdir)
416 417 nt.assert_equal(curpath(), ipdir)
417 418 _ip.magic('popd')
418 419 nt.assert_equal(curpath(), startdir)
419 420 finally:
420 421 os.chdir(startdir)
421 422
422 423
423 424 def test_xmode():
424 425 # Calling xmode three times should be a no-op
425 426 xmode = _ip.InteractiveTB.mode
426 427 for i in range(3):
427 428 _ip.magic("xmode")
428 429 nt.assert_equal(_ip.InteractiveTB.mode, xmode)
429 430
430 431 def test_reset_hard():
431 432 monitor = []
432 433 class A(object):
433 434 def __del__(self):
434 435 monitor.append(1)
435 436 def __repr__(self):
436 437 return "<A instance>"
437 438
438 439 _ip.user_ns["a"] = A()
439 440 _ip.run_cell("a")
440 441
441 442 nt.assert_equal(monitor, [])
442 443 _ip.magic("reset -f")
443 444 nt.assert_equal(monitor, [1])
444 445
445 446 class TestXdel(tt.TempFileMixin):
446 447 def test_xdel(self):
447 448 """Test that references from %run are cleared by xdel."""
448 449 src = ("class A(object):\n"
449 450 " monitor = []\n"
450 451 " def __del__(self):\n"
451 452 " self.monitor.append(1)\n"
452 453 "a = A()\n")
453 454 self.mktmp(src)
454 455 # %run creates some hidden references...
455 456 _ip.magic("run %s" % self.fname)
456 457 # ... as does the displayhook.
457 458 _ip.run_cell("a")
458 459
459 460 monitor = _ip.user_ns["A"].monitor
460 461 nt.assert_equal(monitor, [])
461 462
462 463 _ip.magic("xdel a")
463 464
464 465 # Check that a's __del__ method has been called.
465 466 nt.assert_equal(monitor, [1])
466 467
467 468 def doctest_who():
468 469 """doctest for %who
469 470
470 471 In [1]: %reset -f
471 472
472 473 In [2]: alpha = 123
473 474
474 475 In [3]: beta = 'beta'
475 476
476 477 In [4]: %who int
477 478 alpha
478 479
479 480 In [5]: %who str
480 481 beta
481 482
482 483 In [6]: %whos
483 484 Variable Type Data/Info
484 485 ----------------------------
485 486 alpha int 123
486 487 beta str beta
487 488
488 489 In [7]: %who_ls
489 490 Out[7]: ['alpha', 'beta']
490 491 """
491 492
492 493 def test_whos():
493 494 """Check that whos is protected against objects where repr() fails."""
494 495 class A(object):
495 496 def __repr__(self):
496 497 raise Exception()
497 498 _ip.user_ns['a'] = A()
498 499 _ip.magic("whos")
499 500
500 501 @py3compat.u_format
501 502 def doctest_precision():
502 503 """doctest for %precision
503 504
504 505 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
505 506
506 507 In [2]: %precision 5
507 508 Out[2]: {u}'%.5f'
508 509
509 510 In [3]: f.float_format
510 511 Out[3]: {u}'%.5f'
511 512
512 513 In [4]: %precision %e
513 514 Out[4]: {u}'%e'
514 515
515 516 In [5]: f(3.1415927)
516 517 Out[5]: {u}'3.141593e+00'
517 518 """
518 519
519 520 def test_psearch():
520 521 with tt.AssertPrints("dict.fromkeys"):
521 522 _ip.run_cell("dict.fr*?")
522 523
523 524 def test_timeit_shlex():
524 525 """test shlex issues with timeit (#1109)"""
525 526 _ip.ex("def f(*a,**kw): pass")
526 527 _ip.magic('timeit -n1 "this is a bug".count(" ")')
527 528 _ip.magic('timeit -r1 -n1 f(" ", 1)')
528 529 _ip.magic('timeit -r1 -n1 f(" ", 1, " ", 2, " ")')
529 530 _ip.magic('timeit -r1 -n1 ("a " + "b")')
530 531 _ip.magic('timeit -r1 -n1 f("a " + "b")')
531 532 _ip.magic('timeit -r1 -n1 f("a " + "b ")')
532 533
533 534
534 535 def test_timeit_arguments():
535 536 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
536 537 _ip.magic("timeit ('#')")
537 538
538 539
539 540 def test_timeit_special_syntax():
540 541 "Test %%timeit with IPython special syntax"
541 542 @register_line_magic
542 543 def lmagic(line):
543 544 ip = get_ipython()
544 545 ip.user_ns['lmagic_out'] = line
545 546
546 547 # line mode test
547 548 _ip.run_line_magic('timeit', '-n1 -r1 %lmagic my line')
548 549 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
549 550 # cell mode test
550 551 _ip.run_cell_magic('timeit', '-n1 -r1', '%lmagic my line2')
551 552 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
552 553
553 554 def test_timeit_return():
554 555 """
555 556 test wether timeit -o return object
556 557 """
557 558
558 559 res = _ip.run_line_magic('timeit','-n10 -r10 -o 1')
559 560 assert(res is not None)
560 561
561 562 def test_timeit_quiet():
562 563 """
563 564 test quiet option of timeit magic
564 565 """
565 566 with tt.AssertNotPrints("loops"):
566 567 _ip.run_cell("%timeit -n1 -r1 -q 1")
567 568
568 569 @dec.skipif(sys.version_info[0] >= 3, "no differences with __future__ in py3")
569 570 def test_timeit_futures():
570 571 "Test %timeit with __future__ environments"
571 572 ip = get_ipython()
572 573 ip.run_cell("from __future__ import division")
573 574 with tt.AssertPrints('0.25'):
574 575 ip.run_line_magic('timeit', '-n1 -r1 print(1/4)')
575 576 ip.compile.reset_compiler_flags()
576 577 with tt.AssertNotPrints('0.25'):
577 578 ip.run_line_magic('timeit', '-n1 -r1 print(1/4)')
578 579
579 580 @dec.skipif(execution.profile is None)
580 581 def test_prun_special_syntax():
581 582 "Test %%prun with IPython special syntax"
582 583 @register_line_magic
583 584 def lmagic(line):
584 585 ip = get_ipython()
585 586 ip.user_ns['lmagic_out'] = line
586 587
587 588 # line mode test
588 589 _ip.run_line_magic('prun', '-q %lmagic my line')
589 590 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
590 591 # cell mode test
591 592 _ip.run_cell_magic('prun', '-q', '%lmagic my line2')
592 593 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
593 594
594 595 @dec.skipif(execution.profile is None)
595 596 def test_prun_quotes():
596 597 "Test that prun does not clobber string escapes (GH #1302)"
597 598 _ip.magic(r"prun -q x = '\t'")
598 599 nt.assert_equal(_ip.user_ns['x'], '\t')
599 600
600 601 def test_extension():
601 602 tmpdir = TemporaryDirectory()
602 603 orig_ipython_dir = _ip.ipython_dir
603 604 try:
604 605 _ip.ipython_dir = tmpdir.name
605 606 nt.assert_raises(ImportError, _ip.magic, "load_ext daft_extension")
606 607 url = os.path.join(os.path.dirname(__file__), "daft_extension.py")
607 608 _ip.magic("install_ext %s" % url)
608 609 _ip.user_ns.pop('arq', None)
609 610 invalidate_caches() # Clear import caches
610 611 _ip.magic("load_ext daft_extension")
611 612 nt.assert_equal(_ip.user_ns['arq'], 185)
612 613 _ip.magic("unload_ext daft_extension")
613 614 assert 'arq' not in _ip.user_ns
614 615 finally:
615 616 _ip.ipython_dir = orig_ipython_dir
616 617 tmpdir.cleanup()
617 618
618 619
619 620 # The nose skip decorator doesn't work on classes, so this uses unittest's skipIf
620 621 @skipIf(dec.module_not_available('IPython.nbformat'), 'nbformat not importable')
621 622 class NotebookExportMagicTests(TestCase):
622 623 def test_notebook_export_json(self):
623 624 with TemporaryDirectory() as td:
624 625 outfile = os.path.join(td, "nb.ipynb")
625 626 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
626 627 _ip.magic("notebook -e %s" % outfile)
627 628
628 629
629 def test_env():
630 class TestEnv(TestCase):
631
632 def test_env(self):
630 633 env = _ip.magic("env")
631 assert isinstance(env, dict), type(env)
634 self.assertTrue(isinstance(env, dict))
635
636 def test_env_get_set_simple(self):
637 env = _ip.magic("env var val1")
638 self.assertEqual(env, None)
639 self.assertEqual(os.environ['var'], 'val1')
640 self.assertEqual(_ip.magic("env var"), 'val1')
641 env = _ip.magic("env var=val2")
642 self.assertEqual(env, None)
643 self.assertEqual(os.environ['var'], 'val2')
644
645 def test_env_get_set_complex(self):
646 env = _ip.magic("env var 'val1 '' 'val2")
647 self.assertEqual(env, None)
648 self.assertEqual(os.environ['var'], "'val1 '' 'val2")
649 self.assertEqual(_ip.magic("env var"), "'val1 '' 'val2")
650 env = _ip.magic('env var=val2 val3="val4')
651 self.assertEqual(env, None)
652 self.assertEqual(os.environ['var'], 'val2 val3="val4')
653
654 def test_env_set_bad_input(self):
655 self.assertRaises(UsageError, lambda: _ip.magic("set_env var"))
656
657 def test_env_set_whitespace(self):
658 self.assertRaises(UsageError, lambda: _ip.magic("env var A=B"))
632 659
633 660
634 661 class CellMagicTestCase(TestCase):
635 662
636 663 def check_ident(self, magic):
637 664 # Manually called, we get the result
638 665 out = _ip.run_cell_magic(magic, 'a', 'b')
639 666 nt.assert_equal(out, ('a','b'))
640 667 # Via run_cell, it goes into the user's namespace via displayhook
641 668 _ip.run_cell('%%' + magic +' c\nd')
642 669 nt.assert_equal(_ip.user_ns['_'], ('c','d'))
643 670
644 671 def test_cell_magic_func_deco(self):
645 672 "Cell magic using simple decorator"
646 673 @register_cell_magic
647 674 def cellm(line, cell):
648 675 return line, cell
649 676
650 677 self.check_ident('cellm')
651 678
652 679 def test_cell_magic_reg(self):
653 680 "Cell magic manually registered"
654 681 def cellm(line, cell):
655 682 return line, cell
656 683
657 684 _ip.register_magic_function(cellm, 'cell', 'cellm2')
658 685 self.check_ident('cellm2')
659 686
660 687 def test_cell_magic_class(self):
661 688 "Cell magics declared via a class"
662 689 @magics_class
663 690 class MyMagics(Magics):
664 691
665 692 @cell_magic
666 693 def cellm3(self, line, cell):
667 694 return line, cell
668 695
669 696 _ip.register_magics(MyMagics)
670 697 self.check_ident('cellm3')
671 698
672 699 def test_cell_magic_class2(self):
673 700 "Cell magics declared via a class, #2"
674 701 @magics_class
675 702 class MyMagics2(Magics):
676 703
677 704 @cell_magic('cellm4')
678 705 def cellm33(self, line, cell):
679 706 return line, cell
680 707
681 708 _ip.register_magics(MyMagics2)
682 709 self.check_ident('cellm4')
683 710 # Check that nothing is registered as 'cellm33'
684 711 c33 = _ip.find_cell_magic('cellm33')
685 712 nt.assert_equal(c33, None)
686 713
687 714 def test_file():
688 715 """Basic %%file"""
689 716 ip = get_ipython()
690 717 with TemporaryDirectory() as td:
691 718 fname = os.path.join(td, 'file1')
692 719 ip.run_cell_magic("file", fname, u'\n'.join([
693 720 'line1',
694 721 'line2',
695 722 ]))
696 723 with open(fname) as f:
697 724 s = f.read()
698 725 nt.assert_in('line1\n', s)
699 726 nt.assert_in('line2', s)
700 727
701 728 def test_file_var_expand():
702 729 """%%file $filename"""
703 730 ip = get_ipython()
704 731 with TemporaryDirectory() as td:
705 732 fname = os.path.join(td, 'file1')
706 733 ip.user_ns['filename'] = fname
707 734 ip.run_cell_magic("file", '$filename', u'\n'.join([
708 735 'line1',
709 736 'line2',
710 737 ]))
711 738 with open(fname) as f:
712 739 s = f.read()
713 740 nt.assert_in('line1\n', s)
714 741 nt.assert_in('line2', s)
715 742
716 743 def test_file_unicode():
717 744 """%%file with unicode cell"""
718 745 ip = get_ipython()
719 746 with TemporaryDirectory() as td:
720 747 fname = os.path.join(td, 'file1')
721 748 ip.run_cell_magic("file", fname, u'\n'.join([
722 749 u'linΓ©1',
723 750 u'linΓ©2',
724 751 ]))
725 752 with io.open(fname, encoding='utf-8') as f:
726 753 s = f.read()
727 754 nt.assert_in(u'linΓ©1\n', s)
728 755 nt.assert_in(u'linΓ©2', s)
729 756
730 757 def test_file_amend():
731 758 """%%file -a amends files"""
732 759 ip = get_ipython()
733 760 with TemporaryDirectory() as td:
734 761 fname = os.path.join(td, 'file2')
735 762 ip.run_cell_magic("file", fname, u'\n'.join([
736 763 'line1',
737 764 'line2',
738 765 ]))
739 766 ip.run_cell_magic("file", "-a %s" % fname, u'\n'.join([
740 767 'line3',
741 768 'line4',
742 769 ]))
743 770 with open(fname) as f:
744 771 s = f.read()
745 772 nt.assert_in('line1\n', s)
746 773 nt.assert_in('line3\n', s)
747 774
748 775
749 776 def test_script_config():
750 777 ip = get_ipython()
751 778 ip.config.ScriptMagics.script_magics = ['whoda']
752 779 sm = script.ScriptMagics(shell=ip)
753 780 nt.assert_in('whoda', sm.magics['cell'])
754 781
755 782 @dec.skip_win32
756 783 def test_script_out():
757 784 ip = get_ipython()
758 785 ip.run_cell_magic("script", "--out output sh", "echo 'hi'")
759 786 nt.assert_equal(ip.user_ns['output'], 'hi\n')
760 787
761 788 @dec.skip_win32
762 789 def test_script_err():
763 790 ip = get_ipython()
764 791 ip.run_cell_magic("script", "--err error sh", "echo 'hello' >&2")
765 792 nt.assert_equal(ip.user_ns['error'], 'hello\n')
766 793
767 794 @dec.skip_win32
768 795 def test_script_out_err():
769 796 ip = get_ipython()
770 797 ip.run_cell_magic("script", "--out output --err error sh", "echo 'hi'\necho 'hello' >&2")
771 798 nt.assert_equal(ip.user_ns['output'], 'hi\n')
772 799 nt.assert_equal(ip.user_ns['error'], 'hello\n')
773 800
774 801 @dec.skip_win32
775 802 def test_script_bg_out():
776 803 ip = get_ipython()
777 804 ip.run_cell_magic("script", "--bg --out output sh", "echo 'hi'")
778 805 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
779 806
780 807 @dec.skip_win32
781 808 def test_script_bg_err():
782 809 ip = get_ipython()
783 810 ip.run_cell_magic("script", "--bg --err error sh", "echo 'hello' >&2")
784 811 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
785 812
786 813 @dec.skip_win32
787 814 def test_script_bg_out_err():
788 815 ip = get_ipython()
789 816 ip.run_cell_magic("script", "--bg --out output --err error sh", "echo 'hi'\necho 'hello' >&2")
790 817 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
791 818 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
792 819
793 820 def test_script_defaults():
794 821 ip = get_ipython()
795 822 for cmd in ['sh', 'bash', 'perl', 'ruby']:
796 823 try:
797 824 find_cmd(cmd)
798 825 except Exception:
799 826 pass
800 827 else:
801 828 nt.assert_in(cmd, ip.magics_manager.magics['cell'])
802 829
803 830
804 831 @magics_class
805 832 class FooFoo(Magics):
806 833 """class with both %foo and %%foo magics"""
807 834 @line_magic('foo')
808 835 def line_foo(self, line):
809 836 "I am line foo"
810 837 pass
811 838
812 839 @cell_magic("foo")
813 840 def cell_foo(self, line, cell):
814 841 "I am cell foo, not line foo"
815 842 pass
816 843
817 844 def test_line_cell_info():
818 845 """%%foo and %foo magics are distinguishable to inspect"""
819 846 ip = get_ipython()
820 847 ip.magics_manager.register(FooFoo)
821 848 oinfo = ip.object_inspect('foo')
822 849 nt.assert_true(oinfo['found'])
823 850 nt.assert_true(oinfo['ismagic'])
824 851
825 852 oinfo = ip.object_inspect('%%foo')
826 853 nt.assert_true(oinfo['found'])
827 854 nt.assert_true(oinfo['ismagic'])
828 855 nt.assert_equal(oinfo['docstring'], FooFoo.cell_foo.__doc__)
829 856
830 857 oinfo = ip.object_inspect('%foo')
831 858 nt.assert_true(oinfo['found'])
832 859 nt.assert_true(oinfo['ismagic'])
833 860 nt.assert_equal(oinfo['docstring'], FooFoo.line_foo.__doc__)
834 861
835 862 def test_multiple_magics():
836 863 ip = get_ipython()
837 864 foo1 = FooFoo(ip)
838 865 foo2 = FooFoo(ip)
839 866 mm = ip.magics_manager
840 867 mm.register(foo1)
841 868 nt.assert_true(mm.magics['line']['foo'].__self__ is foo1)
842 869 mm.register(foo2)
843 870 nt.assert_true(mm.magics['line']['foo'].__self__ is foo2)
844 871
845 872 def test_alias_magic():
846 873 """Test %alias_magic."""
847 874 ip = get_ipython()
848 875 mm = ip.magics_manager
849 876
850 877 # Basic operation: both cell and line magics are created, if possible.
851 878 ip.run_line_magic('alias_magic', 'timeit_alias timeit')
852 879 nt.assert_in('timeit_alias', mm.magics['line'])
853 880 nt.assert_in('timeit_alias', mm.magics['cell'])
854 881
855 882 # --cell is specified, line magic not created.
856 883 ip.run_line_magic('alias_magic', '--cell timeit_cell_alias timeit')
857 884 nt.assert_not_in('timeit_cell_alias', mm.magics['line'])
858 885 nt.assert_in('timeit_cell_alias', mm.magics['cell'])
859 886
860 887 # Test that line alias is created successfully.
861 888 ip.run_line_magic('alias_magic', '--line env_alias env')
862 889 nt.assert_equal(ip.run_line_magic('env', ''),
863 890 ip.run_line_magic('env_alias', ''))
864 891
865 892 def test_save():
866 893 """Test %save."""
867 894 ip = get_ipython()
868 895 ip.history_manager.reset() # Clear any existing history.
869 896 cmds = [u"a=1", u"def b():\n return a**2", u"print(a, b())"]
870 897 for i, cmd in enumerate(cmds, start=1):
871 898 ip.history_manager.store_inputs(i, cmd)
872 899 with TemporaryDirectory() as tmpdir:
873 900 file = os.path.join(tmpdir, "testsave.py")
874 901 ip.run_line_magic("save", "%s 1-10" % file)
875 902 with open(file) as f:
876 903 content = f.read()
877 904 nt.assert_equal(content.count(cmds[0]), 1)
878 905 nt.assert_in('coding: utf-8', content)
879 906 ip.run_line_magic("save", "-a %s 1-10" % file)
880 907 with open(file) as f:
881 908 content = f.read()
882 909 nt.assert_equal(content.count(cmds[0]), 2)
883 910 nt.assert_in('coding: utf-8', content)
884 911
885 912
886 913 def test_store():
887 914 """Test %store."""
888 915 ip = get_ipython()
889 916 ip.run_line_magic('load_ext', 'storemagic')
890 917
891 918 # make sure the storage is empty
892 919 ip.run_line_magic('store', '-z')
893 920 ip.user_ns['var'] = 42
894 921 ip.run_line_magic('store', 'var')
895 922 ip.user_ns['var'] = 39
896 923 ip.run_line_magic('store', '-r')
897 924 nt.assert_equal(ip.user_ns['var'], 42)
898 925
899 926 ip.run_line_magic('store', '-d var')
900 927 ip.user_ns['var'] = 39
901 928 ip.run_line_magic('store' , '-r')
902 929 nt.assert_equal(ip.user_ns['var'], 39)
903 930
904 931
905 932 def _run_edit_test(arg_s, exp_filename=None,
906 933 exp_lineno=-1,
907 934 exp_contents=None,
908 935 exp_is_temp=None):
909 936 ip = get_ipython()
910 937 M = code.CodeMagics(ip)
911 938 last_call = ['','']
912 939 opts,args = M.parse_options(arg_s,'prxn:')
913 940 filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call)
914 941
915 942 if exp_filename is not None:
916 943 nt.assert_equal(exp_filename, filename)
917 944 if exp_contents is not None:
918 945 with io.open(filename, 'r', encoding='utf-8') as f:
919 946 contents = f.read()
920 947 nt.assert_equal(exp_contents, contents)
921 948 if exp_lineno != -1:
922 949 nt.assert_equal(exp_lineno, lineno)
923 950 if exp_is_temp is not None:
924 951 nt.assert_equal(exp_is_temp, is_temp)
925 952
926 953
927 954 def test_edit_interactive():
928 955 """%edit on interactively defined objects"""
929 956 ip = get_ipython()
930 957 n = ip.execution_count
931 958 ip.run_cell(u"def foo(): return 1", store_history=True)
932 959
933 960 try:
934 961 _run_edit_test("foo")
935 962 except code.InteractivelyDefined as e:
936 963 nt.assert_equal(e.index, n)
937 964 else:
938 965 raise AssertionError("Should have raised InteractivelyDefined")
939 966
940 967
941 968 def test_edit_cell():
942 969 """%edit [cell id]"""
943 970 ip = get_ipython()
944 971
945 972 ip.run_cell(u"def foo(): return 1", store_history=True)
946 973
947 974 # test
948 975 _run_edit_test("1", exp_contents=ip.user_ns['In'][1], exp_is_temp=True)
949 976
950 977 def test_bookmark():
951 978 ip = get_ipython()
952 979 ip.run_line_magic('bookmark', 'bmname')
953 980 with tt.AssertPrints('bmname'):
954 981 ip.run_line_magic('bookmark', '-l')
955 982 ip.run_line_magic('bookmark', '-d bmname')
General Comments 0
You need to be logged in to leave comments. Login now