##// END OF EJS Templates
Use pathlib
Joyce Er -
Show More
@@ -1,1266 +1,1257 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
6
7 import io
7 import io
8 import os
8 import os
9 import re
9 import re
10 import sys
10 import sys
11 import warnings
11 import warnings
12 from textwrap import dedent
12 from textwrap import dedent
13 from unittest import TestCase
13 from unittest import TestCase
14 from unittest import mock
14 from unittest import mock
15 from importlib import invalidate_caches
15 from importlib import invalidate_caches
16 from io import StringIO
16 from io import StringIO
17 from pathlib import Path
17
18
18 import nose.tools as nt
19 import nose.tools as nt
19
20
20 import shlex
21 import shlex
21
22
22 from IPython import get_ipython
23 from IPython import get_ipython
23 from IPython.core import magic
24 from IPython.core import magic
24 from IPython.core.error import UsageError
25 from IPython.core.error import UsageError
25 from IPython.core.magic import (Magics, magics_class, line_magic,
26 from IPython.core.magic import (Magics, magics_class, line_magic,
26 cell_magic,
27 cell_magic,
27 register_line_magic, register_cell_magic)
28 register_line_magic, register_cell_magic)
28 from IPython.core.magics import execution, script, code, logging, osm
29 from IPython.core.magics import execution, script, code, logging, osm
29 from IPython.testing import decorators as dec
30 from IPython.testing import decorators as dec
30 from IPython.testing import tools as tt
31 from IPython.testing import tools as tt
31 from IPython.utils.io import capture_output
32 from IPython.utils.io import capture_output
32 from IPython.utils.tempdir import (TemporaryDirectory,
33 from IPython.utils.tempdir import (TemporaryDirectory,
33 TemporaryWorkingDirectory)
34 TemporaryWorkingDirectory)
34 from IPython.utils.process import find_cmd
35 from IPython.utils.process import find_cmd
35 from .test_debugger import PdbTestInput
36 from .test_debugger import PdbTestInput
36
37
37
38
38 @magic.magics_class
39 @magic.magics_class
39 class DummyMagics(magic.Magics): pass
40 class DummyMagics(magic.Magics): pass
40
41
41 def test_extract_code_ranges():
42 def test_extract_code_ranges():
42 instr = "1 3 5-6 7-9 10:15 17: :10 10- -13 :"
43 instr = "1 3 5-6 7-9 10:15 17: :10 10- -13 :"
43 expected = [(0, 1),
44 expected = [(0, 1),
44 (2, 3),
45 (2, 3),
45 (4, 6),
46 (4, 6),
46 (6, 9),
47 (6, 9),
47 (9, 14),
48 (9, 14),
48 (16, None),
49 (16, None),
49 (None, 9),
50 (None, 9),
50 (9, None),
51 (9, None),
51 (None, 13),
52 (None, 13),
52 (None, None)]
53 (None, None)]
53 actual = list(code.extract_code_ranges(instr))
54 actual = list(code.extract_code_ranges(instr))
54 nt.assert_equal(actual, expected)
55 nt.assert_equal(actual, expected)
55
56
56 def test_extract_symbols():
57 def test_extract_symbols():
57 source = """import foo\na = 10\ndef b():\n return 42\n\n\nclass A: pass\n\n\n"""
58 source = """import foo\na = 10\ndef b():\n return 42\n\n\nclass A: pass\n\n\n"""
58 symbols_args = ["a", "b", "A", "A,b", "A,a", "z"]
59 symbols_args = ["a", "b", "A", "A,b", "A,a", "z"]
59 expected = [([], ['a']),
60 expected = [([], ['a']),
60 (["def b():\n return 42\n"], []),
61 (["def b():\n return 42\n"], []),
61 (["class A: pass\n"], []),
62 (["class A: pass\n"], []),
62 (["class A: pass\n", "def b():\n return 42\n"], []),
63 (["class A: pass\n", "def b():\n return 42\n"], []),
63 (["class A: pass\n"], ['a']),
64 (["class A: pass\n"], ['a']),
64 ([], ['z'])]
65 ([], ['z'])]
65 for symbols, exp in zip(symbols_args, expected):
66 for symbols, exp in zip(symbols_args, expected):
66 nt.assert_equal(code.extract_symbols(source, symbols), exp)
67 nt.assert_equal(code.extract_symbols(source, symbols), exp)
67
68
68
69
69 def test_extract_symbols_raises_exception_with_non_python_code():
70 def test_extract_symbols_raises_exception_with_non_python_code():
70 source = ("=begin A Ruby program :)=end\n"
71 source = ("=begin A Ruby program :)=end\n"
71 "def hello\n"
72 "def hello\n"
72 "puts 'Hello world'\n"
73 "puts 'Hello world'\n"
73 "end")
74 "end")
74 with nt.assert_raises(SyntaxError):
75 with nt.assert_raises(SyntaxError):
75 code.extract_symbols(source, "hello")
76 code.extract_symbols(source, "hello")
76
77
77
78
78 def test_magic_not_found():
79 def test_magic_not_found():
79 # magic not found raises UsageError
80 # magic not found raises UsageError
80 with nt.assert_raises(UsageError):
81 with nt.assert_raises(UsageError):
81 _ip.magic('doesntexist')
82 _ip.magic('doesntexist')
82
83
83 # ensure result isn't success when a magic isn't found
84 # ensure result isn't success when a magic isn't found
84 result = _ip.run_cell('%doesntexist')
85 result = _ip.run_cell('%doesntexist')
85 assert isinstance(result.error_in_exec, UsageError)
86 assert isinstance(result.error_in_exec, UsageError)
86
87
87
88
88 def test_cell_magic_not_found():
89 def test_cell_magic_not_found():
89 # magic not found raises UsageError
90 # magic not found raises UsageError
90 with nt.assert_raises(UsageError):
91 with nt.assert_raises(UsageError):
91 _ip.run_cell_magic('doesntexist', 'line', 'cell')
92 _ip.run_cell_magic('doesntexist', 'line', 'cell')
92
93
93 # ensure result isn't success when a magic isn't found
94 # ensure result isn't success when a magic isn't found
94 result = _ip.run_cell('%%doesntexist')
95 result = _ip.run_cell('%%doesntexist')
95 assert isinstance(result.error_in_exec, UsageError)
96 assert isinstance(result.error_in_exec, UsageError)
96
97
97
98
98 def test_magic_error_status():
99 def test_magic_error_status():
99 def fail(shell):
100 def fail(shell):
100 1/0
101 1/0
101 _ip.register_magic_function(fail)
102 _ip.register_magic_function(fail)
102 result = _ip.run_cell('%fail')
103 result = _ip.run_cell('%fail')
103 assert isinstance(result.error_in_exec, ZeroDivisionError)
104 assert isinstance(result.error_in_exec, ZeroDivisionError)
104
105
105
106
106 def test_config():
107 def test_config():
107 """ test that config magic does not raise
108 """ test that config magic does not raise
108 can happen if Configurable init is moved too early into
109 can happen if Configurable init is moved too early into
109 Magics.__init__ as then a Config object will be registered as a
110 Magics.__init__ as then a Config object will be registered as a
110 magic.
111 magic.
111 """
112 """
112 ## should not raise.
113 ## should not raise.
113 _ip.magic('config')
114 _ip.magic('config')
114
115
115 def test_config_available_configs():
116 def test_config_available_configs():
116 """ test that config magic prints available configs in unique and
117 """ test that config magic prints available configs in unique and
117 sorted order. """
118 sorted order. """
118 with capture_output() as captured:
119 with capture_output() as captured:
119 _ip.magic('config')
120 _ip.magic('config')
120
121
121 stdout = captured.stdout
122 stdout = captured.stdout
122 config_classes = stdout.strip().split('\n')[1:]
123 config_classes = stdout.strip().split('\n')[1:]
123 nt.assert_list_equal(config_classes, sorted(set(config_classes)))
124 nt.assert_list_equal(config_classes, sorted(set(config_classes)))
124
125
125 def test_config_print_class():
126 def test_config_print_class():
126 """ test that config with a classname prints the class's options. """
127 """ test that config with a classname prints the class's options. """
127 with capture_output() as captured:
128 with capture_output() as captured:
128 _ip.magic('config TerminalInteractiveShell')
129 _ip.magic('config TerminalInteractiveShell')
129
130
130 stdout = captured.stdout
131 stdout = captured.stdout
131 if not re.match("TerminalInteractiveShell.* options", stdout.splitlines()[0]):
132 if not re.match("TerminalInteractiveShell.* options", stdout.splitlines()[0]):
132 print(stdout)
133 print(stdout)
133 raise AssertionError("1st line of stdout not like "
134 raise AssertionError("1st line of stdout not like "
134 "'TerminalInteractiveShell.* options'")
135 "'TerminalInteractiveShell.* options'")
135
136
136 def test_rehashx():
137 def test_rehashx():
137 # clear up everything
138 # clear up everything
138 _ip.alias_manager.clear_aliases()
139 _ip.alias_manager.clear_aliases()
139 del _ip.db['syscmdlist']
140 del _ip.db['syscmdlist']
140
141
141 _ip.magic('rehashx')
142 _ip.magic('rehashx')
142 # Practically ALL ipython development systems will have more than 10 aliases
143 # Practically ALL ipython development systems will have more than 10 aliases
143
144
144 nt.assert_true(len(_ip.alias_manager.aliases) > 10)
145 nt.assert_true(len(_ip.alias_manager.aliases) > 10)
145 for name, cmd in _ip.alias_manager.aliases:
146 for name, cmd in _ip.alias_manager.aliases:
146 # we must strip dots from alias names
147 # we must strip dots from alias names
147 nt.assert_not_in('.', name)
148 nt.assert_not_in('.', name)
148
149
149 # rehashx must fill up syscmdlist
150 # rehashx must fill up syscmdlist
150 scoms = _ip.db['syscmdlist']
151 scoms = _ip.db['syscmdlist']
151 nt.assert_true(len(scoms) > 10)
152 nt.assert_true(len(scoms) > 10)
152
153
153
154
154
155
155 def test_magic_parse_options():
156 def test_magic_parse_options():
156 """Test that we don't mangle paths when parsing magic options."""
157 """Test that we don't mangle paths when parsing magic options."""
157 ip = get_ipython()
158 ip = get_ipython()
158 path = 'c:\\x'
159 path = 'c:\\x'
159 m = DummyMagics(ip)
160 m = DummyMagics(ip)
160 opts = m.parse_options('-f %s' % path,'f:')[0]
161 opts = m.parse_options('-f %s' % path,'f:')[0]
161 # argv splitting is os-dependent
162 # argv splitting is os-dependent
162 if os.name == 'posix':
163 if os.name == 'posix':
163 expected = 'c:x'
164 expected = 'c:x'
164 else:
165 else:
165 expected = path
166 expected = path
166 nt.assert_equal(opts['f'], expected)
167 nt.assert_equal(opts['f'], expected)
167
168
168 def test_magic_parse_long_options():
169 def test_magic_parse_long_options():
169 """Magic.parse_options can handle --foo=bar long options"""
170 """Magic.parse_options can handle --foo=bar long options"""
170 ip = get_ipython()
171 ip = get_ipython()
171 m = DummyMagics(ip)
172 m = DummyMagics(ip)
172 opts, _ = m.parse_options('--foo --bar=bubble', 'a', 'foo', 'bar=')
173 opts, _ = m.parse_options('--foo --bar=bubble', 'a', 'foo', 'bar=')
173 nt.assert_in('foo', opts)
174 nt.assert_in('foo', opts)
174 nt.assert_in('bar', opts)
175 nt.assert_in('bar', opts)
175 nt.assert_equal(opts['bar'], "bubble")
176 nt.assert_equal(opts['bar'], "bubble")
176
177
177
178
178 def doctest_hist_f():
179 def doctest_hist_f():
179 """Test %hist -f with temporary filename.
180 """Test %hist -f with temporary filename.
180
181
181 In [9]: import tempfile
182 In [9]: import tempfile
182
183
183 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
184 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
184
185
185 In [11]: %hist -nl -f $tfile 3
186 In [11]: %hist -nl -f $tfile 3
186
187
187 In [13]: import os; os.unlink(tfile)
188 In [13]: import os; os.unlink(tfile)
188 """
189 """
189
190
190
191
191 def doctest_hist_op():
192 def doctest_hist_op():
192 """Test %hist -op
193 """Test %hist -op
193
194
194 In [1]: class b(float):
195 In [1]: class b(float):
195 ...: pass
196 ...: pass
196 ...:
197 ...:
197
198
198 In [2]: class s(object):
199 In [2]: class s(object):
199 ...: def __str__(self):
200 ...: def __str__(self):
200 ...: return 's'
201 ...: return 's'
201 ...:
202 ...:
202
203
203 In [3]:
204 In [3]:
204
205
205 In [4]: class r(b):
206 In [4]: class r(b):
206 ...: def __repr__(self):
207 ...: def __repr__(self):
207 ...: return 'r'
208 ...: return 'r'
208 ...:
209 ...:
209
210
210 In [5]: class sr(s,r): pass
211 In [5]: class sr(s,r): pass
211 ...:
212 ...:
212
213
213 In [6]:
214 In [6]:
214
215
215 In [7]: bb=b()
216 In [7]: bb=b()
216
217
217 In [8]: ss=s()
218 In [8]: ss=s()
218
219
219 In [9]: rr=r()
220 In [9]: rr=r()
220
221
221 In [10]: ssrr=sr()
222 In [10]: ssrr=sr()
222
223
223 In [11]: 4.5
224 In [11]: 4.5
224 Out[11]: 4.5
225 Out[11]: 4.5
225
226
226 In [12]: str(ss)
227 In [12]: str(ss)
227 Out[12]: 's'
228 Out[12]: 's'
228
229
229 In [13]:
230 In [13]:
230
231
231 In [14]: %hist -op
232 In [14]: %hist -op
232 >>> class b:
233 >>> class b:
233 ... pass
234 ... pass
234 ...
235 ...
235 >>> class s(b):
236 >>> class s(b):
236 ... def __str__(self):
237 ... def __str__(self):
237 ... return 's'
238 ... return 's'
238 ...
239 ...
239 >>>
240 >>>
240 >>> class r(b):
241 >>> class r(b):
241 ... def __repr__(self):
242 ... def __repr__(self):
242 ... return 'r'
243 ... return 'r'
243 ...
244 ...
244 >>> class sr(s,r): pass
245 >>> class sr(s,r): pass
245 >>>
246 >>>
246 >>> bb=b()
247 >>> bb=b()
247 >>> ss=s()
248 >>> ss=s()
248 >>> rr=r()
249 >>> rr=r()
249 >>> ssrr=sr()
250 >>> ssrr=sr()
250 >>> 4.5
251 >>> 4.5
251 4.5
252 4.5
252 >>> str(ss)
253 >>> str(ss)
253 's'
254 's'
254 >>>
255 >>>
255 """
256 """
256
257
257 def test_hist_pof():
258 def test_hist_pof():
258 ip = get_ipython()
259 ip = get_ipython()
259 ip.run_cell(u"1+2", store_history=True)
260 ip.run_cell(u"1+2", store_history=True)
260 #raise Exception(ip.history_manager.session_number)
261 #raise Exception(ip.history_manager.session_number)
261 #raise Exception(list(ip.history_manager._get_range_session()))
262 #raise Exception(list(ip.history_manager._get_range_session()))
262 with TemporaryDirectory() as td:
263 with TemporaryDirectory() as td:
263 tf = os.path.join(td, 'hist.py')
264 tf = os.path.join(td, 'hist.py')
264 ip.run_line_magic('history', '-pof %s' % tf)
265 ip.run_line_magic('history', '-pof %s' % tf)
265 assert os.path.isfile(tf)
266 assert os.path.isfile(tf)
266
267
267
268
268 def test_macro():
269 def test_macro():
269 ip = get_ipython()
270 ip = get_ipython()
270 ip.history_manager.reset() # Clear any existing history.
271 ip.history_manager.reset() # Clear any existing history.
271 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
272 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
272 for i, cmd in enumerate(cmds, start=1):
273 for i, cmd in enumerate(cmds, start=1):
273 ip.history_manager.store_inputs(i, cmd)
274 ip.history_manager.store_inputs(i, cmd)
274 ip.magic("macro test 1-3")
275 ip.magic("macro test 1-3")
275 nt.assert_equal(ip.user_ns["test"].value, "\n".join(cmds)+"\n")
276 nt.assert_equal(ip.user_ns["test"].value, "\n".join(cmds)+"\n")
276
277
277 # List macros
278 # List macros
278 nt.assert_in("test", ip.magic("macro"))
279 nt.assert_in("test", ip.magic("macro"))
279
280
280
281
281 def test_macro_run():
282 def test_macro_run():
282 """Test that we can run a multi-line macro successfully."""
283 """Test that we can run a multi-line macro successfully."""
283 ip = get_ipython()
284 ip = get_ipython()
284 ip.history_manager.reset()
285 ip.history_manager.reset()
285 cmds = ["a=10", "a+=1", "print(a)", "%macro test 2-3"]
286 cmds = ["a=10", "a+=1", "print(a)", "%macro test 2-3"]
286 for cmd in cmds:
287 for cmd in cmds:
287 ip.run_cell(cmd, store_history=True)
288 ip.run_cell(cmd, store_history=True)
288 nt.assert_equal(ip.user_ns["test"].value, "a+=1\nprint(a)\n")
289 nt.assert_equal(ip.user_ns["test"].value, "a+=1\nprint(a)\n")
289 with tt.AssertPrints("12"):
290 with tt.AssertPrints("12"):
290 ip.run_cell("test")
291 ip.run_cell("test")
291 with tt.AssertPrints("13"):
292 with tt.AssertPrints("13"):
292 ip.run_cell("test")
293 ip.run_cell("test")
293
294
294
295
295 def test_magic_magic():
296 def test_magic_magic():
296 """Test %magic"""
297 """Test %magic"""
297 ip = get_ipython()
298 ip = get_ipython()
298 with capture_output() as captured:
299 with capture_output() as captured:
299 ip.magic("magic")
300 ip.magic("magic")
300
301
301 stdout = captured.stdout
302 stdout = captured.stdout
302 nt.assert_in('%magic', stdout)
303 nt.assert_in('%magic', stdout)
303 nt.assert_in('IPython', stdout)
304 nt.assert_in('IPython', stdout)
304 nt.assert_in('Available', stdout)
305 nt.assert_in('Available', stdout)
305
306
306
307
307 @dec.skipif_not_numpy
308 @dec.skipif_not_numpy
308 def test_numpy_reset_array_undec():
309 def test_numpy_reset_array_undec():
309 "Test '%reset array' functionality"
310 "Test '%reset array' functionality"
310 _ip.ex('import numpy as np')
311 _ip.ex('import numpy as np')
311 _ip.ex('a = np.empty(2)')
312 _ip.ex('a = np.empty(2)')
312 nt.assert_in('a', _ip.user_ns)
313 nt.assert_in('a', _ip.user_ns)
313 _ip.magic('reset -f array')
314 _ip.magic('reset -f array')
314 nt.assert_not_in('a', _ip.user_ns)
315 nt.assert_not_in('a', _ip.user_ns)
315
316
316 def test_reset_out():
317 def test_reset_out():
317 "Test '%reset out' magic"
318 "Test '%reset out' magic"
318 _ip.run_cell("parrot = 'dead'", store_history=True)
319 _ip.run_cell("parrot = 'dead'", store_history=True)
319 # test '%reset -f out', make an Out prompt
320 # test '%reset -f out', make an Out prompt
320 _ip.run_cell("parrot", store_history=True)
321 _ip.run_cell("parrot", store_history=True)
321 nt.assert_true('dead' in [_ip.user_ns[x] for x in ('_','__','___')])
322 nt.assert_true('dead' in [_ip.user_ns[x] for x in ('_','__','___')])
322 _ip.magic('reset -f out')
323 _ip.magic('reset -f out')
323 nt.assert_false('dead' in [_ip.user_ns[x] for x in ('_','__','___')])
324 nt.assert_false('dead' in [_ip.user_ns[x] for x in ('_','__','___')])
324 nt.assert_equal(len(_ip.user_ns['Out']), 0)
325 nt.assert_equal(len(_ip.user_ns['Out']), 0)
325
326
326 def test_reset_in():
327 def test_reset_in():
327 "Test '%reset in' magic"
328 "Test '%reset in' magic"
328 # test '%reset -f in'
329 # test '%reset -f in'
329 _ip.run_cell("parrot", store_history=True)
330 _ip.run_cell("parrot", store_history=True)
330 nt.assert_true('parrot' in [_ip.user_ns[x] for x in ('_i','_ii','_iii')])
331 nt.assert_true('parrot' in [_ip.user_ns[x] for x in ('_i','_ii','_iii')])
331 _ip.magic('%reset -f in')
332 _ip.magic('%reset -f in')
332 nt.assert_false('parrot' in [_ip.user_ns[x] for x in ('_i','_ii','_iii')])
333 nt.assert_false('parrot' in [_ip.user_ns[x] for x in ('_i','_ii','_iii')])
333 nt.assert_equal(len(set(_ip.user_ns['In'])), 1)
334 nt.assert_equal(len(set(_ip.user_ns['In'])), 1)
334
335
335 def test_reset_dhist():
336 def test_reset_dhist():
336 "Test '%reset dhist' magic"
337 "Test '%reset dhist' magic"
337 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
338 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
338 _ip.magic('cd ' + os.path.dirname(nt.__file__))
339 _ip.magic('cd ' + os.path.dirname(nt.__file__))
339 _ip.magic('cd -')
340 _ip.magic('cd -')
340 nt.assert_true(len(_ip.user_ns['_dh']) > 0)
341 nt.assert_true(len(_ip.user_ns['_dh']) > 0)
341 _ip.magic('reset -f dhist')
342 _ip.magic('reset -f dhist')
342 nt.assert_equal(len(_ip.user_ns['_dh']), 0)
343 nt.assert_equal(len(_ip.user_ns['_dh']), 0)
343 _ip.run_cell("_dh = [d for d in tmp]") #restore
344 _ip.run_cell("_dh = [d for d in tmp]") #restore
344
345
345 def test_reset_in_length():
346 def test_reset_in_length():
346 "Test that '%reset in' preserves In[] length"
347 "Test that '%reset in' preserves In[] length"
347 _ip.run_cell("print 'foo'")
348 _ip.run_cell("print 'foo'")
348 _ip.run_cell("reset -f in")
349 _ip.run_cell("reset -f in")
349 nt.assert_equal(len(_ip.user_ns['In']), _ip.displayhook.prompt_count+1)
350 nt.assert_equal(len(_ip.user_ns['In']), _ip.displayhook.prompt_count+1)
350
351
351 class TestResetErrors(TestCase):
352 class TestResetErrors(TestCase):
352
353
353 def test_reset_redefine(self):
354 def test_reset_redefine(self):
354
355
355 @magics_class
356 @magics_class
356 class KernelMagics(Magics):
357 class KernelMagics(Magics):
357 @line_magic
358 @line_magic
358 def less(self, shell): pass
359 def less(self, shell): pass
359
360
360 _ip.register_magics(KernelMagics)
361 _ip.register_magics(KernelMagics)
361
362
362 with self.assertLogs() as cm:
363 with self.assertLogs() as cm:
363 # hack, we want to just capture logs, but assertLogs fails if not
364 # hack, we want to just capture logs, but assertLogs fails if not
364 # logs get produce.
365 # logs get produce.
365 # so log one things we ignore.
366 # so log one things we ignore.
366 import logging as log_mod
367 import logging as log_mod
367 log = log_mod.getLogger()
368 log = log_mod.getLogger()
368 log.info('Nothing')
369 log.info('Nothing')
369 # end hack.
370 # end hack.
370 _ip.run_cell("reset -f")
371 _ip.run_cell("reset -f")
371
372
372 assert len(cm.output) == 1
373 assert len(cm.output) == 1
373 for out in cm.output:
374 for out in cm.output:
374 assert "Invalid alias" not in out
375 assert "Invalid alias" not in out
375
376
376 def test_tb_syntaxerror():
377 def test_tb_syntaxerror():
377 """test %tb after a SyntaxError"""
378 """test %tb after a SyntaxError"""
378 ip = get_ipython()
379 ip = get_ipython()
379 ip.run_cell("for")
380 ip.run_cell("for")
380
381
381 # trap and validate stdout
382 # trap and validate stdout
382 save_stdout = sys.stdout
383 save_stdout = sys.stdout
383 try:
384 try:
384 sys.stdout = StringIO()
385 sys.stdout = StringIO()
385 ip.run_cell("%tb")
386 ip.run_cell("%tb")
386 out = sys.stdout.getvalue()
387 out = sys.stdout.getvalue()
387 finally:
388 finally:
388 sys.stdout = save_stdout
389 sys.stdout = save_stdout
389 # trim output, and only check the last line
390 # trim output, and only check the last line
390 last_line = out.rstrip().splitlines()[-1].strip()
391 last_line = out.rstrip().splitlines()[-1].strip()
391 nt.assert_equal(last_line, "SyntaxError: invalid syntax")
392 nt.assert_equal(last_line, "SyntaxError: invalid syntax")
392
393
393
394
394 def test_time():
395 def test_time():
395 ip = get_ipython()
396 ip = get_ipython()
396
397
397 with tt.AssertPrints("Wall time: "):
398 with tt.AssertPrints("Wall time: "):
398 ip.run_cell("%time None")
399 ip.run_cell("%time None")
399
400
400 ip.run_cell("def f(kmjy):\n"
401 ip.run_cell("def f(kmjy):\n"
401 " %time print (2*kmjy)")
402 " %time print (2*kmjy)")
402
403
403 with tt.AssertPrints("Wall time: "):
404 with tt.AssertPrints("Wall time: "):
404 with tt.AssertPrints("hihi", suppress=False):
405 with tt.AssertPrints("hihi", suppress=False):
405 ip.run_cell("f('hi')")
406 ip.run_cell("f('hi')")
406
407
407 def test_time_last_not_expression():
408 def test_time_last_not_expression():
408 ip.run_cell("%%time\n"
409 ip.run_cell("%%time\n"
409 "var_1 = 1\n"
410 "var_1 = 1\n"
410 "var_2 = 2\n")
411 "var_2 = 2\n")
411 assert ip.user_ns['var_1'] == 1
412 assert ip.user_ns['var_1'] == 1
412 del ip.user_ns['var_1']
413 del ip.user_ns['var_1']
413 assert ip.user_ns['var_2'] == 2
414 assert ip.user_ns['var_2'] == 2
414 del ip.user_ns['var_2']
415 del ip.user_ns['var_2']
415
416
416
417
417 @dec.skip_win32
418 @dec.skip_win32
418 def test_time2():
419 def test_time2():
419 ip = get_ipython()
420 ip = get_ipython()
420
421
421 with tt.AssertPrints("CPU times: user "):
422 with tt.AssertPrints("CPU times: user "):
422 ip.run_cell("%time None")
423 ip.run_cell("%time None")
423
424
424 def test_time3():
425 def test_time3():
425 """Erroneous magic function calls, issue gh-3334"""
426 """Erroneous magic function calls, issue gh-3334"""
426 ip = get_ipython()
427 ip = get_ipython()
427 ip.user_ns.pop('run', None)
428 ip.user_ns.pop('run', None)
428
429
429 with tt.AssertNotPrints("not found", channel='stderr'):
430 with tt.AssertNotPrints("not found", channel='stderr'):
430 ip.run_cell("%%time\n"
431 ip.run_cell("%%time\n"
431 "run = 0\n"
432 "run = 0\n"
432 "run += 1")
433 "run += 1")
433
434
434 def test_multiline_time():
435 def test_multiline_time():
435 """Make sure last statement from time return a value."""
436 """Make sure last statement from time return a value."""
436 ip = get_ipython()
437 ip = get_ipython()
437 ip.user_ns.pop('run', None)
438 ip.user_ns.pop('run', None)
438
439
439 ip.run_cell(dedent("""\
440 ip.run_cell(dedent("""\
440 %%time
441 %%time
441 a = "ho"
442 a = "ho"
442 b = "hey"
443 b = "hey"
443 a+b
444 a+b
444 """))
445 """))
445 nt.assert_equal(ip.user_ns_hidden['_'], 'hohey')
446 nt.assert_equal(ip.user_ns_hidden['_'], 'hohey')
446
447
447 def test_time_local_ns():
448 def test_time_local_ns():
448 """
449 """
449 Test that local_ns is actually global_ns when running a cell magic
450 Test that local_ns is actually global_ns when running a cell magic
450 """
451 """
451 ip = get_ipython()
452 ip = get_ipython()
452 ip.run_cell("%%time\n"
453 ip.run_cell("%%time\n"
453 "myvar = 1")
454 "myvar = 1")
454 nt.assert_equal(ip.user_ns['myvar'], 1)
455 nt.assert_equal(ip.user_ns['myvar'], 1)
455 del ip.user_ns['myvar']
456 del ip.user_ns['myvar']
456
457
457 def test_doctest_mode():
458 def test_doctest_mode():
458 "Toggle doctest_mode twice, it should be a no-op and run without error"
459 "Toggle doctest_mode twice, it should be a no-op and run without error"
459 _ip.magic('doctest_mode')
460 _ip.magic('doctest_mode')
460 _ip.magic('doctest_mode')
461 _ip.magic('doctest_mode')
461
462
462
463
463 def test_parse_options():
464 def test_parse_options():
464 """Tests for basic options parsing in magics."""
465 """Tests for basic options parsing in magics."""
465 # These are only the most minimal of tests, more should be added later. At
466 # These are only the most minimal of tests, more should be added later. At
466 # the very least we check that basic text/unicode calls work OK.
467 # the very least we check that basic text/unicode calls work OK.
467 m = DummyMagics(_ip)
468 m = DummyMagics(_ip)
468 nt.assert_equal(m.parse_options('foo', '')[1], 'foo')
469 nt.assert_equal(m.parse_options('foo', '')[1], 'foo')
469 nt.assert_equal(m.parse_options(u'foo', '')[1], u'foo')
470 nt.assert_equal(m.parse_options(u'foo', '')[1], u'foo')
470
471
471
472
472 def test_dirops():
473 def test_dirops():
473 """Test various directory handling operations."""
474 """Test various directory handling operations."""
474 # curpath = lambda :os.path.splitdrive(os.getcwd())[1].replace('\\','/')
475 # curpath = lambda :os.path.splitdrive(os.getcwd())[1].replace('\\','/')
475 curpath = os.getcwd
476 curpath = os.getcwd
476 startdir = os.getcwd()
477 startdir = os.getcwd()
477 ipdir = os.path.realpath(_ip.ipython_dir)
478 ipdir = os.path.realpath(_ip.ipython_dir)
478 try:
479 try:
479 _ip.magic('cd "%s"' % ipdir)
480 _ip.magic('cd "%s"' % ipdir)
480 nt.assert_equal(curpath(), ipdir)
481 nt.assert_equal(curpath(), ipdir)
481 _ip.magic('cd -')
482 _ip.magic('cd -')
482 nt.assert_equal(curpath(), startdir)
483 nt.assert_equal(curpath(), startdir)
483 _ip.magic('pushd "%s"' % ipdir)
484 _ip.magic('pushd "%s"' % ipdir)
484 nt.assert_equal(curpath(), ipdir)
485 nt.assert_equal(curpath(), ipdir)
485 _ip.magic('popd')
486 _ip.magic('popd')
486 nt.assert_equal(curpath(), startdir)
487 nt.assert_equal(curpath(), startdir)
487 finally:
488 finally:
488 os.chdir(startdir)
489 os.chdir(startdir)
489
490
490
491
491 def test_cd_force_quiet():
492 def test_cd_force_quiet():
492 """Test OSMagics.cd_force_quiet option"""
493 """Test OSMagics.cd_force_quiet option"""
493 _ip.config.OSMagics.cd_force_quiet = True
494 _ip.config.OSMagics.cd_force_quiet = True
494 osmagics = osm.OSMagics(shell=_ip)
495 osmagics = osm.OSMagics(shell=_ip)
495
496
496 startdir = os.getcwd()
497 startdir = os.getcwd()
497 ipdir = os.path.realpath(_ip.ipython_dir)
498 ipdir = os.path.realpath(_ip.ipython_dir)
498
499
499 try:
500 try:
500 with tt.AssertNotPrints(ipdir):
501 with tt.AssertNotPrints(ipdir):
501 osmagics.cd('"%s"' % ipdir)
502 osmagics.cd('"%s"' % ipdir)
502 with tt.AssertNotPrints(startdir):
503 with tt.AssertNotPrints(startdir):
503 osmagics.cd('-')
504 osmagics.cd('-')
504 finally:
505 finally:
505 os.chdir(startdir)
506 os.chdir(startdir)
506
507
507
508
508 def test_xmode():
509 def test_xmode():
509 # Calling xmode three times should be a no-op
510 # Calling xmode three times should be a no-op
510 xmode = _ip.InteractiveTB.mode
511 xmode = _ip.InteractiveTB.mode
511 for i in range(4):
512 for i in range(4):
512 _ip.magic("xmode")
513 _ip.magic("xmode")
513 nt.assert_equal(_ip.InteractiveTB.mode, xmode)
514 nt.assert_equal(_ip.InteractiveTB.mode, xmode)
514
515
515 def test_reset_hard():
516 def test_reset_hard():
516 monitor = []
517 monitor = []
517 class A(object):
518 class A(object):
518 def __del__(self):
519 def __del__(self):
519 monitor.append(1)
520 monitor.append(1)
520 def __repr__(self):
521 def __repr__(self):
521 return "<A instance>"
522 return "<A instance>"
522
523
523 _ip.user_ns["a"] = A()
524 _ip.user_ns["a"] = A()
524 _ip.run_cell("a")
525 _ip.run_cell("a")
525
526
526 nt.assert_equal(monitor, [])
527 nt.assert_equal(monitor, [])
527 _ip.magic("reset -f")
528 _ip.magic("reset -f")
528 nt.assert_equal(monitor, [1])
529 nt.assert_equal(monitor, [1])
529
530
530 class TestXdel(tt.TempFileMixin):
531 class TestXdel(tt.TempFileMixin):
531 def test_xdel(self):
532 def test_xdel(self):
532 """Test that references from %run are cleared by xdel."""
533 """Test that references from %run are cleared by xdel."""
533 src = ("class A(object):\n"
534 src = ("class A(object):\n"
534 " monitor = []\n"
535 " monitor = []\n"
535 " def __del__(self):\n"
536 " def __del__(self):\n"
536 " self.monitor.append(1)\n"
537 " self.monitor.append(1)\n"
537 "a = A()\n")
538 "a = A()\n")
538 self.mktmp(src)
539 self.mktmp(src)
539 # %run creates some hidden references...
540 # %run creates some hidden references...
540 _ip.magic("run %s" % self.fname)
541 _ip.magic("run %s" % self.fname)
541 # ... as does the displayhook.
542 # ... as does the displayhook.
542 _ip.run_cell("a")
543 _ip.run_cell("a")
543
544
544 monitor = _ip.user_ns["A"].monitor
545 monitor = _ip.user_ns["A"].monitor
545 nt.assert_equal(monitor, [])
546 nt.assert_equal(monitor, [])
546
547
547 _ip.magic("xdel a")
548 _ip.magic("xdel a")
548
549
549 # Check that a's __del__ method has been called.
550 # Check that a's __del__ method has been called.
550 nt.assert_equal(monitor, [1])
551 nt.assert_equal(monitor, [1])
551
552
552 def doctest_who():
553 def doctest_who():
553 """doctest for %who
554 """doctest for %who
554
555
555 In [1]: %reset -f
556 In [1]: %reset -f
556
557
557 In [2]: alpha = 123
558 In [2]: alpha = 123
558
559
559 In [3]: beta = 'beta'
560 In [3]: beta = 'beta'
560
561
561 In [4]: %who int
562 In [4]: %who int
562 alpha
563 alpha
563
564
564 In [5]: %who str
565 In [5]: %who str
565 beta
566 beta
566
567
567 In [6]: %whos
568 In [6]: %whos
568 Variable Type Data/Info
569 Variable Type Data/Info
569 ----------------------------
570 ----------------------------
570 alpha int 123
571 alpha int 123
571 beta str beta
572 beta str beta
572
573
573 In [7]: %who_ls
574 In [7]: %who_ls
574 Out[7]: ['alpha', 'beta']
575 Out[7]: ['alpha', 'beta']
575 """
576 """
576
577
577 def test_whos():
578 def test_whos():
578 """Check that whos is protected against objects where repr() fails."""
579 """Check that whos is protected against objects where repr() fails."""
579 class A(object):
580 class A(object):
580 def __repr__(self):
581 def __repr__(self):
581 raise Exception()
582 raise Exception()
582 _ip.user_ns['a'] = A()
583 _ip.user_ns['a'] = A()
583 _ip.magic("whos")
584 _ip.magic("whos")
584
585
585 def doctest_precision():
586 def doctest_precision():
586 """doctest for %precision
587 """doctest for %precision
587
588
588 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
589 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
589
590
590 In [2]: %precision 5
591 In [2]: %precision 5
591 Out[2]: '%.5f'
592 Out[2]: '%.5f'
592
593
593 In [3]: f.float_format
594 In [3]: f.float_format
594 Out[3]: '%.5f'
595 Out[3]: '%.5f'
595
596
596 In [4]: %precision %e
597 In [4]: %precision %e
597 Out[4]: '%e'
598 Out[4]: '%e'
598
599
599 In [5]: f(3.1415927)
600 In [5]: f(3.1415927)
600 Out[5]: '3.141593e+00'
601 Out[5]: '3.141593e+00'
601 """
602 """
602
603
603 def test_debug_magic():
604 def test_debug_magic():
604 """Test debugging a small code with %debug
605 """Test debugging a small code with %debug
605
606
606 In [1]: with PdbTestInput(['c']):
607 In [1]: with PdbTestInput(['c']):
607 ...: %debug print("a b") #doctest: +ELLIPSIS
608 ...: %debug print("a b") #doctest: +ELLIPSIS
608 ...:
609 ...:
609 ...
610 ...
610 ipdb> c
611 ipdb> c
611 a b
612 a b
612 In [2]:
613 In [2]:
613 """
614 """
614
615
615 def test_psearch():
616 def test_psearch():
616 with tt.AssertPrints("dict.fromkeys"):
617 with tt.AssertPrints("dict.fromkeys"):
617 _ip.run_cell("dict.fr*?")
618 _ip.run_cell("dict.fr*?")
618 with tt.AssertPrints("Ο€.is_integer"):
619 with tt.AssertPrints("Ο€.is_integer"):
619 _ip.run_cell("Ο€ = 3.14;\nΟ€.is_integ*?")
620 _ip.run_cell("Ο€ = 3.14;\nΟ€.is_integ*?")
620
621
621 def test_timeit_shlex():
622 def test_timeit_shlex():
622 """test shlex issues with timeit (#1109)"""
623 """test shlex issues with timeit (#1109)"""
623 _ip.ex("def f(*a,**kw): pass")
624 _ip.ex("def f(*a,**kw): pass")
624 _ip.magic('timeit -n1 "this is a bug".count(" ")')
625 _ip.magic('timeit -n1 "this is a bug".count(" ")')
625 _ip.magic('timeit -r1 -n1 f(" ", 1)')
626 _ip.magic('timeit -r1 -n1 f(" ", 1)')
626 _ip.magic('timeit -r1 -n1 f(" ", 1, " ", 2, " ")')
627 _ip.magic('timeit -r1 -n1 f(" ", 1, " ", 2, " ")')
627 _ip.magic('timeit -r1 -n1 ("a " + "b")')
628 _ip.magic('timeit -r1 -n1 ("a " + "b")')
628 _ip.magic('timeit -r1 -n1 f("a " + "b")')
629 _ip.magic('timeit -r1 -n1 f("a " + "b")')
629 _ip.magic('timeit -r1 -n1 f("a " + "b ")')
630 _ip.magic('timeit -r1 -n1 f("a " + "b ")')
630
631
631
632
632 def test_timeit_special_syntax():
633 def test_timeit_special_syntax():
633 "Test %%timeit with IPython special syntax"
634 "Test %%timeit with IPython special syntax"
634 @register_line_magic
635 @register_line_magic
635 def lmagic(line):
636 def lmagic(line):
636 ip = get_ipython()
637 ip = get_ipython()
637 ip.user_ns['lmagic_out'] = line
638 ip.user_ns['lmagic_out'] = line
638
639
639 # line mode test
640 # line mode test
640 _ip.run_line_magic('timeit', '-n1 -r1 %lmagic my line')
641 _ip.run_line_magic('timeit', '-n1 -r1 %lmagic my line')
641 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
642 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
642 # cell mode test
643 # cell mode test
643 _ip.run_cell_magic('timeit', '-n1 -r1', '%lmagic my line2')
644 _ip.run_cell_magic('timeit', '-n1 -r1', '%lmagic my line2')
644 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
645 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
645
646
646 def test_timeit_return():
647 def test_timeit_return():
647 """
648 """
648 test whether timeit -o return object
649 test whether timeit -o return object
649 """
650 """
650
651
651 res = _ip.run_line_magic('timeit','-n10 -r10 -o 1')
652 res = _ip.run_line_magic('timeit','-n10 -r10 -o 1')
652 assert(res is not None)
653 assert(res is not None)
653
654
654 def test_timeit_quiet():
655 def test_timeit_quiet():
655 """
656 """
656 test quiet option of timeit magic
657 test quiet option of timeit magic
657 """
658 """
658 with tt.AssertNotPrints("loops"):
659 with tt.AssertNotPrints("loops"):
659 _ip.run_cell("%timeit -n1 -r1 -q 1")
660 _ip.run_cell("%timeit -n1 -r1 -q 1")
660
661
661 def test_timeit_return_quiet():
662 def test_timeit_return_quiet():
662 with tt.AssertNotPrints("loops"):
663 with tt.AssertNotPrints("loops"):
663 res = _ip.run_line_magic('timeit', '-n1 -r1 -q -o 1')
664 res = _ip.run_line_magic('timeit', '-n1 -r1 -q -o 1')
664 assert (res is not None)
665 assert (res is not None)
665
666
666 def test_timeit_invalid_return():
667 def test_timeit_invalid_return():
667 with nt.assert_raises_regex(SyntaxError, "outside function"):
668 with nt.assert_raises_regex(SyntaxError, "outside function"):
668 _ip.run_line_magic('timeit', 'return')
669 _ip.run_line_magic('timeit', 'return')
669
670
670 @dec.skipif(execution.profile is None)
671 @dec.skipif(execution.profile is None)
671 def test_prun_special_syntax():
672 def test_prun_special_syntax():
672 "Test %%prun with IPython special syntax"
673 "Test %%prun with IPython special syntax"
673 @register_line_magic
674 @register_line_magic
674 def lmagic(line):
675 def lmagic(line):
675 ip = get_ipython()
676 ip = get_ipython()
676 ip.user_ns['lmagic_out'] = line
677 ip.user_ns['lmagic_out'] = line
677
678
678 # line mode test
679 # line mode test
679 _ip.run_line_magic('prun', '-q %lmagic my line')
680 _ip.run_line_magic('prun', '-q %lmagic my line')
680 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
681 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
681 # cell mode test
682 # cell mode test
682 _ip.run_cell_magic('prun', '-q', '%lmagic my line2')
683 _ip.run_cell_magic('prun', '-q', '%lmagic my line2')
683 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
684 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
684
685
685 @dec.skipif(execution.profile is None)
686 @dec.skipif(execution.profile is None)
686 def test_prun_quotes():
687 def test_prun_quotes():
687 "Test that prun does not clobber string escapes (GH #1302)"
688 "Test that prun does not clobber string escapes (GH #1302)"
688 _ip.magic(r"prun -q x = '\t'")
689 _ip.magic(r"prun -q x = '\t'")
689 nt.assert_equal(_ip.user_ns['x'], '\t')
690 nt.assert_equal(_ip.user_ns['x'], '\t')
690
691
691 def test_extension():
692 def test_extension():
692 # Debugging information for failures of this test
693 # Debugging information for failures of this test
693 print('sys.path:')
694 print('sys.path:')
694 for p in sys.path:
695 for p in sys.path:
695 print(' ', p)
696 print(' ', p)
696 print('CWD', os.getcwd())
697 print('CWD', os.getcwd())
697
698
698 nt.assert_raises(ImportError, _ip.magic, "load_ext daft_extension")
699 nt.assert_raises(ImportError, _ip.magic, "load_ext daft_extension")
699 daft_path = os.path.join(os.path.dirname(__file__), "daft_extension")
700 daft_path = os.path.join(os.path.dirname(__file__), "daft_extension")
700 sys.path.insert(0, daft_path)
701 sys.path.insert(0, daft_path)
701 try:
702 try:
702 _ip.user_ns.pop('arq', None)
703 _ip.user_ns.pop('arq', None)
703 invalidate_caches() # Clear import caches
704 invalidate_caches() # Clear import caches
704 _ip.magic("load_ext daft_extension")
705 _ip.magic("load_ext daft_extension")
705 nt.assert_equal(_ip.user_ns['arq'], 185)
706 nt.assert_equal(_ip.user_ns['arq'], 185)
706 _ip.magic("unload_ext daft_extension")
707 _ip.magic("unload_ext daft_extension")
707 assert 'arq' not in _ip.user_ns
708 assert 'arq' not in _ip.user_ns
708 finally:
709 finally:
709 sys.path.remove(daft_path)
710 sys.path.remove(daft_path)
710
711
711
712
712 def test_notebook_export_json():
713 def test_notebook_export_json():
713 _ip = get_ipython()
714 _ip = get_ipython()
714 _ip.history_manager.reset() # Clear any existing history.
715 _ip.history_manager.reset() # Clear any existing history.
715 cmds = [u"a=1", u"def b():\n return a**2", u"print('noΓ«l, Γ©tΓ©', b())"]
716 cmds = [u"a=1", u"def b():\n return a**2", u"print('noΓ«l, Γ©tΓ©', b())"]
716 for i, cmd in enumerate(cmds, start=1):
717 for i, cmd in enumerate(cmds, start=1):
717 _ip.history_manager.store_inputs(i, cmd)
718 _ip.history_manager.store_inputs(i, cmd)
718 with TemporaryDirectory() as td:
719 with TemporaryDirectory() as td:
719 outfile = os.path.join(td, "nb.ipynb")
720 outfile = os.path.join(td, "nb.ipynb")
720 _ip.magic("notebook -e %s" % outfile)
721 _ip.magic("notebook -e %s" % outfile)
721
722
722
723
723 class TestEnv(TestCase):
724 class TestEnv(TestCase):
724
725
725 def test_env(self):
726 def test_env(self):
726 env = _ip.magic("env")
727 env = _ip.magic("env")
727 self.assertTrue(isinstance(env, dict))
728 self.assertTrue(isinstance(env, dict))
728
729
729 def test_env_secret(self):
730 def test_env_secret(self):
730 env = _ip.magic("env")
731 env = _ip.magic("env")
731 hidden = "<hidden>"
732 hidden = "<hidden>"
732 with mock.patch.dict(
733 with mock.patch.dict(
733 os.environ,
734 os.environ,
734 {
735 {
735 "API_KEY": "abc123",
736 "API_KEY": "abc123",
736 "SECRET_THING": "ssshhh",
737 "SECRET_THING": "ssshhh",
737 "JUPYTER_TOKEN": "",
738 "JUPYTER_TOKEN": "",
738 "VAR": "abc"
739 "VAR": "abc"
739 }
740 }
740 ):
741 ):
741 env = _ip.magic("env")
742 env = _ip.magic("env")
742 assert env["API_KEY"] == hidden
743 assert env["API_KEY"] == hidden
743 assert env["SECRET_THING"] == hidden
744 assert env["SECRET_THING"] == hidden
744 assert env["JUPYTER_TOKEN"] == hidden
745 assert env["JUPYTER_TOKEN"] == hidden
745 assert env["VAR"] == "abc"
746 assert env["VAR"] == "abc"
746
747
747 def test_env_get_set_simple(self):
748 def test_env_get_set_simple(self):
748 env = _ip.magic("env var val1")
749 env = _ip.magic("env var val1")
749 self.assertEqual(env, None)
750 self.assertEqual(env, None)
750 self.assertEqual(os.environ['var'], 'val1')
751 self.assertEqual(os.environ['var'], 'val1')
751 self.assertEqual(_ip.magic("env var"), 'val1')
752 self.assertEqual(_ip.magic("env var"), 'val1')
752 env = _ip.magic("env var=val2")
753 env = _ip.magic("env var=val2")
753 self.assertEqual(env, None)
754 self.assertEqual(env, None)
754 self.assertEqual(os.environ['var'], 'val2')
755 self.assertEqual(os.environ['var'], 'val2')
755
756
756 def test_env_get_set_complex(self):
757 def test_env_get_set_complex(self):
757 env = _ip.magic("env var 'val1 '' 'val2")
758 env = _ip.magic("env var 'val1 '' 'val2")
758 self.assertEqual(env, None)
759 self.assertEqual(env, None)
759 self.assertEqual(os.environ['var'], "'val1 '' 'val2")
760 self.assertEqual(os.environ['var'], "'val1 '' 'val2")
760 self.assertEqual(_ip.magic("env var"), "'val1 '' 'val2")
761 self.assertEqual(_ip.magic("env var"), "'val1 '' 'val2")
761 env = _ip.magic('env var=val2 val3="val4')
762 env = _ip.magic('env var=val2 val3="val4')
762 self.assertEqual(env, None)
763 self.assertEqual(env, None)
763 self.assertEqual(os.environ['var'], 'val2 val3="val4')
764 self.assertEqual(os.environ['var'], 'val2 val3="val4')
764
765
765 def test_env_set_bad_input(self):
766 def test_env_set_bad_input(self):
766 self.assertRaises(UsageError, lambda: _ip.magic("set_env var"))
767 self.assertRaises(UsageError, lambda: _ip.magic("set_env var"))
767
768
768 def test_env_set_whitespace(self):
769 def test_env_set_whitespace(self):
769 self.assertRaises(UsageError, lambda: _ip.magic("env var A=B"))
770 self.assertRaises(UsageError, lambda: _ip.magic("env var A=B"))
770
771
771
772
772 class CellMagicTestCase(TestCase):
773 class CellMagicTestCase(TestCase):
773
774
774 def check_ident(self, magic):
775 def check_ident(self, magic):
775 # Manually called, we get the result
776 # Manually called, we get the result
776 out = _ip.run_cell_magic(magic, 'a', 'b')
777 out = _ip.run_cell_magic(magic, 'a', 'b')
777 nt.assert_equal(out, ('a','b'))
778 nt.assert_equal(out, ('a','b'))
778 # Via run_cell, it goes into the user's namespace via displayhook
779 # Via run_cell, it goes into the user's namespace via displayhook
779 _ip.run_cell('%%' + magic +' c\nd\n')
780 _ip.run_cell('%%' + magic +' c\nd\n')
780 nt.assert_equal(_ip.user_ns['_'], ('c','d\n'))
781 nt.assert_equal(_ip.user_ns['_'], ('c','d\n'))
781
782
782 def test_cell_magic_func_deco(self):
783 def test_cell_magic_func_deco(self):
783 "Cell magic using simple decorator"
784 "Cell magic using simple decorator"
784 @register_cell_magic
785 @register_cell_magic
785 def cellm(line, cell):
786 def cellm(line, cell):
786 return line, cell
787 return line, cell
787
788
788 self.check_ident('cellm')
789 self.check_ident('cellm')
789
790
790 def test_cell_magic_reg(self):
791 def test_cell_magic_reg(self):
791 "Cell magic manually registered"
792 "Cell magic manually registered"
792 def cellm(line, cell):
793 def cellm(line, cell):
793 return line, cell
794 return line, cell
794
795
795 _ip.register_magic_function(cellm, 'cell', 'cellm2')
796 _ip.register_magic_function(cellm, 'cell', 'cellm2')
796 self.check_ident('cellm2')
797 self.check_ident('cellm2')
797
798
798 def test_cell_magic_class(self):
799 def test_cell_magic_class(self):
799 "Cell magics declared via a class"
800 "Cell magics declared via a class"
800 @magics_class
801 @magics_class
801 class MyMagics(Magics):
802 class MyMagics(Magics):
802
803
803 @cell_magic
804 @cell_magic
804 def cellm3(self, line, cell):
805 def cellm3(self, line, cell):
805 return line, cell
806 return line, cell
806
807
807 _ip.register_magics(MyMagics)
808 _ip.register_magics(MyMagics)
808 self.check_ident('cellm3')
809 self.check_ident('cellm3')
809
810
810 def test_cell_magic_class2(self):
811 def test_cell_magic_class2(self):
811 "Cell magics declared via a class, #2"
812 "Cell magics declared via a class, #2"
812 @magics_class
813 @magics_class
813 class MyMagics2(Magics):
814 class MyMagics2(Magics):
814
815
815 @cell_magic('cellm4')
816 @cell_magic('cellm4')
816 def cellm33(self, line, cell):
817 def cellm33(self, line, cell):
817 return line, cell
818 return line, cell
818
819
819 _ip.register_magics(MyMagics2)
820 _ip.register_magics(MyMagics2)
820 self.check_ident('cellm4')
821 self.check_ident('cellm4')
821 # Check that nothing is registered as 'cellm33'
822 # Check that nothing is registered as 'cellm33'
822 c33 = _ip.find_cell_magic('cellm33')
823 c33 = _ip.find_cell_magic('cellm33')
823 nt.assert_equal(c33, None)
824 nt.assert_equal(c33, None)
824
825
825 def test_file():
826 def test_file():
826 """Basic %%writefile"""
827 """Basic %%writefile"""
827 ip = get_ipython()
828 ip = get_ipython()
828 with TemporaryDirectory() as td:
829 with TemporaryDirectory() as td:
829 fname = os.path.join(td, 'file1')
830 fname = os.path.join(td, 'file1')
830 ip.run_cell_magic("writefile", fname, u'\n'.join([
831 ip.run_cell_magic("writefile", fname, u'\n'.join([
831 'line1',
832 'line1',
832 'line2',
833 'line2',
833 ]))
834 ]))
834 with open(fname) as f:
835 s = Path(fname).read_text()
835 s = f.read()
836 nt.assert_in('line1\n', s)
836 nt.assert_in('line1\n', s)
837 nt.assert_in('line2', s)
837 nt.assert_in('line2', s)
838
838
839 @dec.skip_win32
839 @dec.skip_win32
840 def test_file_single_quote():
840 def test_file_single_quote():
841 """Basic %%writefile with embedded single quotes"""
841 """Basic %%writefile with embedded single quotes"""
842 ip = get_ipython()
842 ip = get_ipython()
843 with TemporaryDirectory() as td:
843 with TemporaryDirectory() as td:
844 fname = os.path.join(td, '\'file1\'')
844 fname = os.path.join(td, '\'file1\'')
845 ip.run_cell_magic("writefile", fname, u'\n'.join([
845 ip.run_cell_magic("writefile", fname, u'\n'.join([
846 'line1',
846 'line1',
847 'line2',
847 'line2',
848 ]))
848 ]))
849 with open(fname) as f:
849 s = Path(fname).read_text()
850 s = f.read()
851 nt.assert_in('line1\n', s)
850 nt.assert_in('line1\n', s)
852 nt.assert_in('line2', s)
851 nt.assert_in('line2', s)
853
852
854 @dec.skip_win32
853 @dec.skip_win32
855 def test_file_double_quote():
854 def test_file_double_quote():
856 """Basic %%writefile with embedded double quotes"""
855 """Basic %%writefile with embedded double quotes"""
857 ip = get_ipython()
856 ip = get_ipython()
858 with TemporaryDirectory() as td:
857 with TemporaryDirectory() as td:
859 fname = os.path.join(td, '"file1"')
858 fname = os.path.join(td, '"file1"')
860 ip.run_cell_magic("writefile", fname, u'\n'.join([
859 ip.run_cell_magic("writefile", fname, u'\n'.join([
861 'line1',
860 'line1',
862 'line2',
861 'line2',
863 ]))
862 ]))
864 with open(fname) as f:
863 s = Path(fname).read_text()
865 s = f.read()
866 nt.assert_in('line1\n', s)
864 nt.assert_in('line1\n', s)
867 nt.assert_in('line2', s)
865 nt.assert_in('line2', s)
868
866
869 def test_file_var_expand():
867 def test_file_var_expand():
870 """%%writefile $filename"""
868 """%%writefile $filename"""
871 ip = get_ipython()
869 ip = get_ipython()
872 with TemporaryDirectory() as td:
870 with TemporaryDirectory() as td:
873 fname = os.path.join(td, 'file1')
871 fname = os.path.join(td, 'file1')
874 ip.user_ns['filename'] = fname
872 ip.user_ns['filename'] = fname
875 ip.run_cell_magic("writefile", '$filename', u'\n'.join([
873 ip.run_cell_magic("writefile", '$filename', u'\n'.join([
876 'line1',
874 'line1',
877 'line2',
875 'line2',
878 ]))
876 ]))
879 with open(fname) as f:
877 s = Path(fname).read_text()
880 s = f.read()
881 nt.assert_in('line1\n', s)
878 nt.assert_in('line1\n', s)
882 nt.assert_in('line2', s)
879 nt.assert_in('line2', s)
883
880
884 def test_file_unicode():
881 def test_file_unicode():
885 """%%writefile with unicode cell"""
882 """%%writefile with unicode cell"""
886 ip = get_ipython()
883 ip = get_ipython()
887 with TemporaryDirectory() as td:
884 with TemporaryDirectory() as td:
888 fname = os.path.join(td, 'file1')
885 fname = os.path.join(td, 'file1')
889 ip.run_cell_magic("writefile", fname, u'\n'.join([
886 ip.run_cell_magic("writefile", fname, u'\n'.join([
890 u'linΓ©1',
887 u'linΓ©1',
891 u'linΓ©2',
888 u'linΓ©2',
892 ]))
889 ]))
893 with io.open(fname, encoding='utf-8') as f:
890 with io.open(fname, encoding='utf-8') as f:
894 s = f.read()
891 s = f.read()
895 nt.assert_in(u'linΓ©1\n', s)
892 nt.assert_in(u'linΓ©1\n', s)
896 nt.assert_in(u'linΓ©2', s)
893 nt.assert_in(u'linΓ©2', s)
897
894
898 def test_file_amend():
895 def test_file_amend():
899 """%%writefile -a amends files"""
896 """%%writefile -a amends files"""
900 ip = get_ipython()
897 ip = get_ipython()
901 with TemporaryDirectory() as td:
898 with TemporaryDirectory() as td:
902 fname = os.path.join(td, 'file2')
899 fname = os.path.join(td, 'file2')
903 ip.run_cell_magic("writefile", fname, u'\n'.join([
900 ip.run_cell_magic("writefile", fname, u'\n'.join([
904 'line1',
901 'line1',
905 'line2',
902 'line2',
906 ]))
903 ]))
907 ip.run_cell_magic("writefile", "-a %s" % fname, u'\n'.join([
904 ip.run_cell_magic("writefile", "-a %s" % fname, u'\n'.join([
908 'line3',
905 'line3',
909 'line4',
906 'line4',
910 ]))
907 ]))
911 with open(fname) as f:
908 s = Path(fname).read_text()
912 s = f.read()
913 nt.assert_in('line1\n', s)
909 nt.assert_in('line1\n', s)
914 nt.assert_in('line3\n', s)
910 nt.assert_in('line3\n', s)
915
911
916 def test_file_spaces():
912 def test_file_spaces():
917 """%%file with spaces in filename"""
913 """%%file with spaces in filename"""
918 ip = get_ipython()
914 ip = get_ipython()
919 with TemporaryWorkingDirectory() as td:
915 with TemporaryWorkingDirectory() as td:
920 fname = "file name"
916 fname = "file name"
921 ip.run_cell_magic("file", '"%s"'%fname, u'\n'.join([
917 ip.run_cell_magic("file", '"%s"'%fname, u'\n'.join([
922 'line1',
918 'line1',
923 'line2',
919 'line2',
924 ]))
920 ]))
925 with open(fname) as f:
921 s = Path(fname).read_text()
926 s = f.read()
927 nt.assert_in('line1\n', s)
922 nt.assert_in('line1\n', s)
928 nt.assert_in('line2', s)
923 nt.assert_in('line2', s)
929
924
930 def test_script_config():
925 def test_script_config():
931 ip = get_ipython()
926 ip = get_ipython()
932 ip.config.ScriptMagics.script_magics = ['whoda']
927 ip.config.ScriptMagics.script_magics = ['whoda']
933 sm = script.ScriptMagics(shell=ip)
928 sm = script.ScriptMagics(shell=ip)
934 nt.assert_in('whoda', sm.magics['cell'])
929 nt.assert_in('whoda', sm.magics['cell'])
935
930
936 @dec.skip_win32
931 @dec.skip_win32
937 def test_script_out():
932 def test_script_out():
938 ip = get_ipython()
933 ip = get_ipython()
939 ip.run_cell_magic("script", "--out output sh", "echo 'hi'")
934 ip.run_cell_magic("script", "--out output sh", "echo 'hi'")
940 nt.assert_equal(ip.user_ns['output'], 'hi\n')
935 nt.assert_equal(ip.user_ns['output'], 'hi\n')
941
936
942 @dec.skip_win32
937 @dec.skip_win32
943 def test_script_err():
938 def test_script_err():
944 ip = get_ipython()
939 ip = get_ipython()
945 ip.run_cell_magic("script", "--err error sh", "echo 'hello' >&2")
940 ip.run_cell_magic("script", "--err error sh", "echo 'hello' >&2")
946 nt.assert_equal(ip.user_ns['error'], 'hello\n')
941 nt.assert_equal(ip.user_ns['error'], 'hello\n')
947
942
948 @dec.skip_win32
943 @dec.skip_win32
949 def test_script_out_err():
944 def test_script_out_err():
950 ip = get_ipython()
945 ip = get_ipython()
951 ip.run_cell_magic("script", "--out output --err error sh", "echo 'hi'\necho 'hello' >&2")
946 ip.run_cell_magic("script", "--out output --err error sh", "echo 'hi'\necho 'hello' >&2")
952 nt.assert_equal(ip.user_ns['output'], 'hi\n')
947 nt.assert_equal(ip.user_ns['output'], 'hi\n')
953 nt.assert_equal(ip.user_ns['error'], 'hello\n')
948 nt.assert_equal(ip.user_ns['error'], 'hello\n')
954
949
955 @dec.skip_win32
950 @dec.skip_win32
956 def test_script_bg_out():
951 def test_script_bg_out():
957 ip = get_ipython()
952 ip = get_ipython()
958 ip.run_cell_magic("script", "--bg --out output sh", "echo 'hi'")
953 ip.run_cell_magic("script", "--bg --out output sh", "echo 'hi'")
959
954
960 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
955 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
961 ip.user_ns['output'].close()
956 ip.user_ns['output'].close()
962
957
963 @dec.skip_win32
958 @dec.skip_win32
964 def test_script_bg_err():
959 def test_script_bg_err():
965 ip = get_ipython()
960 ip = get_ipython()
966 ip.run_cell_magic("script", "--bg --err error sh", "echo 'hello' >&2")
961 ip.run_cell_magic("script", "--bg --err error sh", "echo 'hello' >&2")
967 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
962 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
968 ip.user_ns['error'].close()
963 ip.user_ns['error'].close()
969
964
970 @dec.skip_win32
965 @dec.skip_win32
971 def test_script_bg_out_err():
966 def test_script_bg_out_err():
972 ip = get_ipython()
967 ip = get_ipython()
973 ip.run_cell_magic("script", "--bg --out output --err error sh", "echo 'hi'\necho 'hello' >&2")
968 ip.run_cell_magic("script", "--bg --out output --err error sh", "echo 'hi'\necho 'hello' >&2")
974 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
969 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
975 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
970 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
976 ip.user_ns['output'].close()
971 ip.user_ns['output'].close()
977 ip.user_ns['error'].close()
972 ip.user_ns['error'].close()
978
973
979 def test_script_defaults():
974 def test_script_defaults():
980 ip = get_ipython()
975 ip = get_ipython()
981 for cmd in ['sh', 'bash', 'perl', 'ruby']:
976 for cmd in ['sh', 'bash', 'perl', 'ruby']:
982 try:
977 try:
983 find_cmd(cmd)
978 find_cmd(cmd)
984 except Exception:
979 except Exception:
985 pass
980 pass
986 else:
981 else:
987 nt.assert_in(cmd, ip.magics_manager.magics['cell'])
982 nt.assert_in(cmd, ip.magics_manager.magics['cell'])
988
983
989
984
990 @magics_class
985 @magics_class
991 class FooFoo(Magics):
986 class FooFoo(Magics):
992 """class with both %foo and %%foo magics"""
987 """class with both %foo and %%foo magics"""
993 @line_magic('foo')
988 @line_magic('foo')
994 def line_foo(self, line):
989 def line_foo(self, line):
995 "I am line foo"
990 "I am line foo"
996 pass
991 pass
997
992
998 @cell_magic("foo")
993 @cell_magic("foo")
999 def cell_foo(self, line, cell):
994 def cell_foo(self, line, cell):
1000 "I am cell foo, not line foo"
995 "I am cell foo, not line foo"
1001 pass
996 pass
1002
997
1003 def test_line_cell_info():
998 def test_line_cell_info():
1004 """%%foo and %foo magics are distinguishable to inspect"""
999 """%%foo and %foo magics are distinguishable to inspect"""
1005 ip = get_ipython()
1000 ip = get_ipython()
1006 ip.magics_manager.register(FooFoo)
1001 ip.magics_manager.register(FooFoo)
1007 oinfo = ip.object_inspect('foo')
1002 oinfo = ip.object_inspect('foo')
1008 nt.assert_true(oinfo['found'])
1003 nt.assert_true(oinfo['found'])
1009 nt.assert_true(oinfo['ismagic'])
1004 nt.assert_true(oinfo['ismagic'])
1010
1005
1011 oinfo = ip.object_inspect('%%foo')
1006 oinfo = ip.object_inspect('%%foo')
1012 nt.assert_true(oinfo['found'])
1007 nt.assert_true(oinfo['found'])
1013 nt.assert_true(oinfo['ismagic'])
1008 nt.assert_true(oinfo['ismagic'])
1014 nt.assert_equal(oinfo['docstring'], FooFoo.cell_foo.__doc__)
1009 nt.assert_equal(oinfo['docstring'], FooFoo.cell_foo.__doc__)
1015
1010
1016 oinfo = ip.object_inspect('%foo')
1011 oinfo = ip.object_inspect('%foo')
1017 nt.assert_true(oinfo['found'])
1012 nt.assert_true(oinfo['found'])
1018 nt.assert_true(oinfo['ismagic'])
1013 nt.assert_true(oinfo['ismagic'])
1019 nt.assert_equal(oinfo['docstring'], FooFoo.line_foo.__doc__)
1014 nt.assert_equal(oinfo['docstring'], FooFoo.line_foo.__doc__)
1020
1015
1021 def test_multiple_magics():
1016 def test_multiple_magics():
1022 ip = get_ipython()
1017 ip = get_ipython()
1023 foo1 = FooFoo(ip)
1018 foo1 = FooFoo(ip)
1024 foo2 = FooFoo(ip)
1019 foo2 = FooFoo(ip)
1025 mm = ip.magics_manager
1020 mm = ip.magics_manager
1026 mm.register(foo1)
1021 mm.register(foo1)
1027 nt.assert_true(mm.magics['line']['foo'].__self__ is foo1)
1022 nt.assert_true(mm.magics['line']['foo'].__self__ is foo1)
1028 mm.register(foo2)
1023 mm.register(foo2)
1029 nt.assert_true(mm.magics['line']['foo'].__self__ is foo2)
1024 nt.assert_true(mm.magics['line']['foo'].__self__ is foo2)
1030
1025
1031 def test_alias_magic():
1026 def test_alias_magic():
1032 """Test %alias_magic."""
1027 """Test %alias_magic."""
1033 ip = get_ipython()
1028 ip = get_ipython()
1034 mm = ip.magics_manager
1029 mm = ip.magics_manager
1035
1030
1036 # Basic operation: both cell and line magics are created, if possible.
1031 # Basic operation: both cell and line magics are created, if possible.
1037 ip.run_line_magic('alias_magic', 'timeit_alias timeit')
1032 ip.run_line_magic('alias_magic', 'timeit_alias timeit')
1038 nt.assert_in('timeit_alias', mm.magics['line'])
1033 nt.assert_in('timeit_alias', mm.magics['line'])
1039 nt.assert_in('timeit_alias', mm.magics['cell'])
1034 nt.assert_in('timeit_alias', mm.magics['cell'])
1040
1035
1041 # --cell is specified, line magic not created.
1036 # --cell is specified, line magic not created.
1042 ip.run_line_magic('alias_magic', '--cell timeit_cell_alias timeit')
1037 ip.run_line_magic('alias_magic', '--cell timeit_cell_alias timeit')
1043 nt.assert_not_in('timeit_cell_alias', mm.magics['line'])
1038 nt.assert_not_in('timeit_cell_alias', mm.magics['line'])
1044 nt.assert_in('timeit_cell_alias', mm.magics['cell'])
1039 nt.assert_in('timeit_cell_alias', mm.magics['cell'])
1045
1040
1046 # Test that line alias is created successfully.
1041 # Test that line alias is created successfully.
1047 ip.run_line_magic('alias_magic', '--line env_alias env')
1042 ip.run_line_magic('alias_magic', '--line env_alias env')
1048 nt.assert_equal(ip.run_line_magic('env', ''),
1043 nt.assert_equal(ip.run_line_magic('env', ''),
1049 ip.run_line_magic('env_alias', ''))
1044 ip.run_line_magic('env_alias', ''))
1050
1045
1051 # Test that line alias with parameters passed in is created successfully.
1046 # Test that line alias with parameters passed in is created successfully.
1052 ip.run_line_magic('alias_magic', '--line history_alias history --params ' + shlex.quote('3'))
1047 ip.run_line_magic('alias_magic', '--line history_alias history --params ' + shlex.quote('3'))
1053 nt.assert_in('history_alias', mm.magics['line'])
1048 nt.assert_in('history_alias', mm.magics['line'])
1054
1049
1055
1050
1056 def test_save():
1051 def test_save():
1057 """Test %save."""
1052 """Test %save."""
1058 ip = get_ipython()
1053 ip = get_ipython()
1059 ip.history_manager.reset() # Clear any existing history.
1054 ip.history_manager.reset() # Clear any existing history.
1060 cmds = [u"a=1", u"def b():\n return a**2", u"print(a, b())"]
1055 cmds = [u"a=1", u"def b():\n return a**2", u"print(a, b())"]
1061 for i, cmd in enumerate(cmds, start=1):
1056 for i, cmd in enumerate(cmds, start=1):
1062 ip.history_manager.store_inputs(i, cmd)
1057 ip.history_manager.store_inputs(i, cmd)
1063 with TemporaryDirectory() as tmpdir:
1058 with TemporaryDirectory() as tmpdir:
1064 file = os.path.join(tmpdir, "testsave.py")
1059 file = os.path.join(tmpdir, "testsave.py")
1065 ip.run_line_magic("save", "%s 1-10" % file)
1060 ip.run_line_magic("save", "%s 1-10" % file)
1066 with open(file) as f:
1061 content = Path(file).read_text()
1067 content = f.read()
1062 nt.assert_equal(content.count(cmds[0]), 1)
1068 nt.assert_equal(content.count(cmds[0]), 1)
1063 nt.assert_in('coding: utf-8', content)
1069 nt.assert_in('coding: utf-8', content)
1070 ip.run_line_magic("save", "-a %s 1-10" % file)
1064 ip.run_line_magic("save", "-a %s 1-10" % file)
1071 with open(file) as f:
1065 content = Path(file).read_text()
1072 content = f.read()
1066 nt.assert_equal(content.count(cmds[0]), 2)
1073 nt.assert_equal(content.count(cmds[0]), 2)
1067 nt.assert_in('coding: utf-8', content)
1074 nt.assert_in('coding: utf-8', content)
1075
1068
1076
1069
1077 def test_store():
1070 def test_store():
1078 """Test %store."""
1071 """Test %store."""
1079 ip = get_ipython()
1072 ip = get_ipython()
1080 ip.run_line_magic('load_ext', 'storemagic')
1073 ip.run_line_magic('load_ext', 'storemagic')
1081
1074
1082 # make sure the storage is empty
1075 # make sure the storage is empty
1083 ip.run_line_magic('store', '-z')
1076 ip.run_line_magic('store', '-z')
1084 ip.user_ns['var'] = 42
1077 ip.user_ns['var'] = 42
1085 ip.run_line_magic('store', 'var')
1078 ip.run_line_magic('store', 'var')
1086 ip.user_ns['var'] = 39
1079 ip.user_ns['var'] = 39
1087 ip.run_line_magic('store', '-r')
1080 ip.run_line_magic('store', '-r')
1088 nt.assert_equal(ip.user_ns['var'], 42)
1081 nt.assert_equal(ip.user_ns['var'], 42)
1089
1082
1090 ip.run_line_magic('store', '-d var')
1083 ip.run_line_magic('store', '-d var')
1091 ip.user_ns['var'] = 39
1084 ip.user_ns['var'] = 39
1092 ip.run_line_magic('store' , '-r')
1085 ip.run_line_magic('store' , '-r')
1093 nt.assert_equal(ip.user_ns['var'], 39)
1086 nt.assert_equal(ip.user_ns['var'], 39)
1094
1087
1095
1088
1096 def _run_edit_test(arg_s, exp_filename=None,
1089 def _run_edit_test(arg_s, exp_filename=None,
1097 exp_lineno=-1,
1090 exp_lineno=-1,
1098 exp_contents=None,
1091 exp_contents=None,
1099 exp_is_temp=None):
1092 exp_is_temp=None):
1100 ip = get_ipython()
1093 ip = get_ipython()
1101 M = code.CodeMagics(ip)
1094 M = code.CodeMagics(ip)
1102 last_call = ['','']
1095 last_call = ['','']
1103 opts,args = M.parse_options(arg_s,'prxn:')
1096 opts,args = M.parse_options(arg_s,'prxn:')
1104 filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call)
1097 filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call)
1105
1098
1106 if exp_filename is not None:
1099 if exp_filename is not None:
1107 nt.assert_equal(exp_filename, filename)
1100 nt.assert_equal(exp_filename, filename)
1108 if exp_contents is not None:
1101 if exp_contents is not None:
1109 with io.open(filename, 'r', encoding='utf-8') as f:
1102 with io.open(filename, 'r', encoding='utf-8') as f:
1110 contents = f.read()
1103 contents = f.read()
1111 nt.assert_equal(exp_contents, contents)
1104 nt.assert_equal(exp_contents, contents)
1112 if exp_lineno != -1:
1105 if exp_lineno != -1:
1113 nt.assert_equal(exp_lineno, lineno)
1106 nt.assert_equal(exp_lineno, lineno)
1114 if exp_is_temp is not None:
1107 if exp_is_temp is not None:
1115 nt.assert_equal(exp_is_temp, is_temp)
1108 nt.assert_equal(exp_is_temp, is_temp)
1116
1109
1117
1110
1118 def test_edit_interactive():
1111 def test_edit_interactive():
1119 """%edit on interactively defined objects"""
1112 """%edit on interactively defined objects"""
1120 ip = get_ipython()
1113 ip = get_ipython()
1121 n = ip.execution_count
1114 n = ip.execution_count
1122 ip.run_cell(u"def foo(): return 1", store_history=True)
1115 ip.run_cell(u"def foo(): return 1", store_history=True)
1123
1116
1124 try:
1117 try:
1125 _run_edit_test("foo")
1118 _run_edit_test("foo")
1126 except code.InteractivelyDefined as e:
1119 except code.InteractivelyDefined as e:
1127 nt.assert_equal(e.index, n)
1120 nt.assert_equal(e.index, n)
1128 else:
1121 else:
1129 raise AssertionError("Should have raised InteractivelyDefined")
1122 raise AssertionError("Should have raised InteractivelyDefined")
1130
1123
1131
1124
1132 def test_edit_cell():
1125 def test_edit_cell():
1133 """%edit [cell id]"""
1126 """%edit [cell id]"""
1134 ip = get_ipython()
1127 ip = get_ipython()
1135
1128
1136 ip.run_cell(u"def foo(): return 1", store_history=True)
1129 ip.run_cell(u"def foo(): return 1", store_history=True)
1137
1130
1138 # test
1131 # test
1139 _run_edit_test("1", exp_contents=ip.user_ns['In'][1], exp_is_temp=True)
1132 _run_edit_test("1", exp_contents=ip.user_ns['In'][1], exp_is_temp=True)
1140
1133
1141 def test_edit_fname():
1134 def test_edit_fname():
1142 """%edit file"""
1135 """%edit file"""
1143 # test
1136 # test
1144 _run_edit_test("test file.py", exp_filename="test file.py")
1137 _run_edit_test("test file.py", exp_filename="test file.py")
1145
1138
1146 def test_bookmark():
1139 def test_bookmark():
1147 ip = get_ipython()
1140 ip = get_ipython()
1148 ip.run_line_magic('bookmark', 'bmname')
1141 ip.run_line_magic('bookmark', 'bmname')
1149 with tt.AssertPrints('bmname'):
1142 with tt.AssertPrints('bmname'):
1150 ip.run_line_magic('bookmark', '-l')
1143 ip.run_line_magic('bookmark', '-l')
1151 ip.run_line_magic('bookmark', '-d bmname')
1144 ip.run_line_magic('bookmark', '-d bmname')
1152
1145
1153 def test_ls_magic():
1146 def test_ls_magic():
1154 ip = get_ipython()
1147 ip = get_ipython()
1155 json_formatter = ip.display_formatter.formatters['application/json']
1148 json_formatter = ip.display_formatter.formatters['application/json']
1156 json_formatter.enabled = True
1149 json_formatter.enabled = True
1157 lsmagic = ip.magic('lsmagic')
1150 lsmagic = ip.magic('lsmagic')
1158 with warnings.catch_warnings(record=True) as w:
1151 with warnings.catch_warnings(record=True) as w:
1159 j = json_formatter(lsmagic)
1152 j = json_formatter(lsmagic)
1160 nt.assert_equal(sorted(j), ['cell', 'line'])
1153 nt.assert_equal(sorted(j), ['cell', 'line'])
1161 nt.assert_equal(w, []) # no warnings
1154 nt.assert_equal(w, []) # no warnings
1162
1155
1163 def test_strip_initial_indent():
1156 def test_strip_initial_indent():
1164 def sii(s):
1157 def sii(s):
1165 lines = s.splitlines()
1158 lines = s.splitlines()
1166 return '\n'.join(code.strip_initial_indent(lines))
1159 return '\n'.join(code.strip_initial_indent(lines))
1167
1160
1168 nt.assert_equal(sii(" a = 1\nb = 2"), "a = 1\nb = 2")
1161 nt.assert_equal(sii(" a = 1\nb = 2"), "a = 1\nb = 2")
1169 nt.assert_equal(sii(" a\n b\nc"), "a\n b\nc")
1162 nt.assert_equal(sii(" a\n b\nc"), "a\n b\nc")
1170 nt.assert_equal(sii("a\n b"), "a\n b")
1163 nt.assert_equal(sii("a\n b"), "a\n b")
1171
1164
1172 def test_logging_magic_quiet_from_arg():
1165 def test_logging_magic_quiet_from_arg():
1173 _ip.config.LoggingMagics.quiet = False
1166 _ip.config.LoggingMagics.quiet = False
1174 lm = logging.LoggingMagics(shell=_ip)
1167 lm = logging.LoggingMagics(shell=_ip)
1175 with TemporaryDirectory() as td:
1168 with TemporaryDirectory() as td:
1176 try:
1169 try:
1177 with tt.AssertNotPrints(re.compile("Activating.*")):
1170 with tt.AssertNotPrints(re.compile("Activating.*")):
1178 lm.logstart('-q {}'.format(
1171 lm.logstart('-q {}'.format(
1179 os.path.join(td, "quiet_from_arg.log")))
1172 os.path.join(td, "quiet_from_arg.log")))
1180 finally:
1173 finally:
1181 _ip.logger.logstop()
1174 _ip.logger.logstop()
1182
1175
1183 def test_logging_magic_quiet_from_config():
1176 def test_logging_magic_quiet_from_config():
1184 _ip.config.LoggingMagics.quiet = True
1177 _ip.config.LoggingMagics.quiet = True
1185 lm = logging.LoggingMagics(shell=_ip)
1178 lm = logging.LoggingMagics(shell=_ip)
1186 with TemporaryDirectory() as td:
1179 with TemporaryDirectory() as td:
1187 try:
1180 try:
1188 with tt.AssertNotPrints(re.compile("Activating.*")):
1181 with tt.AssertNotPrints(re.compile("Activating.*")):
1189 lm.logstart(os.path.join(td, "quiet_from_config.log"))
1182 lm.logstart(os.path.join(td, "quiet_from_config.log"))
1190 finally:
1183 finally:
1191 _ip.logger.logstop()
1184 _ip.logger.logstop()
1192
1185
1193
1186
1194 def test_logging_magic_not_quiet():
1187 def test_logging_magic_not_quiet():
1195 _ip.config.LoggingMagics.quiet = False
1188 _ip.config.LoggingMagics.quiet = False
1196 lm = logging.LoggingMagics(shell=_ip)
1189 lm = logging.LoggingMagics(shell=_ip)
1197 with TemporaryDirectory() as td:
1190 with TemporaryDirectory() as td:
1198 try:
1191 try:
1199 with tt.AssertPrints(re.compile("Activating.*")):
1192 with tt.AssertPrints(re.compile("Activating.*")):
1200 lm.logstart(os.path.join(td, "not_quiet.log"))
1193 lm.logstart(os.path.join(td, "not_quiet.log"))
1201 finally:
1194 finally:
1202 _ip.logger.logstop()
1195 _ip.logger.logstop()
1203
1196
1204
1197
1205 def test_time_no_var_expand():
1198 def test_time_no_var_expand():
1206 _ip.user_ns['a'] = 5
1199 _ip.user_ns['a'] = 5
1207 _ip.user_ns['b'] = []
1200 _ip.user_ns['b'] = []
1208 _ip.magic('time b.append("{a}")')
1201 _ip.magic('time b.append("{a}")')
1209 assert _ip.user_ns['b'] == ['{a}']
1202 assert _ip.user_ns['b'] == ['{a}']
1210
1203
1211
1204
1212 # this is slow, put at the end for local testing.
1205 # this is slow, put at the end for local testing.
1213 def test_timeit_arguments():
1206 def test_timeit_arguments():
1214 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
1207 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
1215 if sys.version_info < (3,7):
1208 if sys.version_info < (3,7):
1216 _ip.magic("timeit -n1 -r1 ('#')")
1209 _ip.magic("timeit -n1 -r1 ('#')")
1217 else:
1210 else:
1218 # 3.7 optimize no-op statement like above out, and complain there is
1211 # 3.7 optimize no-op statement like above out, and complain there is
1219 # nothing in the for loop.
1212 # nothing in the for loop.
1220 _ip.magic("timeit -n1 -r1 a=('#')")
1213 _ip.magic("timeit -n1 -r1 a=('#')")
1221
1214
1222
1215
1223 TEST_MODULE = """
1216 TEST_MODULE = """
1224 print('Loaded my_tmp')
1217 print('Loaded my_tmp')
1225 if __name__ == "__main__":
1218 if __name__ == "__main__":
1226 print('I just ran a script')
1219 print('I just ran a script')
1227 """
1220 """
1228
1221
1229
1222
1230 def test_run_module_from_import_hook():
1223 def test_run_module_from_import_hook():
1231 "Test that a module can be loaded via an import hook"
1224 "Test that a module can be loaded via an import hook"
1232 with TemporaryDirectory() as tmpdir:
1225 with TemporaryDirectory() as tmpdir:
1233 fullpath = os.path.join(tmpdir, 'my_tmp.py')
1226 fullpath = os.path.join(tmpdir, 'my_tmp.py')
1234 with open(fullpath, 'w') as f:
1227 Path(fullpath).write_text(TEST_MODULE)
1235 f.write(TEST_MODULE)
1236
1228
1237 class MyTempImporter(object):
1229 class MyTempImporter(object):
1238 def __init__(self):
1230 def __init__(self):
1239 pass
1231 pass
1240
1232
1241 def find_module(self, fullname, path=None):
1233 def find_module(self, fullname, path=None):
1242 if 'my_tmp' in fullname:
1234 if 'my_tmp' in fullname:
1243 return self
1235 return self
1244 return None
1236 return None
1245
1237
1246 def load_module(self, name):
1238 def load_module(self, name):
1247 import imp
1239 import imp
1248 return imp.load_source('my_tmp', fullpath)
1240 return imp.load_source('my_tmp', fullpath)
1249
1241
1250 def get_code(self, fullname):
1242 def get_code(self, fullname):
1251 with open(fullpath, 'r') as f:
1243 return compile(Path(fullpath).read_text(), 'foo', 'exec')
1252 return compile(f.read(), 'foo', 'exec')
1253
1244
1254 def is_package(self, __):
1245 def is_package(self, __):
1255 return False
1246 return False
1256
1247
1257 sys.meta_path.insert(0, MyTempImporter())
1248 sys.meta_path.insert(0, MyTempImporter())
1258
1249
1259 with capture_output() as captured:
1250 with capture_output() as captured:
1260 _ip.magic("run -m my_tmp")
1251 _ip.magic("run -m my_tmp")
1261 _ip.run_cell("import my_tmp")
1252 _ip.run_cell("import my_tmp")
1262
1253
1263 output = "Loaded my_tmp\nI just ran a script\nLoaded my_tmp\n"
1254 output = "Loaded my_tmp\nI just ran a script\nLoaded my_tmp\n"
1264 nt.assert_equal(output, captured.stdout)
1255 nt.assert_equal(output, captured.stdout)
1265
1256
1266 sys.meta_path.pop(0)
1257 sys.meta_path.pop(0)
@@ -1,128 +1,127 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2
2
3 from os.path import join, dirname, abspath
3 from os.path import join, dirname, abspath
4 import inspect
4 import inspect
5
5 from pathlib import Path
6 from IPython.terminal.ipapp import TerminalIPythonApp
6 from IPython.terminal.ipapp import TerminalIPythonApp
7 from ipykernel.kernelapp import IPKernelApp
7 from ipykernel.kernelapp import IPKernelApp
8 from traitlets import Undefined
8 from traitlets import Undefined
9 from collections import defaultdict
9 from collections import defaultdict
10
10
11 here = abspath(dirname(__file__))
11 here = abspath(dirname(__file__))
12 options = join(here, 'source', 'config', 'options')
12 options = join(here, 'source', 'config', 'options')
13 generated = join(options, 'config-generated.txt')
13 generated = join(options, 'config-generated.txt')
14
14
15 import textwrap
15 import textwrap
16 indent = lambda text,n: textwrap.indent(text,n*' ')
16 indent = lambda text,n: textwrap.indent(text,n*' ')
17
17
18
18
19 def interesting_default_value(dv):
19 def interesting_default_value(dv):
20 if (dv is None) or (dv is Undefined):
20 if (dv is None) or (dv is Undefined):
21 return False
21 return False
22 if isinstance(dv, (str, list, tuple, dict, set)):
22 if isinstance(dv, (str, list, tuple, dict, set)):
23 return bool(dv)
23 return bool(dv)
24 return True
24 return True
25
25
26 def format_aliases(aliases):
26 def format_aliases(aliases):
27 fmted = []
27 fmted = []
28 for a in aliases:
28 for a in aliases:
29 dashes = '-' if len(a) == 1 else '--'
29 dashes = '-' if len(a) == 1 else '--'
30 fmted.append('``%s%s``' % (dashes, a))
30 fmted.append('``%s%s``' % (dashes, a))
31 return ', '.join(fmted)
31 return ', '.join(fmted)
32
32
33 def class_config_rst_doc(cls, trait_aliases):
33 def class_config_rst_doc(cls, trait_aliases):
34 """Generate rST documentation for this class' config options.
34 """Generate rST documentation for this class' config options.
35
35
36 Excludes traits defined on parent classes.
36 Excludes traits defined on parent classes.
37 """
37 """
38 lines = []
38 lines = []
39 classname = cls.__name__
39 classname = cls.__name__
40 for k, trait in sorted(cls.class_traits(config=True).items()):
40 for k, trait in sorted(cls.class_traits(config=True).items()):
41 ttype = trait.__class__.__name__
41 ttype = trait.__class__.__name__
42
42
43 fullname = classname + '.' + trait.name
43 fullname = classname + '.' + trait.name
44 lines += ['.. configtrait:: ' + fullname,
44 lines += ['.. configtrait:: ' + fullname,
45 ''
45 ''
46 ]
46 ]
47
47
48 help = trait.help.rstrip() or 'No description'
48 help = trait.help.rstrip() or 'No description'
49 lines.append(indent(inspect.cleandoc(help), 4) + '\n')
49 lines.append(indent(inspect.cleandoc(help), 4) + '\n')
50
50
51 # Choices or type
51 # Choices or type
52 if 'Enum' in ttype:
52 if 'Enum' in ttype:
53 # include Enum choices
53 # include Enum choices
54 lines.append(indent(
54 lines.append(indent(
55 ':options: ' + ', '.join('``%r``' % x for x in trait.values), 4))
55 ':options: ' + ', '.join('``%r``' % x for x in trait.values), 4))
56 else:
56 else:
57 lines.append(indent(':trait type: ' + ttype, 4))
57 lines.append(indent(':trait type: ' + ttype, 4))
58
58
59 # Default value
59 # Default value
60 # Ignore boring default values like None, [] or ''
60 # Ignore boring default values like None, [] or ''
61 if interesting_default_value(trait.default_value):
61 if interesting_default_value(trait.default_value):
62 try:
62 try:
63 dvr = trait.default_value_repr()
63 dvr = trait.default_value_repr()
64 except Exception:
64 except Exception:
65 dvr = None # ignore defaults we can't construct
65 dvr = None # ignore defaults we can't construct
66 if dvr is not None:
66 if dvr is not None:
67 if len(dvr) > 64:
67 if len(dvr) > 64:
68 dvr = dvr[:61] + '...'
68 dvr = dvr[:61] + '...'
69 # Double up backslashes, so they get to the rendered docs
69 # Double up backslashes, so they get to the rendered docs
70 dvr = dvr.replace('\\n', '\\\\n')
70 dvr = dvr.replace('\\n', '\\\\n')
71 lines.append(indent(':default: ``%s``' % dvr, 4))
71 lines.append(indent(':default: ``%s``' % dvr, 4))
72
72
73 # Command line aliases
73 # Command line aliases
74 if trait_aliases[fullname]:
74 if trait_aliases[fullname]:
75 fmt_aliases = format_aliases(trait_aliases[fullname])
75 fmt_aliases = format_aliases(trait_aliases[fullname])
76 lines.append(indent(':CLI option: ' + fmt_aliases, 4))
76 lines.append(indent(':CLI option: ' + fmt_aliases, 4))
77
77
78 # Blank line
78 # Blank line
79 lines.append('')
79 lines.append('')
80
80
81 return '\n'.join(lines)
81 return '\n'.join(lines)
82
82
83 def reverse_aliases(app):
83 def reverse_aliases(app):
84 """Produce a mapping of trait names to lists of command line aliases.
84 """Produce a mapping of trait names to lists of command line aliases.
85 """
85 """
86 res = defaultdict(list)
86 res = defaultdict(list)
87 for alias, trait in app.aliases.items():
87 for alias, trait in app.aliases.items():
88 res[trait].append(alias)
88 res[trait].append(alias)
89
89
90 # Flags also often act as aliases for a boolean trait.
90 # Flags also often act as aliases for a boolean trait.
91 # Treat flags which set one trait to True as aliases.
91 # Treat flags which set one trait to True as aliases.
92 for flag, (cfg, _) in app.flags.items():
92 for flag, (cfg, _) in app.flags.items():
93 if len(cfg) == 1:
93 if len(cfg) == 1:
94 classname = list(cfg)[0]
94 classname = list(cfg)[0]
95 cls_cfg = cfg[classname]
95 cls_cfg = cfg[classname]
96 if len(cls_cfg) == 1:
96 if len(cls_cfg) == 1:
97 traitname = list(cls_cfg)[0]
97 traitname = list(cls_cfg)[0]
98 if cls_cfg[traitname] is True:
98 if cls_cfg[traitname] is True:
99 res[classname+'.'+traitname].append(flag)
99 res[classname+'.'+traitname].append(flag)
100
100
101 return res
101 return res
102
102
103 def write_doc(name, title, app, preamble=None):
103 def write_doc(name, title, app, preamble=None):
104 trait_aliases = reverse_aliases(app)
104 trait_aliases = reverse_aliases(app)
105 filename = join(options, name+'.rst')
105 filename = join(options, name+'.rst')
106 with open(filename, 'w') as f:
106 with open(filename, 'w') as f:
107 f.write(title + '\n')
107 f.write(title + '\n')
108 f.write(('=' * len(title)) + '\n')
108 f.write(('=' * len(title)) + '\n')
109 f.write('\n')
109 f.write('\n')
110 if preamble is not None:
110 if preamble is not None:
111 f.write(preamble + '\n\n')
111 f.write(preamble + '\n\n')
112 #f.write(app.document_config_options())
112 #f.write(app.document_config_options())
113
113
114 for c in app._classes_inc_parents():
114 for c in app._classes_inc_parents():
115 f.write(class_config_rst_doc(c, trait_aliases))
115 f.write(class_config_rst_doc(c, trait_aliases))
116 f.write('\n')
116 f.write('\n')
117
117
118
118
119 if __name__ == '__main__':
119 if __name__ == '__main__':
120 # Touch this file for the make target
120 # Touch this file for the make target
121 with open(generated, 'w'):
121 Path(generated).write_text('')
122 pass
123
122
124 write_doc('terminal', 'Terminal IPython options', TerminalIPythonApp())
123 write_doc('terminal', 'Terminal IPython options', TerminalIPythonApp())
125 write_doc('kernel', 'IPython kernel options', IPKernelApp(),
124 write_doc('kernel', 'IPython kernel options', IPKernelApp(),
126 preamble=("These options can be used in :file:`ipython_kernel_config.py`. "
125 preamble=("These options can be used in :file:`ipython_kernel_config.py`. "
127 "The kernel also respects any options in `ipython_config.py`"),
126 "The kernel also respects any options in `ipython_config.py`"),
128 )
127 )
@@ -1,68 +1,67 b''
1 import os
1 import os
2
2 from pathlib import Path
3 from IPython.core.alias import Alias
3 from IPython.core.alias import Alias
4 from IPython.core.interactiveshell import InteractiveShell
4 from IPython.core.interactiveshell import InteractiveShell
5 from IPython.core.magic import MagicAlias
5 from IPython.core.magic import MagicAlias
6 from IPython.utils.text import dedent, indent
6 from IPython.utils.text import dedent, indent
7
7
8 shell = InteractiveShell.instance()
8 shell = InteractiveShell.instance()
9 magics = shell.magics_manager.magics
9 magics = shell.magics_manager.magics
10
10
11 def _strip_underline(line):
11 def _strip_underline(line):
12 chars = set(line.strip())
12 chars = set(line.strip())
13 if len(chars) == 1 and ('-' in chars or '=' in chars):
13 if len(chars) == 1 and ('-' in chars or '=' in chars):
14 return ""
14 return ""
15 else:
15 else:
16 return line
16 return line
17
17
18 def format_docstring(func):
18 def format_docstring(func):
19 docstring = (func.__doc__ or "Undocumented").rstrip()
19 docstring = (func.__doc__ or "Undocumented").rstrip()
20 docstring = indent(dedent(docstring))
20 docstring = indent(dedent(docstring))
21 # Sphinx complains if indented bits have rst headings in, so strip out
21 # Sphinx complains if indented bits have rst headings in, so strip out
22 # any underlines in the docstring.
22 # any underlines in the docstring.
23 lines = [_strip_underline(l) for l in docstring.splitlines()]
23 lines = [_strip_underline(l) for l in docstring.splitlines()]
24 return "\n".join(lines)
24 return "\n".join(lines)
25
25
26 output = [
26 output = [
27 "Line magics",
27 "Line magics",
28 "===========",
28 "===========",
29 "",
29 "",
30 ]
30 ]
31
31
32 # Case insensitive sort by name
32 # Case insensitive sort by name
33 def sortkey(s): return s[0].lower()
33 def sortkey(s): return s[0].lower()
34
34
35 for name, func in sorted(magics['line'].items(), key=sortkey):
35 for name, func in sorted(magics['line'].items(), key=sortkey):
36 if isinstance(func, Alias) or isinstance(func, MagicAlias):
36 if isinstance(func, Alias) or isinstance(func, MagicAlias):
37 # Aliases are magics, but shouldn't be documented here
37 # Aliases are magics, but shouldn't be documented here
38 # Also skip aliases to other magics
38 # Also skip aliases to other magics
39 continue
39 continue
40 output.extend([".. magic:: {}".format(name),
40 output.extend([".. magic:: {}".format(name),
41 "",
41 "",
42 format_docstring(func),
42 format_docstring(func),
43 ""])
43 ""])
44
44
45 output.extend([
45 output.extend([
46 "Cell magics",
46 "Cell magics",
47 "===========",
47 "===========",
48 "",
48 "",
49 ])
49 ])
50
50
51 for name, func in sorted(magics['cell'].items(), key=sortkey):
51 for name, func in sorted(magics['cell'].items(), key=sortkey):
52 if name == "!":
52 if name == "!":
53 # Special case - don't encourage people to use %%!
53 # Special case - don't encourage people to use %%!
54 continue
54 continue
55 if func == magics['line'].get(name, 'QQQP'):
55 if func == magics['line'].get(name, 'QQQP'):
56 # Don't redocument line magics that double as cell magics
56 # Don't redocument line magics that double as cell magics
57 continue
57 continue
58 if isinstance(func, MagicAlias):
58 if isinstance(func, MagicAlias):
59 continue
59 continue
60 output.extend([".. cellmagic:: {}".format(name),
60 output.extend([".. cellmagic:: {}".format(name),
61 "",
61 "",
62 format_docstring(func),
62 format_docstring(func),
63 ""])
63 ""])
64
64
65 here = os.path.dirname(__file__)
65 here = os.path.dirname(__file__)
66 dest = os.path.join(here, 'source', 'interactive', 'magics-generated.txt')
66 dest = Path(os.path.join(here, 'source', 'interactive', 'magics-generated.txt'))
67 with open(dest, "w") as f:
67 dest.write_text("\n".join(output))
68 f.write("\n".join(output))
General Comments 0
You need to be logged in to leave comments. Login now