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