##// END OF EJS Templates
added test for %store, fixed storemagic
Cavendish McKay -
Show More
@@ -1,779 +1,798 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 StringIO import StringIO
16 16 from unittest import TestCase
17 17
18 18 try:
19 19 from importlib import invalidate_caches # Required from Python 3.3
20 20 except ImportError:
21 21 def invalidate_caches():
22 22 pass
23 23
24 24 import nose.tools as nt
25 25
26 26 from IPython.core import magic
27 27 from IPython.core.magic import (Magics, magics_class, line_magic,
28 28 cell_magic, line_cell_magic,
29 29 register_line_magic, register_cell_magic,
30 30 register_line_cell_magic)
31 31 from IPython.core.magics import execution, script
32 32 from IPython.nbformat.v3.tests.nbexamples import nb0
33 33 from IPython.nbformat import current
34 34 from IPython.testing import decorators as dec
35 35 from IPython.testing import tools as tt
36 36 from IPython.utils import py3compat
37 37 from IPython.utils.tempdir import TemporaryDirectory
38 38 from IPython.utils.process import find_cmd
39 39
40 40 #-----------------------------------------------------------------------------
41 41 # Test functions begin
42 42 #-----------------------------------------------------------------------------
43 43
44 44 @magic.magics_class
45 45 class DummyMagics(magic.Magics): pass
46 46
47 47 def test_rehashx():
48 48 # clear up everything
49 49 _ip = get_ipython()
50 50 _ip.alias_manager.alias_table.clear()
51 51 del _ip.db['syscmdlist']
52 52
53 53 _ip.magic('rehashx')
54 54 # Practically ALL ipython development systems will have more than 10 aliases
55 55
56 56 yield (nt.assert_true, len(_ip.alias_manager.alias_table) > 10)
57 57 for key, val in _ip.alias_manager.alias_table.iteritems():
58 58 # we must strip dots from alias names
59 59 nt.assert_true('.' not in key)
60 60
61 61 # rehashx must fill up syscmdlist
62 62 scoms = _ip.db['syscmdlist']
63 63 yield (nt.assert_true, len(scoms) > 10)
64 64
65 65
66 66 def test_magic_parse_options():
67 67 """Test that we don't mangle paths when parsing magic options."""
68 68 ip = get_ipython()
69 69 path = 'c:\\x'
70 70 m = DummyMagics(ip)
71 71 opts = m.parse_options('-f %s' % path,'f:')[0]
72 72 # argv splitting is os-dependent
73 73 if os.name == 'posix':
74 74 expected = 'c:x'
75 75 else:
76 76 expected = path
77 77 nt.assert_equal(opts['f'], expected)
78 78
79 79 def test_magic_parse_long_options():
80 80 """Magic.parse_options can handle --foo=bar long options"""
81 81 ip = get_ipython()
82 82 m = DummyMagics(ip)
83 83 opts, _ = m.parse_options('--foo --bar=bubble', 'a', 'foo', 'bar=')
84 84 nt.assert_true('foo' in opts)
85 85 nt.assert_true('bar' in opts)
86 86 nt.assert_true(opts['bar'], "bubble")
87 87
88 88
89 89 @dec.skip_without('sqlite3')
90 90 def doctest_hist_f():
91 91 """Test %hist -f with temporary filename.
92 92
93 93 In [9]: import tempfile
94 94
95 95 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
96 96
97 97 In [11]: %hist -nl -f $tfile 3
98 98
99 99 In [13]: import os; os.unlink(tfile)
100 100 """
101 101
102 102
103 103 @dec.skip_without('sqlite3')
104 104 def doctest_hist_r():
105 105 """Test %hist -r
106 106
107 107 XXX - This test is not recording the output correctly. For some reason, in
108 108 testing mode the raw history isn't getting populated. No idea why.
109 109 Disabling the output checking for now, though at least we do run it.
110 110
111 111 In [1]: 'hist' in _ip.lsmagic()
112 112 Out[1]: True
113 113
114 114 In [2]: x=1
115 115
116 116 In [3]: %hist -rl 2
117 117 x=1 # random
118 118 %hist -r 2
119 119 """
120 120
121 121
122 122 @dec.skip_without('sqlite3')
123 123 def doctest_hist_op():
124 124 """Test %hist -op
125 125
126 126 In [1]: class b(float):
127 127 ...: pass
128 128 ...:
129 129
130 130 In [2]: class s(object):
131 131 ...: def __str__(self):
132 132 ...: return 's'
133 133 ...:
134 134
135 135 In [3]:
136 136
137 137 In [4]: class r(b):
138 138 ...: def __repr__(self):
139 139 ...: return 'r'
140 140 ...:
141 141
142 142 In [5]: class sr(s,r): pass
143 143 ...:
144 144
145 145 In [6]:
146 146
147 147 In [7]: bb=b()
148 148
149 149 In [8]: ss=s()
150 150
151 151 In [9]: rr=r()
152 152
153 153 In [10]: ssrr=sr()
154 154
155 155 In [11]: 4.5
156 156 Out[11]: 4.5
157 157
158 158 In [12]: str(ss)
159 159 Out[12]: 's'
160 160
161 161 In [13]:
162 162
163 163 In [14]: %hist -op
164 164 >>> class b:
165 165 ... pass
166 166 ...
167 167 >>> class s(b):
168 168 ... def __str__(self):
169 169 ... return 's'
170 170 ...
171 171 >>>
172 172 >>> class r(b):
173 173 ... def __repr__(self):
174 174 ... return 'r'
175 175 ...
176 176 >>> class sr(s,r): pass
177 177 >>>
178 178 >>> bb=b()
179 179 >>> ss=s()
180 180 >>> rr=r()
181 181 >>> ssrr=sr()
182 182 >>> 4.5
183 183 4.5
184 184 >>> str(ss)
185 185 's'
186 186 >>>
187 187 """
188 188
189 189
190 190 @dec.skip_without('sqlite3')
191 191 def test_macro():
192 192 ip = get_ipython()
193 193 ip.history_manager.reset() # Clear any existing history.
194 194 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
195 195 for i, cmd in enumerate(cmds, start=1):
196 196 ip.history_manager.store_inputs(i, cmd)
197 197 ip.magic("macro test 1-3")
198 198 nt.assert_equal(ip.user_ns["test"].value, "\n".join(cmds)+"\n")
199 199
200 200 # List macros.
201 201 assert "test" in ip.magic("macro")
202 202
203 203
204 204 @dec.skip_without('sqlite3')
205 205 def test_macro_run():
206 206 """Test that we can run a multi-line macro successfully."""
207 207 ip = get_ipython()
208 208 ip.history_manager.reset()
209 209 cmds = ["a=10", "a+=1", py3compat.doctest_refactor_print("print a"),
210 210 "%macro test 2-3"]
211 211 for cmd in cmds:
212 212 ip.run_cell(cmd, store_history=True)
213 213 nt.assert_equal(ip.user_ns["test"].value,
214 214 py3compat.doctest_refactor_print("a+=1\nprint a\n"))
215 215 with tt.AssertPrints("12"):
216 216 ip.run_cell("test")
217 217 with tt.AssertPrints("13"):
218 218 ip.run_cell("test")
219 219
220 220
221 221 @dec.skipif_not_numpy
222 222 def test_numpy_reset_array_undec():
223 223 "Test '%reset array' functionality"
224 224 _ip.ex('import numpy as np')
225 225 _ip.ex('a = np.empty(2)')
226 226 yield (nt.assert_true, 'a' in _ip.user_ns)
227 227 _ip.magic('reset -f array')
228 228 yield (nt.assert_false, 'a' in _ip.user_ns)
229 229
230 230 def test_reset_out():
231 231 "Test '%reset out' magic"
232 232 _ip.run_cell("parrot = 'dead'", store_history=True)
233 233 # test '%reset -f out', make an Out prompt
234 234 _ip.run_cell("parrot", store_history=True)
235 235 nt.assert_true('dead' in [_ip.user_ns[x] for x in '_','__','___'])
236 236 _ip.magic('reset -f out')
237 237 nt.assert_false('dead' in [_ip.user_ns[x] for x in '_','__','___'])
238 238 nt.assert_true(len(_ip.user_ns['Out']) == 0)
239 239
240 240 def test_reset_in():
241 241 "Test '%reset in' magic"
242 242 # test '%reset -f in'
243 243 _ip.run_cell("parrot", store_history=True)
244 244 nt.assert_true('parrot' in [_ip.user_ns[x] for x in '_i','_ii','_iii'])
245 245 _ip.magic('%reset -f in')
246 246 nt.assert_false('parrot' in [_ip.user_ns[x] for x in '_i','_ii','_iii'])
247 247 nt.assert_true(len(set(_ip.user_ns['In'])) == 1)
248 248
249 249 def test_reset_dhist():
250 250 "Test '%reset dhist' magic"
251 251 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
252 252 _ip.magic('cd ' + os.path.dirname(nt.__file__))
253 253 _ip.magic('cd -')
254 254 nt.assert_true(len(_ip.user_ns['_dh']) > 0)
255 255 _ip.magic('reset -f dhist')
256 256 nt.assert_true(len(_ip.user_ns['_dh']) == 0)
257 257 _ip.run_cell("_dh = [d for d in tmp]") #restore
258 258
259 259 def test_reset_in_length():
260 260 "Test that '%reset in' preserves In[] length"
261 261 _ip.run_cell("print 'foo'")
262 262 _ip.run_cell("reset -f in")
263 263 nt.assert_true(len(_ip.user_ns['In']) == _ip.displayhook.prompt_count+1)
264 264
265 265 def test_time():
266 266 _ip.magic('time None')
267 267
268 268 def test_tb_syntaxerror():
269 269 """test %tb after a SyntaxError"""
270 270 ip = get_ipython()
271 271 ip.run_cell("for")
272 272
273 273 # trap and validate stdout
274 274 save_stdout = sys.stdout
275 275 try:
276 276 sys.stdout = StringIO()
277 277 ip.run_cell("%tb")
278 278 out = sys.stdout.getvalue()
279 279 finally:
280 280 sys.stdout = save_stdout
281 281 # trim output, and only check the last line
282 282 last_line = out.rstrip().splitlines()[-1].strip()
283 283 nt.assert_equal(last_line, "SyntaxError: invalid syntax")
284 284
285 285
286 286 @py3compat.doctest_refactor_print
287 287 def doctest_time():
288 288 """
289 289 In [10]: %time None
290 290 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
291 291 Wall time: 0.00 s
292 292
293 293 In [11]: def f(kmjy):
294 294 ....: %time print 2*kmjy
295 295
296 296 In [12]: f(3)
297 297 6
298 298 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
299 299 Wall time: 0.00 s
300 300 """
301 301
302 302
303 303 def test_doctest_mode():
304 304 "Toggle doctest_mode twice, it should be a no-op and run without error"
305 305 _ip.magic('doctest_mode')
306 306 _ip.magic('doctest_mode')
307 307
308 308
309 309 def test_parse_options():
310 310 """Tests for basic options parsing in magics."""
311 311 # These are only the most minimal of tests, more should be added later. At
312 312 # the very least we check that basic text/unicode calls work OK.
313 313 m = DummyMagics(_ip)
314 314 nt.assert_equal(m.parse_options('foo', '')[1], 'foo')
315 315 nt.assert_equal(m.parse_options(u'foo', '')[1], u'foo')
316 316
317 317
318 318 def test_dirops():
319 319 """Test various directory handling operations."""
320 320 # curpath = lambda :os.path.splitdrive(os.getcwdu())[1].replace('\\','/')
321 321 curpath = os.getcwdu
322 322 startdir = os.getcwdu()
323 323 ipdir = os.path.realpath(_ip.ipython_dir)
324 324 try:
325 325 _ip.magic('cd "%s"' % ipdir)
326 326 nt.assert_equal(curpath(), ipdir)
327 327 _ip.magic('cd -')
328 328 nt.assert_equal(curpath(), startdir)
329 329 _ip.magic('pushd "%s"' % ipdir)
330 330 nt.assert_equal(curpath(), ipdir)
331 331 _ip.magic('popd')
332 332 nt.assert_equal(curpath(), startdir)
333 333 finally:
334 334 os.chdir(startdir)
335 335
336 336
337 337 def test_xmode():
338 338 # Calling xmode three times should be a no-op
339 339 xmode = _ip.InteractiveTB.mode
340 340 for i in range(3):
341 341 _ip.magic("xmode")
342 342 nt.assert_equal(_ip.InteractiveTB.mode, xmode)
343 343
344 344 def test_reset_hard():
345 345 monitor = []
346 346 class A(object):
347 347 def __del__(self):
348 348 monitor.append(1)
349 349 def __repr__(self):
350 350 return "<A instance>"
351 351
352 352 _ip.user_ns["a"] = A()
353 353 _ip.run_cell("a")
354 354
355 355 nt.assert_equal(monitor, [])
356 356 _ip.magic("reset -f")
357 357 nt.assert_equal(monitor, [1])
358 358
359 359 class TestXdel(tt.TempFileMixin):
360 360 def test_xdel(self):
361 361 """Test that references from %run are cleared by xdel."""
362 362 src = ("class A(object):\n"
363 363 " monitor = []\n"
364 364 " def __del__(self):\n"
365 365 " self.monitor.append(1)\n"
366 366 "a = A()\n")
367 367 self.mktmp(src)
368 368 # %run creates some hidden references...
369 369 _ip.magic("run %s" % self.fname)
370 370 # ... as does the displayhook.
371 371 _ip.run_cell("a")
372 372
373 373 monitor = _ip.user_ns["A"].monitor
374 374 nt.assert_equal(monitor, [])
375 375
376 376 _ip.magic("xdel a")
377 377
378 378 # Check that a's __del__ method has been called.
379 379 nt.assert_equal(monitor, [1])
380 380
381 381 def doctest_who():
382 382 """doctest for %who
383 383
384 384 In [1]: %reset -f
385 385
386 386 In [2]: alpha = 123
387 387
388 388 In [3]: beta = 'beta'
389 389
390 390 In [4]: %who int
391 391 alpha
392 392
393 393 In [5]: %who str
394 394 beta
395 395
396 396 In [6]: %whos
397 397 Variable Type Data/Info
398 398 ----------------------------
399 399 alpha int 123
400 400 beta str beta
401 401
402 402 In [7]: %who_ls
403 403 Out[7]: ['alpha', 'beta']
404 404 """
405 405
406 406 def test_whos():
407 407 """Check that whos is protected against objects where repr() fails."""
408 408 class A(object):
409 409 def __repr__(self):
410 410 raise Exception()
411 411 _ip.user_ns['a'] = A()
412 412 _ip.magic("whos")
413 413
414 414 @py3compat.u_format
415 415 def doctest_precision():
416 416 """doctest for %precision
417 417
418 418 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
419 419
420 420 In [2]: %precision 5
421 421 Out[2]: {u}'%.5f'
422 422
423 423 In [3]: f.float_format
424 424 Out[3]: {u}'%.5f'
425 425
426 426 In [4]: %precision %e
427 427 Out[4]: {u}'%e'
428 428
429 429 In [5]: f(3.1415927)
430 430 Out[5]: {u}'3.141593e+00'
431 431 """
432 432
433 433 def test_psearch():
434 434 with tt.AssertPrints("dict.fromkeys"):
435 435 _ip.run_cell("dict.fr*?")
436 436
437 437 def test_timeit_shlex():
438 438 """test shlex issues with timeit (#1109)"""
439 439 _ip.ex("def f(*a,**kw): pass")
440 440 _ip.magic('timeit -n1 "this is a bug".count(" ")')
441 441 _ip.magic('timeit -r1 -n1 f(" ", 1)')
442 442 _ip.magic('timeit -r1 -n1 f(" ", 1, " ", 2, " ")')
443 443 _ip.magic('timeit -r1 -n1 ("a " + "b")')
444 444 _ip.magic('timeit -r1 -n1 f("a " + "b")')
445 445 _ip.magic('timeit -r1 -n1 f("a " + "b ")')
446 446
447 447
448 448 def test_timeit_arguments():
449 449 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
450 450 _ip.magic("timeit ('#')")
451 451
452 452
453 453 def test_timeit_special_syntax():
454 454 "Test %%timeit with IPython special syntax"
455 455 from IPython.core.magic import register_line_magic
456 456
457 457 @register_line_magic
458 458 def lmagic(line):
459 459 ip = get_ipython()
460 460 ip.user_ns['lmagic_out'] = line
461 461
462 462 # line mode test
463 463 _ip.run_line_magic('timeit', '-n1 -r1 %lmagic my line')
464 464 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
465 465 # cell mode test
466 466 _ip.run_cell_magic('timeit', '-n1 -r1', '%lmagic my line2')
467 467 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
468 468
469 469
470 470 @dec.skipif(execution.profile is None)
471 471 def test_prun_quotes():
472 472 "Test that prun does not clobber string escapes (GH #1302)"
473 473 _ip.magic(r"prun -q x = '\t'")
474 474 nt.assert_equal(_ip.user_ns['x'], '\t')
475 475
476 476 def test_extension():
477 477 tmpdir = TemporaryDirectory()
478 478 orig_ipython_dir = _ip.ipython_dir
479 479 try:
480 480 _ip.ipython_dir = tmpdir.name
481 481 nt.assert_raises(ImportError, _ip.magic, "load_ext daft_extension")
482 482 url = os.path.join(os.path.dirname(__file__), "daft_extension.py")
483 483 _ip.magic("install_ext %s" % url)
484 484 _ip.user_ns.pop('arq', None)
485 485 invalidate_caches() # Clear import caches
486 486 _ip.magic("load_ext daft_extension")
487 487 nt.assert_equal(_ip.user_ns['arq'], 185)
488 488 _ip.magic("unload_ext daft_extension")
489 489 assert 'arq' not in _ip.user_ns
490 490 finally:
491 491 _ip.ipython_dir = orig_ipython_dir
492 492 tmpdir.cleanup()
493 493
494 494 def test_notebook_export_json():
495 495 with TemporaryDirectory() as td:
496 496 outfile = os.path.join(td, "nb.ipynb")
497 497 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
498 498 _ip.magic("notebook -e %s" % outfile)
499 499
500 500 def test_notebook_export_py():
501 501 with TemporaryDirectory() as td:
502 502 outfile = os.path.join(td, "nb.py")
503 503 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
504 504 _ip.magic("notebook -e %s" % outfile)
505 505
506 506 def test_notebook_reformat_py():
507 507 with TemporaryDirectory() as td:
508 508 infile = os.path.join(td, "nb.ipynb")
509 509 with io.open(infile, 'w', encoding='utf-8') as f:
510 510 current.write(nb0, f, 'json')
511 511
512 512 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
513 513 _ip.magic("notebook -f py %s" % infile)
514 514
515 515 def test_notebook_reformat_json():
516 516 with TemporaryDirectory() as td:
517 517 infile = os.path.join(td, "nb.py")
518 518 with io.open(infile, 'w', encoding='utf-8') as f:
519 519 current.write(nb0, f, 'py')
520 520
521 521 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
522 522 _ip.magic("notebook -f ipynb %s" % infile)
523 523 _ip.magic("notebook -f json %s" % infile)
524 524
525 525 def test_env():
526 526 env = _ip.magic("env")
527 527 assert isinstance(env, dict), type(env)
528 528
529 529
530 530 class CellMagicTestCase(TestCase):
531 531
532 532 def check_ident(self, magic):
533 533 # Manually called, we get the result
534 534 out = _ip.run_cell_magic(magic, 'a', 'b')
535 535 nt.assert_equal(out, ('a','b'))
536 536 # Via run_cell, it goes into the user's namespace via displayhook
537 537 _ip.run_cell('%%' + magic +' c\nd')
538 538 nt.assert_equal(_ip.user_ns['_'], ('c','d'))
539 539
540 540 def test_cell_magic_func_deco(self):
541 541 "Cell magic using simple decorator"
542 542 @register_cell_magic
543 543 def cellm(line, cell):
544 544 return line, cell
545 545
546 546 self.check_ident('cellm')
547 547
548 548 def test_cell_magic_reg(self):
549 549 "Cell magic manually registered"
550 550 def cellm(line, cell):
551 551 return line, cell
552 552
553 553 _ip.register_magic_function(cellm, 'cell', 'cellm2')
554 554 self.check_ident('cellm2')
555 555
556 556 def test_cell_magic_class(self):
557 557 "Cell magics declared via a class"
558 558 @magics_class
559 559 class MyMagics(Magics):
560 560
561 561 @cell_magic
562 562 def cellm3(self, line, cell):
563 563 return line, cell
564 564
565 565 _ip.register_magics(MyMagics)
566 566 self.check_ident('cellm3')
567 567
568 568 def test_cell_magic_class2(self):
569 569 "Cell magics declared via a class, #2"
570 570 @magics_class
571 571 class MyMagics2(Magics):
572 572
573 573 @cell_magic('cellm4')
574 574 def cellm33(self, line, cell):
575 575 return line, cell
576 576
577 577 _ip.register_magics(MyMagics2)
578 578 self.check_ident('cellm4')
579 579 # Check that nothing is registered as 'cellm33'
580 580 c33 = _ip.find_cell_magic('cellm33')
581 581 nt.assert_equal(c33, None)
582 582
583 583 def test_file():
584 584 """Basic %%file"""
585 585 ip = get_ipython()
586 586 with TemporaryDirectory() as td:
587 587 fname = os.path.join(td, 'file1')
588 588 ip.run_cell_magic("file", fname, u'\n'.join([
589 589 'line1',
590 590 'line2',
591 591 ]))
592 592 with open(fname) as f:
593 593 s = f.read()
594 594 nt.assert_in('line1\n', s)
595 595 nt.assert_in('line2', s)
596 596
597 597 def test_file_var_expand():
598 598 """%%file $filename"""
599 599 ip = get_ipython()
600 600 with TemporaryDirectory() as td:
601 601 fname = os.path.join(td, 'file1')
602 602 ip.user_ns['filename'] = fname
603 603 ip.run_cell_magic("file", '$filename', u'\n'.join([
604 604 'line1',
605 605 'line2',
606 606 ]))
607 607 with open(fname) as f:
608 608 s = f.read()
609 609 nt.assert_in('line1\n', s)
610 610 nt.assert_in('line2', s)
611 611
612 612 def test_file_unicode():
613 613 """%%file with unicode cell"""
614 614 ip = get_ipython()
615 615 with TemporaryDirectory() as td:
616 616 fname = os.path.join(td, 'file1')
617 617 ip.run_cell_magic("file", fname, u'\n'.join([
618 618 u'linΓ©1',
619 619 u'linΓ©2',
620 620 ]))
621 621 with io.open(fname, encoding='utf-8') as f:
622 622 s = f.read()
623 623 nt.assert_in(u'linΓ©1\n', s)
624 624 nt.assert_in(u'linΓ©2', s)
625 625
626 626 def test_file_amend():
627 627 """%%file -a amends files"""
628 628 ip = get_ipython()
629 629 with TemporaryDirectory() as td:
630 630 fname = os.path.join(td, 'file2')
631 631 ip.run_cell_magic("file", fname, u'\n'.join([
632 632 'line1',
633 633 'line2',
634 634 ]))
635 635 ip.run_cell_magic("file", "-a %s" % fname, u'\n'.join([
636 636 'line3',
637 637 'line4',
638 638 ]))
639 639 with open(fname) as f:
640 640 s = f.read()
641 641 nt.assert_in('line1\n', s)
642 642 nt.assert_in('line3\n', s)
643 643
644 644
645 645 def test_script_config():
646 646 ip = get_ipython()
647 647 ip.config.ScriptMagics.script_magics = ['whoda']
648 648 sm = script.ScriptMagics(shell=ip)
649 649 nt.assert_in('whoda', sm.magics['cell'])
650 650
651 651 @dec.skip_win32
652 652 def test_script_out():
653 653 ip = get_ipython()
654 654 ip.run_cell_magic("script", "--out output sh", "echo 'hi'")
655 655 nt.assert_equal(ip.user_ns['output'], 'hi\n')
656 656
657 657 @dec.skip_win32
658 658 def test_script_err():
659 659 ip = get_ipython()
660 660 ip.run_cell_magic("script", "--err error sh", "echo 'hello' >&2")
661 661 nt.assert_equal(ip.user_ns['error'], 'hello\n')
662 662
663 663 @dec.skip_win32
664 664 def test_script_out_err():
665 665 ip = get_ipython()
666 666 ip.run_cell_magic("script", "--out output --err error sh", "echo 'hi'\necho 'hello' >&2")
667 667 nt.assert_equal(ip.user_ns['output'], 'hi\n')
668 668 nt.assert_equal(ip.user_ns['error'], 'hello\n')
669 669
670 670 @dec.skip_win32
671 671 def test_script_bg_out():
672 672 ip = get_ipython()
673 673 ip.run_cell_magic("script", "--bg --out output sh", "echo 'hi'")
674 674 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
675 675
676 676 @dec.skip_win32
677 677 def test_script_bg_err():
678 678 ip = get_ipython()
679 679 ip.run_cell_magic("script", "--bg --err error sh", "echo 'hello' >&2")
680 680 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
681 681
682 682 @dec.skip_win32
683 683 def test_script_bg_out_err():
684 684 ip = get_ipython()
685 685 ip.run_cell_magic("script", "--bg --out output --err error sh", "echo 'hi'\necho 'hello' >&2")
686 686 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
687 687 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
688 688
689 689 def test_script_defaults():
690 690 ip = get_ipython()
691 691 for cmd in ['sh', 'bash', 'perl', 'ruby']:
692 692 try:
693 693 find_cmd(cmd)
694 694 except Exception:
695 695 pass
696 696 else:
697 697 nt.assert_in(cmd, ip.magics_manager.magics['cell'])
698 698
699 699
700 700 @magics_class
701 701 class FooFoo(Magics):
702 702 """class with both %foo and %%foo magics"""
703 703 @line_magic('foo')
704 704 def line_foo(self, line):
705 705 "I am line foo"
706 706 pass
707 707
708 708 @cell_magic("foo")
709 709 def cell_foo(self, line, cell):
710 710 "I am cell foo, not line foo"
711 711 pass
712 712
713 713 def test_line_cell_info():
714 714 """%%foo and %foo magics are distinguishable to inspect"""
715 715 ip = get_ipython()
716 716 ip.magics_manager.register(FooFoo)
717 717 oinfo = ip.object_inspect('foo')
718 718 nt.assert_true(oinfo['found'])
719 719 nt.assert_true(oinfo['ismagic'])
720 720
721 721 oinfo = ip.object_inspect('%%foo')
722 722 nt.assert_true(oinfo['found'])
723 723 nt.assert_true(oinfo['ismagic'])
724 724 nt.assert_equal(oinfo['docstring'], FooFoo.cell_foo.__doc__)
725 725
726 726 oinfo = ip.object_inspect('%foo')
727 727 nt.assert_true(oinfo['found'])
728 728 nt.assert_true(oinfo['ismagic'])
729 729 nt.assert_equal(oinfo['docstring'], FooFoo.line_foo.__doc__)
730 730
731 731 def test_multiple_magics():
732 732 ip = get_ipython()
733 733 foo1 = FooFoo(ip)
734 734 foo2 = FooFoo(ip)
735 735 mm = ip.magics_manager
736 736 mm.register(foo1)
737 737 nt.assert_true(mm.magics['line']['foo'].im_self is foo1)
738 738 mm.register(foo2)
739 739 nt.assert_true(mm.magics['line']['foo'].im_self is foo2)
740 740
741 741 def test_alias_magic():
742 742 """Test %alias_magic."""
743 743 ip = get_ipython()
744 744 mm = ip.magics_manager
745 745
746 746 # Basic operation: both cell and line magics are created, if possible.
747 747 ip.run_line_magic('alias_magic', 'timeit_alias timeit')
748 748 nt.assert_true('timeit_alias' in mm.magics['line'])
749 749 nt.assert_true('timeit_alias' in mm.magics['cell'])
750 750
751 751 # --cell is specified, line magic not created.
752 752 ip.run_line_magic('alias_magic', '--cell timeit_cell_alias timeit')
753 753 nt.assert_false('timeit_cell_alias' in mm.magics['line'])
754 754 nt.assert_true('timeit_cell_alias' in mm.magics['cell'])
755 755
756 756 # Test that line alias is created successfully.
757 757 ip.run_line_magic('alias_magic', '--line env_alias env')
758 758 nt.assert_equal(ip.run_line_magic('env', ''),
759 759 ip.run_line_magic('env_alias', ''))
760 760
761 761 def test_save():
762 762 """Test %save."""
763 763 ip = get_ipython()
764 764 ip.history_manager.reset() # Clear any existing history.
765 765 cmds = [u"a=1", u"def b():\n return a**2", u"print(a, b())"]
766 766 for i, cmd in enumerate(cmds, start=1):
767 767 ip.history_manager.store_inputs(i, cmd)
768 768 with TemporaryDirectory() as tmpdir:
769 769 file = os.path.join(tmpdir, "testsave.py")
770 770 ip.run_line_magic("save", "%s 1-10" % file)
771 771 with open(file) as f:
772 772 content = f.read()
773 773 nt.assert_equal(content.count(cmds[0]), 1)
774 774 nt.assert_true('coding: utf-8' in content)
775 775 ip.run_line_magic("save", "-a %s 1-10" % file)
776 776 with open(file) as f:
777 777 content = f.read()
778 778 nt.assert_equal(content.count(cmds[0]), 2)
779 779 nt.assert_true('coding: utf-8' in content)
780
781
782 def test_store():
783 """Test %store."""
784 ip = get_ipython()
785 ip.run_line_magic('load_ext', 'storemagic')
786
787 # make sure the storage is empty
788 ip.run_line_magic('store', '-z')
789 ip.user_ns['var'] = 42
790 ip.run_line_magic('store', 'var')
791 ip.user_ns['var'] = 39
792 ip.run_line_magic('store', '-r')
793 nt.assert_equal(ip.user_ns['var'], 42)
794
795 ip.run_line_magic('store', '-d var')
796 ip.user_ns['var'] = 39
797 ip.run_line_magic('store' , '-r')
798 nt.assert_equal(ip.user_ns['var'], 39)
@@ -1,234 +1,234 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 %store magic for lightweight persistence.
4 4
5 5 Stores variables, aliases and macros in IPython's database.
6 6
7 7 To automatically restore stored variables at startup, add this to your
8 8 :file:`ipython_config.py` file::
9 9
10 10 c.StoreMagic.autorestore = True
11 11 """
12 12 #-----------------------------------------------------------------------------
13 13 # Copyright (c) 2012, The IPython Development Team.
14 14 #
15 15 # Distributed under the terms of the Modified BSD License.
16 16 #
17 17 # The full license is in the file COPYING.txt, distributed with this software.
18 18 #-----------------------------------------------------------------------------
19 19
20 20 #-----------------------------------------------------------------------------
21 21 # Imports
22 22 #-----------------------------------------------------------------------------
23 23
24 24 # Stdlib
25 25 import inspect, os, sys, textwrap
26 26
27 27 # Our own
28 28 from IPython.core.error import UsageError
29 29 from IPython.core.fakemodule import FakeModule
30 30 from IPython.core.magic import Magics, magics_class, line_magic
31 31 from IPython.core.plugin import Plugin
32 32 from IPython.testing.skipdoctest import skip_doctest
33 33 from IPython.utils.traitlets import Bool, Instance
34 34
35 35 #-----------------------------------------------------------------------------
36 36 # Functions and classes
37 37 #-----------------------------------------------------------------------------
38 38
39 39 def restore_aliases(ip):
40 40 staliases = ip.db.get('stored_aliases', {})
41 41 for k,v in staliases.items():
42 42 #print "restore alias",k,v # dbg
43 43 #self.alias_table[k] = v
44 44 ip.alias_manager.define_alias(k,v)
45 45
46 46
47 47 def refresh_variables(ip):
48 48 db = ip.db
49 49 for key in db.keys('autorestore/*'):
50 50 # strip autorestore
51 51 justkey = os.path.basename(key)
52 52 try:
53 53 obj = db[key]
54 54 except KeyError:
55 55 print "Unable to restore variable '%s', ignoring (use %%store -d to forget!)" % justkey
56 56 print "The error was:", sys.exc_info()[0]
57 57 else:
58 58 #print "restored",justkey,"=",obj #dbg
59 59 ip.user_ns[justkey] = obj
60 60
61 61
62 62 def restore_dhist(ip):
63 63 ip.user_ns['_dh'] = ip.db.get('dhist',[])
64 64
65 65
66 66 def restore_data(ip):
67 67 refresh_variables(ip)
68 68 restore_aliases(ip)
69 69 restore_dhist(ip)
70 70
71 71
72 72 @magics_class
73 73 class StoreMagics(Magics):
74 74 """Lightweight persistence for python variables.
75 75
76 76 Provides the %store magic."""
77 77
78 78 @skip_doctest
79 79 @line_magic
80 80 def store(self, parameter_s=''):
81 81 """Lightweight persistence for python variables.
82 82
83 83 Example::
84 84
85 85 In [1]: l = ['hello',10,'world']
86 86 In [2]: %store l
87 87 In [3]: exit
88 88
89 89 (IPython session is closed and started again...)
90 90
91 91 ville@badger:~$ ipython
92 92 In [1]: l
93 93 Out[1]: ['hello', 10, 'world']
94 94
95 95 Usage:
96 96
97 97 * ``%store`` - Show list of all variables and their current
98 98 values
99 99 * ``%store spam`` - Store the *current* value of the variable spam
100 100 to disk
101 101 * ``%store -d spam`` - Remove the variable and its value from storage
102 102 * ``%store -z`` - Remove all variables from storage
103 103 * ``%store -r`` - Refresh all variables from store (delete
104 104 current vals)
105 105 * ``%store foo >a.txt`` - Store value of foo to new file a.txt
106 106 * ``%store foo >>a.txt`` - Append value of foo to file a.txt
107 107
108 108 It should be noted that if you change the value of a variable, you
109 109 need to %store it again if you want to persist the new value.
110 110
111 111 Note also that the variables will need to be pickleable; most basic
112 112 python types can be safely %store'd.
113 113
114 114 Also aliases can be %store'd across sessions.
115 115 """
116 116
117 117 opts,argsl = self.parse_options(parameter_s,'drz',mode='string')
118 118 args = argsl.split(None,1)
119 119 ip = self.shell
120 120 db = ip.db
121 121 # delete
122 122 if 'd' in opts:
123 123 try:
124 124 todel = args[0]
125 125 except IndexError:
126 126 raise UsageError('You must provide the variable to forget')
127 127 else:
128 128 try:
129 129 del db['autorestore/' + todel]
130 130 except:
131 131 raise UsageError("Can't delete variable '%s'" % todel)
132 132 # reset
133 133 elif 'z' in opts:
134 134 for k in db.keys('autorestore/*'):
135 135 del db[k]
136 136
137 137 elif 'r' in opts:
138 138 refresh_variables(ip)
139 139
140 140
141 141 # run without arguments -> list variables & values
142 142 elif not args:
143 vars = self.db.keys('autorestore/*')
143 vars = db.keys('autorestore/*')
144 144 vars.sort()
145 145 if vars:
146 146 size = max(map(len, vars))
147 147 else:
148 148 size = 0
149 149
150 150 print 'Stored variables and their in-db values:'
151 151 fmt = '%-'+str(size)+'s -> %s'
152 152 get = db.get
153 153 for var in vars:
154 154 justkey = os.path.basename(var)
155 155 # print 30 first characters from every var
156 156 print fmt % (justkey, repr(get(var, '<unavailable>'))[:50])
157 157
158 158 # default action - store the variable
159 159 else:
160 160 # %store foo >file.txt or >>file.txt
161 161 if len(args) > 1 and args[1].startswith('>'):
162 162 fnam = os.path.expanduser(args[1].lstrip('>').lstrip())
163 163 if args[1].startswith('>>'):
164 164 fil = open(fnam, 'a')
165 165 else:
166 166 fil = open(fnam, 'w')
167 167 obj = ip.ev(args[0])
168 168 print "Writing '%s' (%s) to file '%s'." % (args[0],
169 169 obj.__class__.__name__, fnam)
170 170
171 171
172 172 if not isinstance (obj, basestring):
173 173 from pprint import pprint
174 174 pprint(obj, fil)
175 175 else:
176 176 fil.write(obj)
177 177 if not obj.endswith('\n'):
178 178 fil.write('\n')
179 179
180 180 fil.close()
181 181 return
182 182
183 183 # %store foo
184 184 try:
185 185 obj = ip.user_ns[args[0]]
186 186 except KeyError:
187 187 # it might be an alias
188 188 # This needs to be refactored to use the new AliasManager stuff.
189 if args[0] in self.alias_manager:
189 if args[0] in ip.alias_manager:
190 190 name = args[0]
191 nargs, cmd = self.alias_manager.alias_table[ name ]
191 nargs, cmd = ip.alias_manager.alias_table[ name ]
192 192 staliases = db.get('stored_aliases',{})
193 193 staliases[ name ] = cmd
194 194 db['stored_aliases'] = staliases
195 195 print "Alias stored: %s (%s)" % (name, cmd)
196 196 return
197 197 else:
198 198 raise UsageError("Unknown variable '%s'" % args[0])
199 199
200 200 else:
201 201 if isinstance(inspect.getmodule(obj), FakeModule):
202 202 print textwrap.dedent("""\
203 203 Warning:%s is %s
204 204 Proper storage of interactively declared classes (or instances
205 205 of those classes) is not possible! Only instances
206 206 of classes in real modules on file system can be %%store'd.
207 207 """ % (args[0], obj) )
208 208 return
209 209 #pickled = pickle.dumps(obj)
210 self.db[ 'autorestore/' + args[0] ] = obj
210 db[ 'autorestore/' + args[0] ] = obj
211 211 print "Stored '%s' (%s)" % (args[0], obj.__class__.__name__)
212 212
213 213
214 214 class StoreMagic(Plugin):
215 215 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
216 216 autorestore = Bool(False, config=True)
217 217
218 218 def __init__(self, shell, config):
219 219 super(StoreMagic, self).__init__(shell=shell, config=config)
220 220 shell.register_magics(StoreMagics)
221 221
222 222 if self.autorestore:
223 223 restore_data(shell)
224 224
225 225
226 226 _loaded = False
227 227
228 228 def load_ipython_extension(ip):
229 229 """Load the extension in IPython."""
230 230 global _loaded
231 231 if not _loaded:
232 232 plugin = StoreMagic(shell=ip, config=ip.config)
233 233 ip.plugin_manager.register_plugin('storemagic', plugin)
234 234 _loaded = True
General Comments 0
You need to be logged in to leave comments. Login now