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