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