##// END OF EJS Templates
more fixes
M Bussonnier -
Show More
@@ -1,1556 +1,1556
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tests for various magic functions."""
2 """Tests for various magic functions."""
3
3
4 import gc
4 import gc
5 import io
5 import io
6 import os
6 import os
7 import re
7 import re
8 import shlex
8 import shlex
9 import sys
9 import sys
10 import warnings
10 import warnings
11 from importlib import invalidate_caches
11 from importlib import invalidate_caches
12 from io import StringIO
12 from io import StringIO
13 from pathlib import Path
13 from pathlib import Path
14 from textwrap import dedent
14 from textwrap import dedent
15 from unittest import TestCase, mock
15 from unittest import TestCase, mock
16
16
17 import pytest
17 import pytest
18
18
19 from IPython import get_ipython
19 from IPython import get_ipython
20 from IPython.core import magic
20 from IPython.core import magic
21 from IPython.core.error import UsageError
21 from IPython.core.error import UsageError
22 from IPython.core.magic import (
22 from IPython.core.magic import (
23 Magics,
23 Magics,
24 cell_magic,
24 cell_magic,
25 line_magic,
25 line_magic,
26 magics_class,
26 magics_class,
27 register_cell_magic,
27 register_cell_magic,
28 register_line_magic,
28 register_line_magic,
29 )
29 )
30 from IPython.core.magics import code, execution, logging, osm, script
30 from IPython.core.magics import code, execution, logging, osm, script
31 from IPython.testing import decorators as dec
31 from IPython.testing import decorators as dec
32 from IPython.testing import tools as tt
32 from IPython.testing import tools as tt
33 from IPython.utils.io import capture_output
33 from IPython.utils.io import capture_output
34 from IPython.utils.process import find_cmd
34 from IPython.utils.process import find_cmd
35 from IPython.utils.tempdir import TemporaryDirectory, TemporaryWorkingDirectory
35 from IPython.utils.tempdir import TemporaryDirectory, TemporaryWorkingDirectory
36 from IPython.utils.syspathcontext import prepended_to_syspath
36 from IPython.utils.syspathcontext import prepended_to_syspath
37
37
38 # import needed by doctest
38 # import needed by doctest
39 from .test_debugger import PdbTestInput # noqa: F401
39 from .test_debugger import PdbTestInput # noqa: F401
40
40
41 _ip = get_ipython()
41
42
42 @magic.magics_class
43 @magic.magics_class
43 class DummyMagics(magic.Magics): pass
44 class DummyMagics(magic.Magics):
45 pass
44
46
45 def test_extract_code_ranges():
47 def test_extract_code_ranges():
46 instr = "1 3 5-6 7-9 10:15 17: :10 10- -13 :"
48 instr = "1 3 5-6 7-9 10:15 17: :10 10- -13 :"
47 expected = [
49 expected = [
48 (0, 1),
50 (0, 1),
49 (2, 3),
51 (2, 3),
50 (4, 6),
52 (4, 6),
51 (6, 9),
53 (6, 9),
52 (9, 14),
54 (9, 14),
53 (16, None),
55 (16, None),
54 (None, 9),
56 (None, 9),
55 (9, None),
57 (9, None),
56 (None, 13),
58 (None, 13),
57 (None, None),
59 (None, None),
58 ]
60 ]
59 actual = list(code.extract_code_ranges(instr))
61 actual = list(code.extract_code_ranges(instr))
60 assert actual == expected
62 assert actual == expected
61
63
62 def test_extract_symbols():
64 def test_extract_symbols():
63 source = """import foo\na = 10\ndef b():\n return 42\n\n\nclass A: pass\n\n\n"""
65 source = """import foo\na = 10\ndef b():\n return 42\n\n\nclass A: pass\n\n\n"""
64 symbols_args = ["a", "b", "A", "A,b", "A,a", "z"]
66 symbols_args = ["a", "b", "A", "A,b", "A,a", "z"]
65 expected = [([], ['a']),
67 expected = [([], ['a']),
66 (["def b():\n return 42\n"], []),
68 (["def b():\n return 42\n"], []),
67 (["class A: pass\n"], []),
69 (["class A: pass\n"], []),
68 (["class A: pass\n", "def b():\n return 42\n"], []),
70 (["class A: pass\n", "def b():\n return 42\n"], []),
69 (["class A: pass\n"], ['a']),
71 (["class A: pass\n"], ['a']),
70 ([], ['z'])]
72 ([], ['z'])]
71 for symbols, exp in zip(symbols_args, expected):
73 for symbols, exp in zip(symbols_args, expected):
72 assert code.extract_symbols(source, symbols) == exp
74 assert code.extract_symbols(source, symbols) == exp
73
75
74
76
75 def test_extract_symbols_raises_exception_with_non_python_code():
77 def test_extract_symbols_raises_exception_with_non_python_code():
76 source = ("=begin A Ruby program :)=end\n"
78 source = ("=begin A Ruby program :)=end\n"
77 "def hello\n"
79 "def hello\n"
78 "puts 'Hello world'\n"
80 "puts 'Hello world'\n"
79 "end")
81 "end")
80 with pytest.raises(SyntaxError):
82 with pytest.raises(SyntaxError):
81 code.extract_symbols(source, "hello")
83 code.extract_symbols(source, "hello")
82
84
83
85
84 def test_magic_not_found():
86 def test_magic_not_found():
85 # magic not found raises UsageError
87 # magic not found raises UsageError
86 with pytest.raises(UsageError):
88 with pytest.raises(UsageError):
87 _ip.run_line_magic("doesntexist", "")
89 _ip.run_line_magic("doesntexist", "")
88
90
89 # ensure result isn't success when a magic isn't found
91 # ensure result isn't success when a magic isn't found
90 result = _ip.run_cell('%doesntexist')
92 result = _ip.run_cell('%doesntexist')
91 assert isinstance(result.error_in_exec, UsageError)
93 assert isinstance(result.error_in_exec, UsageError)
92
94
93
95
94 def test_cell_magic_not_found():
96 def test_cell_magic_not_found():
95 # magic not found raises UsageError
97 # magic not found raises UsageError
96 with pytest.raises(UsageError):
98 with pytest.raises(UsageError):
97 _ip.run_cell_magic('doesntexist', 'line', 'cell')
99 _ip.run_cell_magic('doesntexist', 'line', 'cell')
98
100
99 # ensure result isn't success when a magic isn't found
101 # ensure result isn't success when a magic isn't found
100 result = _ip.run_cell('%%doesntexist')
102 result = _ip.run_cell('%%doesntexist')
101 assert isinstance(result.error_in_exec, UsageError)
103 assert isinstance(result.error_in_exec, UsageError)
102
104
103
105
104 def test_magic_error_status():
106 def test_magic_error_status():
105 def fail(shell):
107 def fail(shell):
106 1/0
108 1/0
107 _ip.register_magic_function(fail)
109 _ip.register_magic_function(fail)
108 result = _ip.run_cell('%fail')
110 result = _ip.run_cell('%fail')
109 assert isinstance(result.error_in_exec, ZeroDivisionError)
111 assert isinstance(result.error_in_exec, ZeroDivisionError)
110
112
111
113
112 def test_config():
114 def test_config():
113 """ test that config magic does not raise
115 """ test that config magic does not raise
114 can happen if Configurable init is moved too early into
116 can happen if Configurable init is moved too early into
115 Magics.__init__ as then a Config object will be registered as a
117 Magics.__init__ as then a Config object will be registered as a
116 magic.
118 magic.
117 """
119 """
118 ## should not raise.
120 ## should not raise.
119 _ip.run_line_magic("config", "")
121 _ip.run_line_magic("config", "")
120
122
121
123
122 def test_config_available_configs():
124 def test_config_available_configs():
123 """ test that config magic prints available configs in unique and
125 """ test that config magic prints available configs in unique and
124 sorted order. """
126 sorted order. """
125 with capture_output() as captured:
127 with capture_output() as captured:
126 _ip.run_line_magic("config", "")
128 _ip.run_line_magic("config", "")
127
129
128 stdout = captured.stdout
130 stdout = captured.stdout
129 config_classes = stdout.strip().split('\n')[1:]
131 config_classes = stdout.strip().split('\n')[1:]
130 assert config_classes == sorted(set(config_classes))
132 assert config_classes == sorted(set(config_classes))
131
133
132 def test_config_print_class():
134 def test_config_print_class():
133 """ test that config with a classname prints the class's options. """
135 """ test that config with a classname prints the class's options. """
134 with capture_output() as captured:
136 with capture_output() as captured:
135 _ip.run_line_magic("config", "TerminalInteractiveShell")
137 _ip.run_line_magic("config", "TerminalInteractiveShell")
136
138
137 stdout = captured.stdout
139 stdout = captured.stdout
138 assert re.match(
140 assert re.match(
139 "TerminalInteractiveShell.* options", stdout.splitlines()[0]
141 "TerminalInteractiveShell.* options", stdout.splitlines()[0]
140 ), f"{stdout}\n\n1st line of stdout not like 'TerminalInteractiveShell.* options'"
142 ), f"{stdout}\n\n1st line of stdout not like 'TerminalInteractiveShell.* options'"
141
143
142
144
143 def test_rehashx():
145 def test_rehashx():
144 # clear up everything
146 # clear up everything
145 _ip.alias_manager.clear_aliases()
147 _ip.alias_manager.clear_aliases()
146 del _ip.db['syscmdlist']
148 del _ip.db['syscmdlist']
147
149
148 _ip.run_line_magic("rehashx", "")
150 _ip.run_line_magic("rehashx", "")
149 # Practically ALL ipython development systems will have more than 10 aliases
151 # Practically ALL ipython development systems will have more than 10 aliases
150
152
151 assert len(_ip.alias_manager.aliases) > 10
153 assert len(_ip.alias_manager.aliases) > 10
152 for name, cmd in _ip.alias_manager.aliases:
154 for name, cmd in _ip.alias_manager.aliases:
153 # we must strip dots from alias names
155 # we must strip dots from alias names
154 assert "." not in name
156 assert "." not in name
155
157
156 # rehashx must fill up syscmdlist
158 # rehashx must fill up syscmdlist
157 scoms = _ip.db['syscmdlist']
159 scoms = _ip.db['syscmdlist']
158 assert len(scoms) > 10
160 assert len(scoms) > 10
159
161
160
162
161 def test_magic_parse_options():
163 def test_magic_parse_options():
162 """Test that we don't mangle paths when parsing magic options."""
164 """Test that we don't mangle paths when parsing magic options."""
163 ip = get_ipython()
165 ip = get_ipython()
164 path = 'c:\\x'
166 path = 'c:\\x'
165 m = DummyMagics(ip)
167 m = DummyMagics(ip)
166 opts = m.parse_options('-f %s' % path,'f:')[0]
168 opts = m.parse_options('-f %s' % path,'f:')[0]
167 # argv splitting is os-dependent
169 # argv splitting is os-dependent
168 if os.name == 'posix':
170 if os.name == 'posix':
169 expected = 'c:x'
171 expected = 'c:x'
170 else:
172 else:
171 expected = path
173 expected = path
172 assert opts["f"] == expected
174 assert opts["f"] == expected
173
175
174
176
175 def test_magic_parse_long_options():
177 def test_magic_parse_long_options():
176 """Magic.parse_options can handle --foo=bar long options"""
178 """Magic.parse_options can handle --foo=bar long options"""
177 ip = get_ipython()
179 ip = get_ipython()
178 m = DummyMagics(ip)
180 m = DummyMagics(ip)
179 opts, _ = m.parse_options("--foo --bar=bubble", "a", "foo", "bar=")
181 opts, _ = m.parse_options("--foo --bar=bubble", "a", "foo", "bar=")
180 assert "foo" in opts
182 assert "foo" in opts
181 assert "bar" in opts
183 assert "bar" in opts
182 assert opts["bar"] == "bubble"
184 assert opts["bar"] == "bubble"
183
185
184
186
185 def doctest_hist_f():
187 def doctest_hist_f():
186 """Test %hist -f with temporary filename.
188 """Test %hist -f with temporary filename.
187
189
188 In [9]: import tempfile
190 In [9]: import tempfile
189
191
190 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
192 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
191
193
192 In [11]: %hist -nl -f $tfile 3
194 In [11]: %hist -nl -f $tfile 3
193
195
194 In [13]: import os; os.unlink(tfile)
196 In [13]: import os; os.unlink(tfile)
195 """
197 """
196
198
197
199
198 def doctest_hist_op():
200 def doctest_hist_op():
199 """Test %hist -op
201 """Test %hist -op
200
202
201 In [1]: class b(float):
203 In [1]: class b(float):
202 ...: pass
204 ...: pass
203 ...:
205 ...:
204
206
205 In [2]: class s(object):
207 In [2]: class s(object):
206 ...: def __str__(self):
208 ...: def __str__(self):
207 ...: return 's'
209 ...: return 's'
208 ...:
210 ...:
209
211
210 In [3]:
212 In [3]:
211
213
212 In [4]: class r(b):
214 In [4]: class r(b):
213 ...: def __repr__(self):
215 ...: def __repr__(self):
214 ...: return 'r'
216 ...: return 'r'
215 ...:
217 ...:
216
218
217 In [5]: class sr(s,r): pass
219 In [5]: class sr(s,r): pass
218 ...:
220 ...:
219
221
220 In [6]:
222 In [6]:
221
223
222 In [7]: bb=b()
224 In [7]: bb=b()
223
225
224 In [8]: ss=s()
226 In [8]: ss=s()
225
227
226 In [9]: rr=r()
228 In [9]: rr=r()
227
229
228 In [10]: ssrr=sr()
230 In [10]: ssrr=sr()
229
231
230 In [11]: 4.5
232 In [11]: 4.5
231 Out[11]: 4.5
233 Out[11]: 4.5
232
234
233 In [12]: str(ss)
235 In [12]: str(ss)
234 Out[12]: 's'
236 Out[12]: 's'
235
237
236 In [13]:
238 In [13]:
237
239
238 In [14]: %hist -op
240 In [14]: %hist -op
239 >>> class b:
241 >>> class b:
240 ... pass
242 ... pass
241 ...
243 ...
242 >>> class s(b):
244 >>> class s(b):
243 ... def __str__(self):
245 ... def __str__(self):
244 ... return 's'
246 ... return 's'
245 ...
247 ...
246 >>>
248 >>>
247 >>> class r(b):
249 >>> class r(b):
248 ... def __repr__(self):
250 ... def __repr__(self):
249 ... return 'r'
251 ... return 'r'
250 ...
252 ...
251 >>> class sr(s,r): pass
253 >>> class sr(s,r): pass
252 >>>
254 >>>
253 >>> bb=b()
255 >>> bb=b()
254 >>> ss=s()
256 >>> ss=s()
255 >>> rr=r()
257 >>> rr=r()
256 >>> ssrr=sr()
258 >>> ssrr=sr()
257 >>> 4.5
259 >>> 4.5
258 4.5
260 4.5
259 >>> str(ss)
261 >>> str(ss)
260 's'
262 's'
261 >>>
263 >>>
262 """
264 """
263
265
264 def test_hist_pof():
266 def test_hist_pof():
265 ip = get_ipython()
267 ip = get_ipython()
266 ip.run_cell("1+2", store_history=True)
268 ip.run_cell("1+2", store_history=True)
267 #raise Exception(ip.history_manager.session_number)
269 #raise Exception(ip.history_manager.session_number)
268 #raise Exception(list(ip.history_manager._get_range_session()))
270 #raise Exception(list(ip.history_manager._get_range_session()))
269 with TemporaryDirectory() as td:
271 with TemporaryDirectory() as td:
270 tf = os.path.join(td, 'hist.py')
272 tf = os.path.join(td, 'hist.py')
271 ip.run_line_magic('history', '-pof %s' % tf)
273 ip.run_line_magic('history', '-pof %s' % tf)
272 assert os.path.isfile(tf)
274 assert os.path.isfile(tf)
273
275
274
276
275 def test_macro():
277 def test_macro():
276 ip = get_ipython()
278 ip = get_ipython()
277 ip.history_manager.reset() # Clear any existing history.
279 ip.history_manager.reset() # Clear any existing history.
278 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
280 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
279 for i, cmd in enumerate(cmds, start=1):
281 for i, cmd in enumerate(cmds, start=1):
280 ip.history_manager.store_inputs(i, cmd)
282 ip.history_manager.store_inputs(i, cmd)
281 ip.run_line_magic("macro", "test 1-3")
283 ip.run_line_magic("macro", "test 1-3")
282 assert ip.user_ns["test"].value == "\n".join(cmds) + "\n"
284 assert ip.user_ns["test"].value == "\n".join(cmds) + "\n"
283
285
284 # List macros
286 # List macros
285 assert "test" in ip.run_line_magic("macro", "")
287 assert "test" in ip.run_line_magic("macro", "")
286
288
287
289
288 def test_macro_run():
290 def test_macro_run():
289 """Test that we can run a multi-line macro successfully."""
291 """Test that we can run a multi-line macro successfully."""
290 ip = get_ipython()
292 ip = get_ipython()
291 ip.history_manager.reset()
293 ip.history_manager.reset()
292 cmds = ["a=10", "a+=1", "print(a)", "%macro test 2-3"]
294 cmds = ["a=10", "a+=1", "print(a)", "%macro test 2-3"]
293 for cmd in cmds:
295 for cmd in cmds:
294 ip.run_cell(cmd, store_history=True)
296 ip.run_cell(cmd, store_history=True)
295 assert ip.user_ns["test"].value == "a+=1\nprint(a)\n"
297 assert ip.user_ns["test"].value == "a+=1\nprint(a)\n"
296 with tt.AssertPrints("12"):
298 with tt.AssertPrints("12"):
297 ip.run_cell("test")
299 ip.run_cell("test")
298 with tt.AssertPrints("13"):
300 with tt.AssertPrints("13"):
299 ip.run_cell("test")
301 ip.run_cell("test")
300
302
301
303
302 def test_magic_magic():
304 def test_magic_magic():
303 """Test %magic"""
305 """Test %magic"""
304 ip = get_ipython()
306 ip = get_ipython()
305 with capture_output() as captured:
307 with capture_output() as captured:
306 ip.run_line_magic("magic", "")
308 ip.run_line_magic("magic", "")
307
309
308 stdout = captured.stdout
310 stdout = captured.stdout
309 assert "%magic" in stdout
311 assert "%magic" in stdout
310 assert "IPython" in stdout
312 assert "IPython" in stdout
311 assert "Available" in stdout
313 assert "Available" in stdout
312
314
313
315
314 @dec.skipif_not_numpy
316 @dec.skipif_not_numpy
315 def test_numpy_reset_array_undec():
317 def test_numpy_reset_array_undec():
316 "Test '%reset array' functionality"
318 "Test '%reset array' functionality"
317 _ip.ex("import numpy as np")
319 _ip.ex("import numpy as np")
318 _ip.ex("a = np.empty(2)")
320 _ip.ex("a = np.empty(2)")
319 assert "a" in _ip.user_ns
321 assert "a" in _ip.user_ns
320 _ip.run_line_magic("reset", "-f array")
322 _ip.run_line_magic("reset", "-f array")
321 assert "a" not in _ip.user_ns
323 assert "a" not in _ip.user_ns
322
324
323
325
324 def test_reset_out():
326 def test_reset_out():
325 "Test '%reset out' magic"
327 "Test '%reset out' magic"
326 _ip.run_cell("parrot = 'dead'", store_history=True)
328 _ip.run_cell("parrot = 'dead'", store_history=True)
327 # test '%reset -f out', make an Out prompt
329 # test '%reset -f out', make an Out prompt
328 _ip.run_cell("parrot", store_history=True)
330 _ip.run_cell("parrot", store_history=True)
329 assert "dead" in [_ip.user_ns[x] for x in ("_", "__", "___")]
331 assert "dead" in [_ip.user_ns[x] for x in ("_", "__", "___")]
330 _ip.run_line_magic("reset", "-f out")
332 _ip.run_line_magic("reset", "-f out")
331 assert "dead" not in [_ip.user_ns[x] for x in ("_", "__", "___")]
333 assert "dead" not in [_ip.user_ns[x] for x in ("_", "__", "___")]
332 assert len(_ip.user_ns["Out"]) == 0
334 assert len(_ip.user_ns["Out"]) == 0
333
335
334
336
335 def test_reset_in():
337 def test_reset_in():
336 "Test '%reset in' magic"
338 "Test '%reset in' magic"
337 # test '%reset -f in'
339 # test '%reset -f in'
338 _ip.run_cell("parrot", store_history=True)
340 _ip.run_cell("parrot", store_history=True)
339 assert "parrot" in [_ip.user_ns[x] for x in ("_i", "_ii", "_iii")]
341 assert "parrot" in [_ip.user_ns[x] for x in ("_i", "_ii", "_iii")]
340 _ip.run_line_magic("reset", "-f in")
342 _ip.run_line_magic("reset", "-f in")
341 assert "parrot" not in [_ip.user_ns[x] for x in ("_i", "_ii", "_iii")]
343 assert "parrot" not in [_ip.user_ns[x] for x in ("_i", "_ii", "_iii")]
342 assert len(set(_ip.user_ns["In"])) == 1
344 assert len(set(_ip.user_ns["In"])) == 1
343
345
344
346
345 def test_reset_dhist():
347 def test_reset_dhist():
346 "Test '%reset dhist' magic"
348 "Test '%reset dhist' magic"
347 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
349 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
348 _ip.run_line_magic("cd", os.path.dirname(pytest.__file__))
350 _ip.run_line_magic("cd", os.path.dirname(pytest.__file__))
349 _ip.run_line_magic("cd", "-")
351 _ip.run_line_magic("cd", "-")
350 assert len(_ip.user_ns["_dh"]) > 0
352 assert len(_ip.user_ns["_dh"]) > 0
351 _ip.run_line_magic("reset", "-f dhist")
353 _ip.run_line_magic("reset", "-f dhist")
352 assert len(_ip.user_ns["_dh"]) == 0
354 assert len(_ip.user_ns["_dh"]) == 0
353 _ip.run_cell("_dh = [d for d in tmp]") # restore
355 _ip.run_cell("_dh = [d for d in tmp]") # restore
354
356
355
357
356 def test_reset_in_length():
358 def test_reset_in_length():
357 "Test that '%reset in' preserves In[] length"
359 "Test that '%reset in' preserves In[] length"
358 _ip.run_cell("print 'foo'")
360 _ip.run_cell("print 'foo'")
359 _ip.run_cell("reset -f in")
361 _ip.run_cell("reset -f in")
360 assert len(_ip.user_ns["In"]) == _ip.displayhook.prompt_count + 1
362 assert len(_ip.user_ns["In"]) == _ip.displayhook.prompt_count + 1
361
363
362
364
363 class TestResetErrors(TestCase):
365 class TestResetErrors(TestCase):
364
366
365 def test_reset_redefine(self):
367 def test_reset_redefine(self):
366
368
367 @magics_class
369 @magics_class
368 class KernelMagics(Magics):
370 class KernelMagics(Magics):
369 @line_magic
371 @line_magic
370 def less(self, shell): pass
372 def less(self, shell): pass
371
373
372 _ip.register_magics(KernelMagics)
374 _ip.register_magics(KernelMagics)
373
375
374 with self.assertLogs() as cm:
376 with self.assertLogs() as cm:
375 # hack, we want to just capture logs, but assertLogs fails if not
377 # hack, we want to just capture logs, but assertLogs fails if not
376 # logs get produce.
378 # logs get produce.
377 # so log one things we ignore.
379 # so log one things we ignore.
378 import logging as log_mod
380 import logging as log_mod
379 log = log_mod.getLogger()
381 log = log_mod.getLogger()
380 log.info('Nothing')
382 log.info('Nothing')
381 # end hack.
383 # end hack.
382 _ip.run_cell("reset -f")
384 _ip.run_cell("reset -f")
383
385
384 assert len(cm.output) == 1
386 assert len(cm.output) == 1
385 for out in cm.output:
387 for out in cm.output:
386 assert "Invalid alias" not in out
388 assert "Invalid alias" not in out
387
389
388 def test_tb_syntaxerror():
390 def test_tb_syntaxerror():
389 """test %tb after a SyntaxError"""
391 """test %tb after a SyntaxError"""
390 ip = get_ipython()
392 ip = get_ipython()
391 ip.run_cell("for")
393 ip.run_cell("for")
392
394
393 # trap and validate stdout
395 # trap and validate stdout
394 save_stdout = sys.stdout
396 save_stdout = sys.stdout
395 try:
397 try:
396 sys.stdout = StringIO()
398 sys.stdout = StringIO()
397 ip.run_cell("%tb")
399 ip.run_cell("%tb")
398 out = sys.stdout.getvalue()
400 out = sys.stdout.getvalue()
399 finally:
401 finally:
400 sys.stdout = save_stdout
402 sys.stdout = save_stdout
401 # trim output, and only check the last line
403 # trim output, and only check the last line
402 last_line = out.rstrip().splitlines()[-1].strip()
404 last_line = out.rstrip().splitlines()[-1].strip()
403 assert last_line == "SyntaxError: invalid syntax"
405 assert last_line == "SyntaxError: invalid syntax"
404
406
405
407
406 def test_time():
408 def test_time():
407 ip = get_ipython()
409 ip = get_ipython()
408
410
409 with tt.AssertPrints("Wall time: "):
411 with tt.AssertPrints("Wall time: "):
410 ip.run_cell("%time None")
412 ip.run_cell("%time None")
411
413
412 ip.run_cell("def f(kmjy):\n"
414 ip.run_cell("def f(kmjy):\n"
413 " %time print (2*kmjy)")
415 " %time print (2*kmjy)")
414
416
415 with tt.AssertPrints("Wall time: "):
417 with tt.AssertPrints("Wall time: "):
416 with tt.AssertPrints("hihi", suppress=False):
418 with tt.AssertPrints("hihi", suppress=False):
417 ip.run_cell("f('hi')")
419 ip.run_cell("f('hi')")
418
420
419
421
420 # ';' at the end of %time prevents instruction value to be printed.
422 # ';' at the end of %time prevents instruction value to be printed.
421 # This tests fix for #13837.
423 # This tests fix for #13837.
422 def test_time_no_output_with_semicolon():
424 def test_time_no_output_with_semicolon():
423 ip = get_ipython()
425 ip = get_ipython()
424
426
425 # Test %time cases
427 # Test %time cases
426 with tt.AssertPrints(" 123456"):
428 with tt.AssertPrints(" 123456"):
427 with tt.AssertPrints("Wall time: ", suppress=False):
429 with tt.AssertPrints("Wall time: ", suppress=False):
428 with tt.AssertPrints("CPU times: ", suppress=False):
430 with tt.AssertPrints("CPU times: ", suppress=False):
429 ip.run_cell("%time 123000+456")
431 ip.run_cell("%time 123000+456")
430
432
431 with tt.AssertNotPrints(" 123456"):
433 with tt.AssertNotPrints(" 123456"):
432 with tt.AssertPrints("Wall time: ", suppress=False):
434 with tt.AssertPrints("Wall time: ", suppress=False):
433 with tt.AssertPrints("CPU times: ", suppress=False):
435 with tt.AssertPrints("CPU times: ", suppress=False):
434 ip.run_cell("%time 123000+456;")
436 ip.run_cell("%time 123000+456;")
435
437
436 with tt.AssertPrints(" 123456"):
438 with tt.AssertPrints(" 123456"):
437 with tt.AssertPrints("Wall time: ", suppress=False):
439 with tt.AssertPrints("Wall time: ", suppress=False):
438 with tt.AssertPrints("CPU times: ", suppress=False):
440 with tt.AssertPrints("CPU times: ", suppress=False):
439 ip.run_cell("%time 123000+456 # Comment")
441 ip.run_cell("%time 123000+456 # Comment")
440
442
441 with tt.AssertNotPrints(" 123456"):
443 with tt.AssertNotPrints(" 123456"):
442 with tt.AssertPrints("Wall time: ", suppress=False):
444 with tt.AssertPrints("Wall time: ", suppress=False):
443 with tt.AssertPrints("CPU times: ", suppress=False):
445 with tt.AssertPrints("CPU times: ", suppress=False):
444 ip.run_cell("%time 123000+456; # Comment")
446 ip.run_cell("%time 123000+456; # Comment")
445
447
446 with tt.AssertPrints(" 123456"):
448 with tt.AssertPrints(" 123456"):
447 with tt.AssertPrints("Wall time: ", suppress=False):
449 with tt.AssertPrints("Wall time: ", suppress=False):
448 with tt.AssertPrints("CPU times: ", suppress=False):
450 with tt.AssertPrints("CPU times: ", suppress=False):
449 ip.run_cell("%time 123000+456 # ;Comment")
451 ip.run_cell("%time 123000+456 # ;Comment")
450
452
451 # Test %%time cases
453 # Test %%time cases
452 with tt.AssertPrints("123456"):
454 with tt.AssertPrints("123456"):
453 with tt.AssertPrints("Wall time: ", suppress=False):
455 with tt.AssertPrints("Wall time: ", suppress=False):
454 with tt.AssertPrints("CPU times: ", suppress=False):
456 with tt.AssertPrints("CPU times: ", suppress=False):
455 ip.run_cell("%%time\n123000+456\n\n\n")
457 ip.run_cell("%%time\n123000+456\n\n\n")
456
458
457 with tt.AssertNotPrints("123456"):
459 with tt.AssertNotPrints("123456"):
458 with tt.AssertPrints("Wall time: ", suppress=False):
460 with tt.AssertPrints("Wall time: ", suppress=False):
459 with tt.AssertPrints("CPU times: ", suppress=False):
461 with tt.AssertPrints("CPU times: ", suppress=False):
460 ip.run_cell("%%time\n123000+456;\n\n\n")
462 ip.run_cell("%%time\n123000+456;\n\n\n")
461
463
462 with tt.AssertPrints("123456"):
464 with tt.AssertPrints("123456"):
463 with tt.AssertPrints("Wall time: ", suppress=False):
465 with tt.AssertPrints("Wall time: ", suppress=False):
464 with tt.AssertPrints("CPU times: ", suppress=False):
466 with tt.AssertPrints("CPU times: ", suppress=False):
465 ip.run_cell("%%time\n123000+456 # Comment\n\n\n")
467 ip.run_cell("%%time\n123000+456 # Comment\n\n\n")
466
468
467 with tt.AssertNotPrints("123456"):
469 with tt.AssertNotPrints("123456"):
468 with tt.AssertPrints("Wall time: ", suppress=False):
470 with tt.AssertPrints("Wall time: ", suppress=False):
469 with tt.AssertPrints("CPU times: ", suppress=False):
471 with tt.AssertPrints("CPU times: ", suppress=False):
470 ip.run_cell("%%time\n123000+456; # Comment\n\n\n")
472 ip.run_cell("%%time\n123000+456; # Comment\n\n\n")
471
473
472 with tt.AssertPrints("123456"):
474 with tt.AssertPrints("123456"):
473 with tt.AssertPrints("Wall time: ", suppress=False):
475 with tt.AssertPrints("Wall time: ", suppress=False):
474 with tt.AssertPrints("CPU times: ", suppress=False):
476 with tt.AssertPrints("CPU times: ", suppress=False):
475 ip.run_cell("%%time\n123000+456 # ;Comment\n\n\n")
477 ip.run_cell("%%time\n123000+456 # ;Comment\n\n\n")
476
478
477
479
478 def test_time_last_not_expression():
480 def test_time_last_not_expression():
479 ip.run_cell("%%time\n"
481 _ip.run_cell("%%time\n"
480 "var_1 = 1\n"
482 "var_1 = 1\n"
481 "var_2 = 2\n")
483 "var_2 = 2\n")
482 assert ip.user_ns['var_1'] == 1
484 assert _ip.user_ns['var_1'] == 1
483 del ip.user_ns['var_1']
485 del _ip.user_ns['var_1']
484 assert ip.user_ns['var_2'] == 2
486 assert _ip.user_ns['var_2'] == 2
485 del ip.user_ns['var_2']
487 del _ip.user_ns['var_2']
486
488
487
489
488 @dec.skip_win32
490 @dec.skip_win32
489 def test_time2():
491 def test_time2():
490 ip = get_ipython()
492 ip = get_ipython()
491
493
492 with tt.AssertPrints("CPU times: user "):
494 with tt.AssertPrints("CPU times: user "):
493 ip.run_cell("%time None")
495 ip.run_cell("%time None")
494
496
495 def test_time3():
497 def test_time3():
496 """Erroneous magic function calls, issue gh-3334"""
498 """Erroneous magic function calls, issue gh-3334"""
497 ip = get_ipython()
499 ip = get_ipython()
498 ip.user_ns.pop('run', None)
500 ip.user_ns.pop('run', None)
499
501
500 with tt.AssertNotPrints("not found", channel='stderr'):
502 with tt.AssertNotPrints("not found", channel='stderr'):
501 ip.run_cell("%%time\n"
503 ip.run_cell("%%time\n"
502 "run = 0\n"
504 "run = 0\n"
503 "run += 1")
505 "run += 1")
504
506
505 def test_multiline_time():
507 def test_multiline_time():
506 """Make sure last statement from time return a value."""
508 """Make sure last statement from time return a value."""
507 ip = get_ipython()
509 ip = get_ipython()
508 ip.user_ns.pop('run', None)
510 ip.user_ns.pop('run', None)
509
511
510 ip.run_cell(
512 ip.run_cell(
511 dedent(
513 dedent(
512 """\
514 """\
513 %%time
515 %%time
514 a = "ho"
516 a = "ho"
515 b = "hey"
517 b = "hey"
516 a+b
518 a+b
517 """
519 """
518 )
520 )
519 )
521 )
520 assert ip.user_ns_hidden["_"] == "hohey"
522 assert ip.user_ns_hidden["_"] == "hohey"
521
523
522
524
523 def test_time_local_ns():
525 def test_time_local_ns():
524 """
526 """
525 Test that local_ns is actually global_ns when running a cell magic
527 Test that local_ns is actually global_ns when running a cell magic
526 """
528 """
527 ip = get_ipython()
529 ip = get_ipython()
528 ip.run_cell("%%time\n" "myvar = 1")
530 ip.run_cell("%%time\n" "myvar = 1")
529 assert ip.user_ns["myvar"] == 1
531 assert ip.user_ns["myvar"] == 1
530 del ip.user_ns["myvar"]
532 del ip.user_ns["myvar"]
531
533
532
534
533 def test_time_microseconds_display():
535 def test_time_microseconds_display():
534 """Ensure ASCII is used when necessary"""
536 """Ensure ASCII is used when necessary"""
535 with mock.patch("sys.stdout", io.TextIOWrapper(StringIO(), encoding="utf-8")):
537 with mock.patch("sys.stdout", io.TextIOWrapper(StringIO(), encoding="utf-8")):
536 assert execution._format_time(0.000001) == "1 \u03bcs"
538 assert execution._format_time(0.000001) == "1 \u03bcs"
537 with mock.patch("sys.stdout", io.TextIOWrapper(StringIO(), encoding="ascii")):
539 with mock.patch("sys.stdout", io.TextIOWrapper(StringIO(), encoding="ascii")):
538 assert execution._format_time(0.000001) == "1 us"
540 assert execution._format_time(0.000001) == "1 us"
539
541
540
542
541 # Test %%capture magic. Added to test issue #13926
543 # Test %%capture magic. Added to test issue #13926
542 def test_capture():
544 def test_capture():
543 ip = get_ipython()
545 ip = get_ipython()
544
546
545 # Test %%capture nominal case
547 # Test %%capture nominal case
546 ip.run_cell("%%capture abc\n1+2")
548 ip.run_cell("%%capture abc\n1+2")
547 with tt.AssertPrints("True", suppress=False):
549 with tt.AssertPrints("True", suppress=False):
548 ip.run_cell("'abc' in locals()")
550 ip.run_cell("'abc' in locals()")
549 with tt.AssertPrints("True", suppress=False):
551 with tt.AssertPrints("True", suppress=False):
550 ip.run_cell("'outputs' in dir(abc)")
552 ip.run_cell("'outputs' in dir(abc)")
551 with tt.AssertPrints("3", suppress=False):
553 with tt.AssertPrints("3", suppress=False):
552 ip.run_cell("abc.outputs[0]")
554 ip.run_cell("abc.outputs[0]")
553
555
554 # Test %%capture with ';' at end of expression
556 # Test %%capture with ';' at end of expression
555 ip.run_cell("%%capture abc\n7+8;")
557 ip.run_cell("%%capture abc\n7+8;")
556 with tt.AssertPrints("False", suppress=False):
558 with tt.AssertPrints("False", suppress=False):
557 ip.run_cell("'abc' in locals()")
559 ip.run_cell("'abc' in locals()")
558
560
559
561
560 def test_doctest_mode():
562 def test_doctest_mode():
561 "Toggle doctest_mode twice, it should be a no-op and run without error"
563 "Toggle doctest_mode twice, it should be a no-op and run without error"
562 _ip.run_line_magic("doctest_mode", "")
564 _ip.run_line_magic("doctest_mode", "")
563 _ip.run_line_magic("doctest_mode", "")
565 _ip.run_line_magic("doctest_mode", "")
564
566
565
567
566 def test_parse_options():
568 def test_parse_options():
567 """Tests for basic options parsing in magics."""
569 """Tests for basic options parsing in magics."""
568 # These are only the most minimal of tests, more should be added later. At
570 # These are only the most minimal of tests, more should be added later. At
569 # the very least we check that basic text/unicode calls work OK.
571 # the very least we check that basic text/unicode calls work OK.
570 m = DummyMagics(_ip)
572 m = DummyMagics(_ip)
571 assert m.parse_options("foo", "")[1] == "foo"
573 assert m.parse_options("foo", "")[1] == "foo"
572 assert m.parse_options("foo", "")[1] == "foo"
574 assert m.parse_options("foo", "")[1] == "foo"
573
575
574
576
575 def test_parse_options_preserve_non_option_string():
577 def test_parse_options_preserve_non_option_string():
576 """Test to assert preservation of non-option part of magic-block, while parsing magic options."""
578 """Test to assert preservation of non-option part of magic-block, while parsing magic options."""
577 m = DummyMagics(_ip)
579 m = DummyMagics(_ip)
578 opts, stmt = m.parse_options(
580 opts, stmt = m.parse_options(
579 " -n1 -r 13 _ = 314 + foo", "n:r:", preserve_non_opts=True
581 " -n1 -r 13 _ = 314 + foo", "n:r:", preserve_non_opts=True
580 )
582 )
581 assert opts == {"n": "1", "r": "13"}
583 assert opts == {"n": "1", "r": "13"}
582 assert stmt == "_ = 314 + foo"
584 assert stmt == "_ = 314 + foo"
583
585
584
586
585 def test_run_magic_preserve_code_block():
587 def test_run_magic_preserve_code_block():
586 """Test to assert preservation of non-option part of magic-block, while running magic."""
588 """Test to assert preservation of non-option part of magic-block, while running magic."""
587 _ip.user_ns["spaces"] = []
589 _ip.user_ns["spaces"] = []
588 _ip.run_line_magic(
590 _ip.run_line_magic(
589 "timeit", "-n1 -r1 spaces.append([s.count(' ') for s in ['document']])"
591 "timeit", "-n1 -r1 spaces.append([s.count(' ') for s in ['document']])"
590 )
592 )
591 assert _ip.user_ns["spaces"] == [[0]]
593 assert _ip.user_ns["spaces"] == [[0]]
592
594
593
595
594 def test_dirops():
596 def test_dirops():
595 """Test various directory handling operations."""
597 """Test various directory handling operations."""
596 # curpath = lambda :os.path.splitdrive(os.getcwd())[1].replace('\\','/')
598 # curpath = lambda :os.path.splitdrive(os.getcwd())[1].replace('\\','/')
597 curpath = os.getcwd
599 curpath = os.getcwd
598 startdir = os.getcwd()
600 startdir = os.getcwd()
599 ipdir = os.path.realpath(_ip.ipython_dir)
601 ipdir = os.path.realpath(_ip.ipython_dir)
600 try:
602 try:
601 _ip.run_line_magic("cd", '"%s"' % ipdir)
603 _ip.run_line_magic("cd", '"%s"' % ipdir)
602 assert curpath() == ipdir
604 assert curpath() == ipdir
603 _ip.run_line_magic("cd", "-")
605 _ip.run_line_magic("cd", "-")
604 assert curpath() == startdir
606 assert curpath() == startdir
605 _ip.run_line_magic("pushd", '"%s"' % ipdir)
607 _ip.run_line_magic("pushd", '"%s"' % ipdir)
606 assert curpath() == ipdir
608 assert curpath() == ipdir
607 _ip.run_line_magic("popd", "")
609 _ip.run_line_magic("popd", "")
608 assert curpath() == startdir
610 assert curpath() == startdir
609 finally:
611 finally:
610 os.chdir(startdir)
612 os.chdir(startdir)
611
613
612
614
613 def test_cd_force_quiet():
615 def test_cd_force_quiet():
614 """Test OSMagics.cd_force_quiet option"""
616 """Test OSMagics.cd_force_quiet option"""
615 _ip.config.OSMagics.cd_force_quiet = True
617 _ip.config.OSMagics.cd_force_quiet = True
616 osmagics = osm.OSMagics(shell=_ip)
618 osmagics = osm.OSMagics(shell=_ip)
617
619
618 startdir = os.getcwd()
620 startdir = os.getcwd()
619 ipdir = os.path.realpath(_ip.ipython_dir)
621 ipdir = os.path.realpath(_ip.ipython_dir)
620
622
621 try:
623 try:
622 with tt.AssertNotPrints(ipdir):
624 with tt.AssertNotPrints(ipdir):
623 osmagics.cd('"%s"' % ipdir)
625 osmagics.cd('"%s"' % ipdir)
624 with tt.AssertNotPrints(startdir):
626 with tt.AssertNotPrints(startdir):
625 osmagics.cd('-')
627 osmagics.cd('-')
626 finally:
628 finally:
627 os.chdir(startdir)
629 os.chdir(startdir)
628
630
629
631
630 def test_xmode():
632 def test_xmode():
631 # Calling xmode three times should be a no-op
633 # Calling xmode three times should be a no-op
632 xmode = _ip.InteractiveTB.mode
634 xmode = _ip.InteractiveTB.mode
633 for i in range(4):
635 for i in range(4):
634 _ip.run_line_magic("xmode", "")
636 _ip.run_line_magic("xmode", "")
635 assert _ip.InteractiveTB.mode == xmode
637 assert _ip.InteractiveTB.mode == xmode
636
638
637 def test_reset_hard():
639 def test_reset_hard():
638 monitor = []
640 monitor = []
639 class A(object):
641 class A(object):
640 def __del__(self):
642 def __del__(self):
641 monitor.append(1)
643 monitor.append(1)
642 def __repr__(self):
644 def __repr__(self):
643 return "<A instance>"
645 return "<A instance>"
644
646
645 _ip.user_ns["a"] = A()
647 _ip.user_ns["a"] = A()
646 _ip.run_cell("a")
648 _ip.run_cell("a")
647
649
648 assert monitor == []
650 assert monitor == []
649 _ip.run_line_magic("reset", "-f")
651 _ip.run_line_magic("reset", "-f")
650 assert monitor == [1]
652 assert monitor == [1]
651
653
652 class TestXdel(tt.TempFileMixin):
654 class TestXdel(tt.TempFileMixin):
653 def test_xdel(self):
655 def test_xdel(self):
654 """Test that references from %run are cleared by xdel."""
656 """Test that references from %run are cleared by xdel."""
655 src = ("class A(object):\n"
657 src = ("class A(object):\n"
656 " monitor = []\n"
658 " monitor = []\n"
657 " def __del__(self):\n"
659 " def __del__(self):\n"
658 " self.monitor.append(1)\n"
660 " self.monitor.append(1)\n"
659 "a = A()\n")
661 "a = A()\n")
660 self.mktmp(src)
662 self.mktmp(src)
661 # %run creates some hidden references...
663 # %run creates some hidden references...
662 _ip.run_line_magic("run", "%s" % self.fname)
664 _ip.run_line_magic("run", "%s" % self.fname)
663 # ... as does the displayhook.
665 # ... as does the displayhook.
664 _ip.run_cell("a")
666 _ip.run_cell("a")
665
667
666 monitor = _ip.user_ns["A"].monitor
668 monitor = _ip.user_ns["A"].monitor
667 assert monitor == []
669 assert monitor == []
668
670
669 _ip.run_line_magic("xdel", "a")
671 _ip.run_line_magic("xdel", "a")
670
672
671 # Check that a's __del__ method has been called.
673 # Check that a's __del__ method has been called.
672 gc.collect(0)
674 gc.collect(0)
673 assert monitor == [1]
675 assert monitor == [1]
674
676
675 def doctest_who():
677 def doctest_who():
676 """doctest for %who
678 """doctest for %who
677
679
678 In [1]: %reset -sf
680 In [1]: %reset -sf
679
681
680 In [2]: alpha = 123
682 In [2]: alpha = 123
681
683
682 In [3]: beta = 'beta'
684 In [3]: beta = 'beta'
683
685
684 In [4]: %who int
686 In [4]: %who int
685 alpha
687 alpha
686
688
687 In [5]: %who str
689 In [5]: %who str
688 beta
690 beta
689
691
690 In [6]: %whos
692 In [6]: %whos
691 Variable Type Data/Info
693 Variable Type Data/Info
692 ----------------------------
694 ----------------------------
693 alpha int 123
695 alpha int 123
694 beta str beta
696 beta str beta
695
697
696 In [7]: %who_ls
698 In [7]: %who_ls
697 Out[7]: ['alpha', 'beta']
699 Out[7]: ['alpha', 'beta']
698 """
700 """
699
701
700 def test_whos():
702 def test_whos():
701 """Check that whos is protected against objects where repr() fails."""
703 """Check that whos is protected against objects where repr() fails."""
702 class A(object):
704 class A(object):
703 def __repr__(self):
705 def __repr__(self):
704 raise Exception()
706 raise Exception()
705 _ip.user_ns['a'] = A()
707 _ip.user_ns['a'] = A()
706 _ip.run_line_magic("whos", "")
708 _ip.run_line_magic("whos", "")
707
709
708 def doctest_precision():
710 def doctest_precision():
709 """doctest for %precision
711 """doctest for %precision
710
712
711 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
713 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
712
714
713 In [2]: %precision 5
715 In [2]: %precision 5
714 Out[2]: '%.5f'
716 Out[2]: '%.5f'
715
717
716 In [3]: f.float_format
718 In [3]: f.float_format
717 Out[3]: '%.5f'
719 Out[3]: '%.5f'
718
720
719 In [4]: %precision %e
721 In [4]: %precision %e
720 Out[4]: '%e'
722 Out[4]: '%e'
721
723
722 In [5]: f(3.1415927)
724 In [5]: f(3.1415927)
723 Out[5]: '3.141593e+00'
725 Out[5]: '3.141593e+00'
724 """
726 """
725
727
726
728
727 def test_debug_magic():
729 def test_debug_magic():
728 """Test debugging a small code with %debug
730 """Test debugging a small code with %debug
729
731
730 In [1]: with PdbTestInput(['c']):
732 In [1]: with PdbTestInput(['c']):
731 ...: %debug print("a b") #doctest: +ELLIPSIS
733 ...: %debug print("a b") #doctest: +ELLIPSIS
732 ...:
734 ...:
733 ...
735 ...
734 ipdb> c
736 ipdb> c
735 a b
737 a b
736 In [2]:
738 In [2]:
737 """
739 """
738
740
739
741
740 def test_debug_magic_locals():
742 def test_debug_magic_locals():
741 """Test debugging a small code with %debug with locals
743 """Test debugging a small code with %debug with locals
742
744
743 In [1]: with PdbTestInput(['c']):
745 In [1]: with PdbTestInput(['c']):
744 ...: def fun():
746 ...: def fun():
745 ...: res = 1
747 ...: res = 1
746 ...: %debug print(res)
748 ...: %debug print(res)
747 ...: fun()
749 ...: fun()
748 ...:
750 ...:
749 ...
751 ...
750 ipdb> c
752 ipdb> c
751 1
753 1
752 In [2]:
754 In [2]:
753 """
755 """
754
756
755 def test_psearch():
757 def test_psearch():
756 with tt.AssertPrints("dict.fromkeys"):
758 with tt.AssertPrints("dict.fromkeys"):
757 _ip.run_cell("dict.fr*?")
759 _ip.run_cell("dict.fr*?")
758 with tt.AssertPrints("Ο€.is_integer"):
760 with tt.AssertPrints("Ο€.is_integer"):
759 _ip.run_cell("Ο€ = 3.14;\nΟ€.is_integ*?")
761 _ip.run_cell("Ο€ = 3.14;\nΟ€.is_integ*?")
760
762
761 def test_timeit_shlex():
763 def test_timeit_shlex():
762 """test shlex issues with timeit (#1109)"""
764 """test shlex issues with timeit (#1109)"""
763 _ip.ex("def f(*a,**kw): pass")
765 _ip.ex("def f(*a,**kw): pass")
764 _ip.run_line_magic("timeit", '-n1 "this is a bug".count(" ")')
766 _ip.run_line_magic("timeit", '-n1 "this is a bug".count(" ")')
765 _ip.run_line_magic("timeit", '-r1 -n1 f(" ", 1)')
767 _ip.run_line_magic("timeit", '-r1 -n1 f(" ", 1)')
766 _ip.run_line_magic("timeit", '-r1 -n1 f(" ", 1, " ", 2, " ")')
768 _ip.run_line_magic("timeit", '-r1 -n1 f(" ", 1, " ", 2, " ")')
767 _ip.run_line_magic("timeit", '-r1 -n1 ("a " + "b")')
769 _ip.run_line_magic("timeit", '-r1 -n1 ("a " + "b")')
768 _ip.run_line_magic("timeit", '-r1 -n1 f("a " + "b")')
770 _ip.run_line_magic("timeit", '-r1 -n1 f("a " + "b")')
769 _ip.run_line_magic("timeit", '-r1 -n1 f("a " + "b ")')
771 _ip.run_line_magic("timeit", '-r1 -n1 f("a " + "b ")')
770
772
771
773
772 def test_timeit_special_syntax():
774 def test_timeit_special_syntax():
773 "Test %%timeit with IPython special syntax"
775 "Test %%timeit with IPython special syntax"
774 @register_line_magic
776 @register_line_magic
775 def lmagic(line):
777 def lmagic(line):
776 ip = get_ipython()
778 ip = get_ipython()
777 ip.user_ns['lmagic_out'] = line
779 ip.user_ns['lmagic_out'] = line
778
780
779 # line mode test
781 # line mode test
780 _ip.run_line_magic("timeit", "-n1 -r1 %lmagic my line")
782 _ip.run_line_magic("timeit", "-n1 -r1 %lmagic my line")
781 assert _ip.user_ns["lmagic_out"] == "my line"
783 assert _ip.user_ns["lmagic_out"] == "my line"
782 # cell mode test
784 # cell mode test
783 _ip.run_cell_magic("timeit", "-n1 -r1", "%lmagic my line2")
785 _ip.run_cell_magic("timeit", "-n1 -r1", "%lmagic my line2")
784 assert _ip.user_ns["lmagic_out"] == "my line2"
786 assert _ip.user_ns["lmagic_out"] == "my line2"
785
787
786
788
787 def test_timeit_return():
789 def test_timeit_return():
788 """
790 """
789 test whether timeit -o return object
791 test whether timeit -o return object
790 """
792 """
791
793
792 res = _ip.run_line_magic('timeit','-n10 -r10 -o 1')
794 res = _ip.run_line_magic('timeit','-n10 -r10 -o 1')
793 assert(res is not None)
795 assert(res is not None)
794
796
795 def test_timeit_quiet():
797 def test_timeit_quiet():
796 """
798 """
797 test quiet option of timeit magic
799 test quiet option of timeit magic
798 """
800 """
799 with tt.AssertNotPrints("loops"):
801 with tt.AssertNotPrints("loops"):
800 _ip.run_cell("%timeit -n1 -r1 -q 1")
802 _ip.run_cell("%timeit -n1 -r1 -q 1")
801
803
802 def test_timeit_return_quiet():
804 def test_timeit_return_quiet():
803 with tt.AssertNotPrints("loops"):
805 with tt.AssertNotPrints("loops"):
804 res = _ip.run_line_magic('timeit', '-n1 -r1 -q -o 1')
806 res = _ip.run_line_magic('timeit', '-n1 -r1 -q -o 1')
805 assert (res is not None)
807 assert (res is not None)
806
808
807 def test_timeit_invalid_return():
809 def test_timeit_invalid_return():
808 with pytest.raises(SyntaxError):
810 with pytest.raises(SyntaxError):
809 _ip.run_line_magic('timeit', 'return')
811 _ip.run_line_magic('timeit', 'return')
810
812
811 @dec.skipif(execution.profile is None)
813 @dec.skipif(execution.profile is None)
812 def test_prun_special_syntax():
814 def test_prun_special_syntax():
813 "Test %%prun with IPython special syntax"
815 "Test %%prun with IPython special syntax"
814 @register_line_magic
816 @register_line_magic
815 def lmagic(line):
817 def lmagic(line):
816 ip = get_ipython()
818 ip = get_ipython()
817 ip.user_ns['lmagic_out'] = line
819 ip.user_ns['lmagic_out'] = line
818
820
819 # line mode test
821 # line mode test
820 _ip.run_line_magic("prun", "-q %lmagic my line")
822 _ip.run_line_magic("prun", "-q %lmagic my line")
821 assert _ip.user_ns["lmagic_out"] == "my line"
823 assert _ip.user_ns["lmagic_out"] == "my line"
822 # cell mode test
824 # cell mode test
823 _ip.run_cell_magic("prun", "-q", "%lmagic my line2")
825 _ip.run_cell_magic("prun", "-q", "%lmagic my line2")
824 assert _ip.user_ns["lmagic_out"] == "my line2"
826 assert _ip.user_ns["lmagic_out"] == "my line2"
825
827
826
828
827 @dec.skipif(execution.profile is None)
829 @dec.skipif(execution.profile is None)
828 def test_prun_quotes():
830 def test_prun_quotes():
829 "Test that prun does not clobber string escapes (GH #1302)"
831 "Test that prun does not clobber string escapes (GH #1302)"
830 _ip.run_line_magic("prun", r"-q x = '\t'")
832 _ip.run_line_magic("prun", r"-q x = '\t'")
831 assert _ip.user_ns["x"] == "\t"
833 assert _ip.user_ns["x"] == "\t"
832
834
833
835
834 def test_extension():
836 def test_extension():
835 # Debugging information for failures of this test
837 # Debugging information for failures of this test
836 print('sys.path:')
838 print('sys.path:')
837 for p in sys.path:
839 for p in sys.path:
838 print(' ', p)
840 print(' ', p)
839 print('CWD', os.getcwd())
841 print('CWD', os.getcwd())
840
842
841 pytest.raises(ImportError, _ip.run_line_magic, "load_ext", "daft_extension")
843 pytest.raises(ImportError, _ip.run_line_magic, "load_ext", "daft_extension")
842 daft_path = os.path.join(os.path.dirname(__file__), "daft_extension")
844 daft_path = os.path.join(os.path.dirname(__file__), "daft_extension")
843 sys.path.insert(0, daft_path)
845 sys.path.insert(0, daft_path)
844 try:
846 try:
845 _ip.user_ns.pop('arq', None)
847 _ip.user_ns.pop('arq', None)
846 invalidate_caches() # Clear import caches
848 invalidate_caches() # Clear import caches
847 _ip.run_line_magic("load_ext", "daft_extension")
849 _ip.run_line_magic("load_ext", "daft_extension")
848 assert _ip.user_ns["arq"] == 185
850 assert _ip.user_ns["arq"] == 185
849 _ip.run_line_magic("unload_ext", "daft_extension")
851 _ip.run_line_magic("unload_ext", "daft_extension")
850 assert 'arq' not in _ip.user_ns
852 assert 'arq' not in _ip.user_ns
851 finally:
853 finally:
852 sys.path.remove(daft_path)
854 sys.path.remove(daft_path)
853
855
854
856
855 def test_notebook_export_json():
857 def test_notebook_export_json():
856 pytest.importorskip("nbformat")
858 pytest.importorskip("nbformat")
857 _ip = get_ipython()
859 _ip = get_ipython()
858 _ip.history_manager.reset() # Clear any existing history.
860 _ip.history_manager.reset() # Clear any existing history.
859 cmds = ["a=1", "def b():\n return a**2", "print('noΓ«l, Γ©tΓ©', b())"]
861 cmds = ["a=1", "def b():\n return a**2", "print('noΓ«l, Γ©tΓ©', b())"]
860 for i, cmd in enumerate(cmds, start=1):
862 for i, cmd in enumerate(cmds, start=1):
861 _ip.history_manager.store_inputs(i, cmd)
863 _ip.history_manager.store_inputs(i, cmd)
862 with TemporaryDirectory() as td:
864 with TemporaryDirectory() as td:
863 outfile = os.path.join(td, "nb.ipynb")
865 outfile = os.path.join(td, "nb.ipynb")
864 _ip.run_line_magic("notebook", "%s" % outfile)
866 _ip.run_line_magic("notebook", "%s" % outfile)
865
867
866
868
867 class TestEnv(TestCase):
869 class TestEnv(TestCase):
868
870
869 def test_env(self):
871 def test_env(self):
870 env = _ip.run_line_magic("env", "")
872 env = _ip.run_line_magic("env", "")
871 self.assertTrue(isinstance(env, dict))
873 self.assertTrue(isinstance(env, dict))
872
874
873 def test_env_secret(self):
875 def test_env_secret(self):
874 env = _ip.run_line_magic("env", "")
876 env = _ip.run_line_magic("env", "")
875 hidden = "<hidden>"
877 hidden = "<hidden>"
876 with mock.patch.dict(
878 with mock.patch.dict(
877 os.environ,
879 os.environ,
878 {
880 {
879 "API_KEY": "abc123",
881 "API_KEY": "abc123",
880 "SECRET_THING": "ssshhh",
882 "SECRET_THING": "ssshhh",
881 "JUPYTER_TOKEN": "",
883 "JUPYTER_TOKEN": "",
882 "VAR": "abc"
884 "VAR": "abc"
883 }
885 }
884 ):
886 ):
885 env = _ip.run_line_magic("env", "")
887 env = _ip.run_line_magic("env", "")
886 assert env["API_KEY"] == hidden
888 assert env["API_KEY"] == hidden
887 assert env["SECRET_THING"] == hidden
889 assert env["SECRET_THING"] == hidden
888 assert env["JUPYTER_TOKEN"] == hidden
890 assert env["JUPYTER_TOKEN"] == hidden
889 assert env["VAR"] == "abc"
891 assert env["VAR"] == "abc"
890
892
891 def test_env_get_set_simple(self):
893 def test_env_get_set_simple(self):
892 env = _ip.run_line_magic("env", "var val1")
894 env = _ip.run_line_magic("env", "var val1")
893 self.assertEqual(env, None)
895 self.assertEqual(env, None)
894 self.assertEqual(os.environ["var"], "val1")
896 self.assertEqual(os.environ["var"], "val1")
895 self.assertEqual(_ip.run_line_magic("env", "var"), "val1")
897 self.assertEqual(_ip.run_line_magic("env", "var"), "val1")
896 env = _ip.run_line_magic("env", "var=val2")
898 env = _ip.run_line_magic("env", "var=val2")
897 self.assertEqual(env, None)
899 self.assertEqual(env, None)
898 self.assertEqual(os.environ['var'], 'val2')
900 self.assertEqual(os.environ['var'], 'val2')
899
901
900 def test_env_get_set_complex(self):
902 def test_env_get_set_complex(self):
901 env = _ip.run_line_magic("env", "var 'val1 '' 'val2")
903 env = _ip.run_line_magic("env", "var 'val1 '' 'val2")
902 self.assertEqual(env, None)
904 self.assertEqual(env, None)
903 self.assertEqual(os.environ['var'], "'val1 '' 'val2")
905 self.assertEqual(os.environ['var'], "'val1 '' 'val2")
904 self.assertEqual(_ip.run_line_magic("env", "var"), "'val1 '' 'val2")
906 self.assertEqual(_ip.run_line_magic("env", "var"), "'val1 '' 'val2")
905 env = _ip.run_line_magic("env", 'var=val2 val3="val4')
907 env = _ip.run_line_magic("env", 'var=val2 val3="val4')
906 self.assertEqual(env, None)
908 self.assertEqual(env, None)
907 self.assertEqual(os.environ['var'], 'val2 val3="val4')
909 self.assertEqual(os.environ['var'], 'val2 val3="val4')
908
910
909 def test_env_set_bad_input(self):
911 def test_env_set_bad_input(self):
910 self.assertRaises(UsageError, lambda: _ip.run_line_magic("set_env", "var"))
912 self.assertRaises(UsageError, lambda: _ip.run_line_magic("set_env", "var"))
911
913
912 def test_env_set_whitespace(self):
914 def test_env_set_whitespace(self):
913 self.assertRaises(UsageError, lambda: _ip.run_line_magic("env", "var A=B"))
915 self.assertRaises(UsageError, lambda: _ip.run_line_magic("env", "var A=B"))
914
916
915
917
916 class CellMagicTestCase(TestCase):
918 class CellMagicTestCase(TestCase):
917
919
918 def check_ident(self, magic):
920 def check_ident(self, magic):
919 # Manually called, we get the result
921 # Manually called, we get the result
920 out = _ip.run_cell_magic(magic, "a", "b")
922 out = _ip.run_cell_magic(magic, "a", "b")
921 assert out == ("a", "b")
923 assert out == ("a", "b")
922 # Via run_cell, it goes into the user's namespace via displayhook
924 # Via run_cell, it goes into the user's namespace via displayhook
923 _ip.run_cell("%%" + magic + " c\nd\n")
925 _ip.run_cell("%%" + magic + " c\nd\n")
924 assert _ip.user_ns["_"] == ("c", "d\n")
926 assert _ip.user_ns["_"] == ("c", "d\n")
925
927
926 def test_cell_magic_func_deco(self):
928 def test_cell_magic_func_deco(self):
927 "Cell magic using simple decorator"
929 "Cell magic using simple decorator"
928 @register_cell_magic
930 @register_cell_magic
929 def cellm(line, cell):
931 def cellm(line, cell):
930 return line, cell
932 return line, cell
931
933
932 self.check_ident('cellm')
934 self.check_ident('cellm')
933
935
934 def test_cell_magic_reg(self):
936 def test_cell_magic_reg(self):
935 "Cell magic manually registered"
937 "Cell magic manually registered"
936 def cellm(line, cell):
938 def cellm(line, cell):
937 return line, cell
939 return line, cell
938
940
939 _ip.register_magic_function(cellm, 'cell', 'cellm2')
941 _ip.register_magic_function(cellm, 'cell', 'cellm2')
940 self.check_ident('cellm2')
942 self.check_ident('cellm2')
941
943
942 def test_cell_magic_class(self):
944 def test_cell_magic_class(self):
943 "Cell magics declared via a class"
945 "Cell magics declared via a class"
944 @magics_class
946 @magics_class
945 class MyMagics(Magics):
947 class MyMagics(Magics):
946
948
947 @cell_magic
949 @cell_magic
948 def cellm3(self, line, cell):
950 def cellm3(self, line, cell):
949 return line, cell
951 return line, cell
950
952
951 _ip.register_magics(MyMagics)
953 _ip.register_magics(MyMagics)
952 self.check_ident('cellm3')
954 self.check_ident('cellm3')
953
955
954 def test_cell_magic_class2(self):
956 def test_cell_magic_class2(self):
955 "Cell magics declared via a class, #2"
957 "Cell magics declared via a class, #2"
956 @magics_class
958 @magics_class
957 class MyMagics2(Magics):
959 class MyMagics2(Magics):
958
960
959 @cell_magic('cellm4')
961 @cell_magic('cellm4')
960 def cellm33(self, line, cell):
962 def cellm33(self, line, cell):
961 return line, cell
963 return line, cell
962
964
963 _ip.register_magics(MyMagics2)
965 _ip.register_magics(MyMagics2)
964 self.check_ident('cellm4')
966 self.check_ident('cellm4')
965 # Check that nothing is registered as 'cellm33'
967 # Check that nothing is registered as 'cellm33'
966 c33 = _ip.find_cell_magic('cellm33')
968 c33 = _ip.find_cell_magic('cellm33')
967 assert c33 == None
969 assert c33 is None
968
970
969 def test_file():
971 def test_file():
970 """Basic %%writefile"""
972 """Basic %%writefile"""
971 ip = get_ipython()
973 ip = get_ipython()
972 with TemporaryDirectory() as td:
974 with TemporaryDirectory() as td:
973 fname = os.path.join(td, "file1")
975 fname = os.path.join(td, "file1")
974 ip.run_cell_magic(
976 ip.run_cell_magic(
975 "writefile",
977 "writefile",
976 fname,
978 fname,
977 "\n".join(
979 "\n".join(
978 [
980 [
979 "line1",
981 "line1",
980 "line2",
982 "line2",
981 ]
983 ]
982 ),
984 ),
983 )
985 )
984 s = Path(fname).read_text(encoding="utf-8")
986 s = Path(fname).read_text(encoding="utf-8")
985 assert "line1\n" in s
987 assert "line1\n" in s
986 assert "line2" in s
988 assert "line2" in s
987
989
988
990
989 @dec.skip_win32
991 @dec.skip_win32
990 def test_file_single_quote():
992 def test_file_single_quote():
991 """Basic %%writefile with embedded single quotes"""
993 """Basic %%writefile with embedded single quotes"""
992 ip = get_ipython()
994 ip = get_ipython()
993 with TemporaryDirectory() as td:
995 with TemporaryDirectory() as td:
994 fname = os.path.join(td, "'file1'")
996 fname = os.path.join(td, "'file1'")
995 ip.run_cell_magic(
997 ip.run_cell_magic(
996 "writefile",
998 "writefile",
997 fname,
999 fname,
998 "\n".join(
1000 "\n".join(
999 [
1001 [
1000 "line1",
1002 "line1",
1001 "line2",
1003 "line2",
1002 ]
1004 ]
1003 ),
1005 ),
1004 )
1006 )
1005 s = Path(fname).read_text(encoding="utf-8")
1007 s = Path(fname).read_text(encoding="utf-8")
1006 assert "line1\n" in s
1008 assert "line1\n" in s
1007 assert "line2" in s
1009 assert "line2" in s
1008
1010
1009
1011
1010 @dec.skip_win32
1012 @dec.skip_win32
1011 def test_file_double_quote():
1013 def test_file_double_quote():
1012 """Basic %%writefile with embedded double quotes"""
1014 """Basic %%writefile with embedded double quotes"""
1013 ip = get_ipython()
1015 ip = get_ipython()
1014 with TemporaryDirectory() as td:
1016 with TemporaryDirectory() as td:
1015 fname = os.path.join(td, '"file1"')
1017 fname = os.path.join(td, '"file1"')
1016 ip.run_cell_magic(
1018 ip.run_cell_magic(
1017 "writefile",
1019 "writefile",
1018 fname,
1020 fname,
1019 "\n".join(
1021 "\n".join(
1020 [
1022 [
1021 "line1",
1023 "line1",
1022 "line2",
1024 "line2",
1023 ]
1025 ]
1024 ),
1026 ),
1025 )
1027 )
1026 s = Path(fname).read_text(encoding="utf-8")
1028 s = Path(fname).read_text(encoding="utf-8")
1027 assert "line1\n" in s
1029 assert "line1\n" in s
1028 assert "line2" in s
1030 assert "line2" in s
1029
1031
1030
1032
1031 def test_file_var_expand():
1033 def test_file_var_expand():
1032 """%%writefile $filename"""
1034 """%%writefile $filename"""
1033 ip = get_ipython()
1035 ip = get_ipython()
1034 with TemporaryDirectory() as td:
1036 with TemporaryDirectory() as td:
1035 fname = os.path.join(td, "file1")
1037 fname = os.path.join(td, "file1")
1036 ip.user_ns["filename"] = fname
1038 ip.user_ns["filename"] = fname
1037 ip.run_cell_magic(
1039 ip.run_cell_magic(
1038 "writefile",
1040 "writefile",
1039 "$filename",
1041 "$filename",
1040 "\n".join(
1042 "\n".join(
1041 [
1043 [
1042 "line1",
1044 "line1",
1043 "line2",
1045 "line2",
1044 ]
1046 ]
1045 ),
1047 ),
1046 )
1048 )
1047 s = Path(fname).read_text(encoding="utf-8")
1049 s = Path(fname).read_text(encoding="utf-8")
1048 assert "line1\n" in s
1050 assert "line1\n" in s
1049 assert "line2" in s
1051 assert "line2" in s
1050
1052
1051
1053
1052 def test_file_unicode():
1054 def test_file_unicode():
1053 """%%writefile with unicode cell"""
1055 """%%writefile with unicode cell"""
1054 ip = get_ipython()
1056 ip = get_ipython()
1055 with TemporaryDirectory() as td:
1057 with TemporaryDirectory() as td:
1056 fname = os.path.join(td, 'file1')
1058 fname = os.path.join(td, 'file1')
1057 ip.run_cell_magic("writefile", fname, u'\n'.join([
1059 ip.run_cell_magic("writefile", fname, u'\n'.join([
1058 u'linΓ©1',
1060 u'linΓ©1',
1059 u'linΓ©2',
1061 u'linΓ©2',
1060 ]))
1062 ]))
1061 with io.open(fname, encoding='utf-8') as f:
1063 with io.open(fname, encoding='utf-8') as f:
1062 s = f.read()
1064 s = f.read()
1063 assert "linΓ©1\n" in s
1065 assert "linΓ©1\n" in s
1064 assert "linΓ©2" in s
1066 assert "linΓ©2" in s
1065
1067
1066
1068
1067 def test_file_amend():
1069 def test_file_amend():
1068 """%%writefile -a amends files"""
1070 """%%writefile -a amends files"""
1069 ip = get_ipython()
1071 ip = get_ipython()
1070 with TemporaryDirectory() as td:
1072 with TemporaryDirectory() as td:
1071 fname = os.path.join(td, "file2")
1073 fname = os.path.join(td, "file2")
1072 ip.run_cell_magic(
1074 ip.run_cell_magic(
1073 "writefile",
1075 "writefile",
1074 fname,
1076 fname,
1075 "\n".join(
1077 "\n".join(
1076 [
1078 [
1077 "line1",
1079 "line1",
1078 "line2",
1080 "line2",
1079 ]
1081 ]
1080 ),
1082 ),
1081 )
1083 )
1082 ip.run_cell_magic(
1084 ip.run_cell_magic(
1083 "writefile",
1085 "writefile",
1084 "-a %s" % fname,
1086 "-a %s" % fname,
1085 "\n".join(
1087 "\n".join(
1086 [
1088 [
1087 "line3",
1089 "line3",
1088 "line4",
1090 "line4",
1089 ]
1091 ]
1090 ),
1092 ),
1091 )
1093 )
1092 s = Path(fname).read_text(encoding="utf-8")
1094 s = Path(fname).read_text(encoding="utf-8")
1093 assert "line1\n" in s
1095 assert "line1\n" in s
1094 assert "line3\n" in s
1096 assert "line3\n" in s
1095
1097
1096
1098
1097 def test_file_spaces():
1099 def test_file_spaces():
1098 """%%file with spaces in filename"""
1100 """%%file with spaces in filename"""
1099 ip = get_ipython()
1101 ip = get_ipython()
1100 with TemporaryWorkingDirectory() as td:
1102 with TemporaryWorkingDirectory():
1101 fname = "file name"
1103 fname = "file name"
1102 ip.run_cell_magic(
1104 ip.run_cell_magic(
1103 "file",
1105 "file",
1104 '"%s"' % fname,
1106 '"%s"' % fname,
1105 "\n".join(
1107 "\n".join(
1106 [
1108 [
1107 "line1",
1109 "line1",
1108 "line2",
1110 "line2",
1109 ]
1111 ]
1110 ),
1112 ),
1111 )
1113 )
1112 s = Path(fname).read_text(encoding="utf-8")
1114 s = Path(fname).read_text(encoding="utf-8")
1113 assert "line1\n" in s
1115 assert "line1\n" in s
1114 assert "line2" in s
1116 assert "line2" in s
1115
1117
1116
1118
1117 def test_script_config():
1119 def test_script_config():
1118 ip = get_ipython()
1120 ip = get_ipython()
1119 ip.config.ScriptMagics.script_magics = ['whoda']
1121 ip.config.ScriptMagics.script_magics = ['whoda']
1120 sm = script.ScriptMagics(shell=ip)
1122 sm = script.ScriptMagics(shell=ip)
1121 assert "whoda" in sm.magics["cell"]
1123 assert "whoda" in sm.magics["cell"]
1122
1124
1123
1125
1124 def test_script_out():
1126 def test_script_out():
1125 ip = get_ipython()
1127 ip = get_ipython()
1126 ip.run_cell_magic("script", f"--out output {sys.executable}", "print('hi')")
1128 ip.run_cell_magic("script", f"--out output {sys.executable}", "print('hi')")
1127 assert ip.user_ns["output"].strip() == "hi"
1129 assert ip.user_ns["output"].strip() == "hi"
1128
1130
1129
1131
1130 def test_script_err():
1132 def test_script_err():
1131 ip = get_ipython()
1133 ip = get_ipython()
1132 ip.run_cell_magic(
1134 ip.run_cell_magic(
1133 "script",
1135 "script",
1134 f"--err error {sys.executable}",
1136 f"--err error {sys.executable}",
1135 "import sys; print('hello', file=sys.stderr)",
1137 "import sys; print('hello', file=sys.stderr)",
1136 )
1138 )
1137 assert ip.user_ns["error"].strip() == "hello"
1139 assert ip.user_ns["error"].strip() == "hello"
1138
1140
1139
1141
1140 def test_script_out_err():
1142 def test_script_out_err():
1141 ip = get_ipython()
1143 ip = get_ipython()
1142 ip.run_cell_magic(
1144 ip.run_cell_magic(
1143 "script",
1145 "script",
1144 f"--out output --err error {sys.executable}",
1146 f"--out output --err error {sys.executable}",
1145 "\n".join(
1147 "\n".join(
1146 [
1148 [
1147 "import sys",
1149 "import sys",
1148 "print('hi')",
1150 "print('hi')",
1149 "print('hello', file=sys.stderr)",
1151 "print('hello', file=sys.stderr)",
1150 ]
1152 ]
1151 ),
1153 ),
1152 )
1154 )
1153 assert ip.user_ns["output"].strip() == "hi"
1155 assert ip.user_ns["output"].strip() == "hi"
1154 assert ip.user_ns["error"].strip() == "hello"
1156 assert ip.user_ns["error"].strip() == "hello"
1155
1157
1156
1158
1157 async def test_script_bg_out():
1159 async def test_script_bg_out():
1158 ip = get_ipython()
1160 ip = get_ipython()
1159 ip.run_cell_magic("script", f"--bg --out output {sys.executable}", "print('hi')")
1161 ip.run_cell_magic("script", f"--bg --out output {sys.executable}", "print('hi')")
1160 assert (await ip.user_ns["output"].read()).strip() == b"hi"
1162 assert (await ip.user_ns["output"].read()).strip() == b"hi"
1161 assert ip.user_ns["output"].at_eof()
1163 assert ip.user_ns["output"].at_eof()
1162
1164
1163
1165
1164 async def test_script_bg_err():
1166 async def test_script_bg_err():
1165 ip = get_ipython()
1167 ip = get_ipython()
1166 ip.run_cell_magic(
1168 ip.run_cell_magic(
1167 "script",
1169 "script",
1168 f"--bg --err error {sys.executable}",
1170 f"--bg --err error {sys.executable}",
1169 "import sys; print('hello', file=sys.stderr)",
1171 "import sys; print('hello', file=sys.stderr)",
1170 )
1172 )
1171 assert (await ip.user_ns["error"].read()).strip() == b"hello"
1173 assert (await ip.user_ns["error"].read()).strip() == b"hello"
1172 assert ip.user_ns["error"].at_eof()
1174 assert ip.user_ns["error"].at_eof()
1173
1175
1174
1176
1175 async def test_script_bg_out_err():
1177 async def test_script_bg_out_err():
1176 ip = get_ipython()
1178 ip = get_ipython()
1177 ip.run_cell_magic(
1179 ip.run_cell_magic(
1178 "script",
1180 "script",
1179 f"--bg --out output --err error {sys.executable}",
1181 f"--bg --out output --err error {sys.executable}",
1180 "\n".join(
1182 "\n".join(
1181 [
1183 [
1182 "import sys",
1184 "import sys",
1183 "print('hi')",
1185 "print('hi')",
1184 "print('hello', file=sys.stderr)",
1186 "print('hello', file=sys.stderr)",
1185 ]
1187 ]
1186 ),
1188 ),
1187 )
1189 )
1188 assert (await ip.user_ns["output"].read()).strip() == b"hi"
1190 assert (await ip.user_ns["output"].read()).strip() == b"hi"
1189 assert (await ip.user_ns["error"].read()).strip() == b"hello"
1191 assert (await ip.user_ns["error"].read()).strip() == b"hello"
1190 assert ip.user_ns["output"].at_eof()
1192 assert ip.user_ns["output"].at_eof()
1191 assert ip.user_ns["error"].at_eof()
1193 assert ip.user_ns["error"].at_eof()
1192
1194
1193
1195
1194 async def test_script_bg_proc():
1196 async def test_script_bg_proc():
1195 ip = get_ipython()
1197 ip = get_ipython()
1196 ip.run_cell_magic(
1198 ip.run_cell_magic(
1197 "script",
1199 "script",
1198 f"--bg --out output --proc p {sys.executable}",
1200 f"--bg --out output --proc p {sys.executable}",
1199 "\n".join(
1201 "\n".join(
1200 [
1202 [
1201 "import sys",
1203 "import sys",
1202 "print('hi')",
1204 "print('hi')",
1203 "print('hello', file=sys.stderr)",
1205 "print('hello', file=sys.stderr)",
1204 ]
1206 ]
1205 ),
1207 ),
1206 )
1208 )
1207 p = ip.user_ns["p"]
1209 p = ip.user_ns["p"]
1208 await p.wait()
1210 await p.wait()
1209 assert p.returncode == 0
1211 assert p.returncode == 0
1210 assert (await p.stdout.read()).strip() == b"hi"
1212 assert (await p.stdout.read()).strip() == b"hi"
1211 # not captured, so empty
1213 # not captured, so empty
1212 assert (await p.stderr.read()) == b""
1214 assert (await p.stderr.read()) == b""
1213 assert p.stdout.at_eof()
1215 assert p.stdout.at_eof()
1214 assert p.stderr.at_eof()
1216 assert p.stderr.at_eof()
1215
1217
1216
1218
1217 def test_script_defaults():
1219 def test_script_defaults():
1218 ip = get_ipython()
1220 ip = get_ipython()
1219 for cmd in ['sh', 'bash', 'perl', 'ruby']:
1221 for cmd in ['sh', 'bash', 'perl', 'ruby']:
1220 try:
1222 try:
1221 find_cmd(cmd)
1223 find_cmd(cmd)
1222 except Exception:
1224 except Exception:
1223 pass
1225 pass
1224 else:
1226 else:
1225 assert cmd in ip.magics_manager.magics["cell"]
1227 assert cmd in ip.magics_manager.magics["cell"]
1226
1228
1227
1229
1228 @magics_class
1230 @magics_class
1229 class FooFoo(Magics):
1231 class FooFoo(Magics):
1230 """class with both %foo and %%foo magics"""
1232 """class with both %foo and %%foo magics"""
1231 @line_magic('foo')
1233 @line_magic('foo')
1232 def line_foo(self, line):
1234 def line_foo(self, line):
1233 "I am line foo"
1235 "I am line foo"
1234 pass
1236 pass
1235
1237
1236 @cell_magic("foo")
1238 @cell_magic("foo")
1237 def cell_foo(self, line, cell):
1239 def cell_foo(self, line, cell):
1238 "I am cell foo, not line foo"
1240 "I am cell foo, not line foo"
1239 pass
1241 pass
1240
1242
1241 def test_line_cell_info():
1243 def test_line_cell_info():
1242 """%%foo and %foo magics are distinguishable to inspect"""
1244 """%%foo and %foo magics are distinguishable to inspect"""
1243 ip = get_ipython()
1245 ip = get_ipython()
1244 ip.magics_manager.register(FooFoo)
1246 ip.magics_manager.register(FooFoo)
1245 oinfo = ip.object_inspect("foo")
1247 oinfo = ip.object_inspect("foo")
1246 assert oinfo["found"] is True
1248 assert oinfo["found"] is True
1247 assert oinfo["ismagic"] is True
1249 assert oinfo["ismagic"] is True
1248
1250
1249 oinfo = ip.object_inspect("%%foo")
1251 oinfo = ip.object_inspect("%%foo")
1250 assert oinfo["found"] is True
1252 assert oinfo["found"] is True
1251 assert oinfo["ismagic"] is True
1253 assert oinfo["ismagic"] is True
1252 assert oinfo["docstring"] == FooFoo.cell_foo.__doc__
1254 assert oinfo["docstring"] == FooFoo.cell_foo.__doc__
1253
1255
1254 oinfo = ip.object_inspect("%foo")
1256 oinfo = ip.object_inspect("%foo")
1255 assert oinfo["found"] is True
1257 assert oinfo["found"] is True
1256 assert oinfo["ismagic"] is True
1258 assert oinfo["ismagic"] is True
1257 assert oinfo["docstring"] == FooFoo.line_foo.__doc__
1259 assert oinfo["docstring"] == FooFoo.line_foo.__doc__
1258
1260
1259
1261
1260 def test_multiple_magics():
1262 def test_multiple_magics():
1261 ip = get_ipython()
1263 ip = get_ipython()
1262 foo1 = FooFoo(ip)
1264 foo1 = FooFoo(ip)
1263 foo2 = FooFoo(ip)
1265 foo2 = FooFoo(ip)
1264 mm = ip.magics_manager
1266 mm = ip.magics_manager
1265 mm.register(foo1)
1267 mm.register(foo1)
1266 assert mm.magics["line"]["foo"].__self__ is foo1
1268 assert mm.magics["line"]["foo"].__self__ is foo1
1267 mm.register(foo2)
1269 mm.register(foo2)
1268 assert mm.magics["line"]["foo"].__self__ is foo2
1270 assert mm.magics["line"]["foo"].__self__ is foo2
1269
1271
1270
1272
1271 def test_alias_magic():
1273 def test_alias_magic():
1272 """Test %alias_magic."""
1274 """Test %alias_magic."""
1273 ip = get_ipython()
1275 ip = get_ipython()
1274 mm = ip.magics_manager
1276 mm = ip.magics_manager
1275
1277
1276 # Basic operation: both cell and line magics are created, if possible.
1278 # Basic operation: both cell and line magics are created, if possible.
1277 ip.run_line_magic("alias_magic", "timeit_alias timeit")
1279 ip.run_line_magic("alias_magic", "timeit_alias timeit")
1278 assert "timeit_alias" in mm.magics["line"]
1280 assert "timeit_alias" in mm.magics["line"]
1279 assert "timeit_alias" in mm.magics["cell"]
1281 assert "timeit_alias" in mm.magics["cell"]
1280
1282
1281 # --cell is specified, line magic not created.
1283 # --cell is specified, line magic not created.
1282 ip.run_line_magic("alias_magic", "--cell timeit_cell_alias timeit")
1284 ip.run_line_magic("alias_magic", "--cell timeit_cell_alias timeit")
1283 assert "timeit_cell_alias" not in mm.magics["line"]
1285 assert "timeit_cell_alias" not in mm.magics["line"]
1284 assert "timeit_cell_alias" in mm.magics["cell"]
1286 assert "timeit_cell_alias" in mm.magics["cell"]
1285
1287
1286 # Test that line alias is created successfully.
1288 # Test that line alias is created successfully.
1287 ip.run_line_magic("alias_magic", "--line env_alias env")
1289 ip.run_line_magic("alias_magic", "--line env_alias env")
1288 assert ip.run_line_magic("env", "") == ip.run_line_magic("env_alias", "")
1290 assert ip.run_line_magic("env", "") == ip.run_line_magic("env_alias", "")
1289
1291
1290 # Test that line alias with parameters passed in is created successfully.
1292 # Test that line alias with parameters passed in is created successfully.
1291 ip.run_line_magic(
1293 ip.run_line_magic(
1292 "alias_magic", "--line history_alias history --params " + shlex.quote("3")
1294 "alias_magic", "--line history_alias history --params " + shlex.quote("3")
1293 )
1295 )
1294 assert "history_alias" in mm.magics["line"]
1296 assert "history_alias" in mm.magics["line"]
1295
1297
1296
1298
1297 def test_save():
1299 def test_save():
1298 """Test %save."""
1300 """Test %save."""
1299 ip = get_ipython()
1301 ip = get_ipython()
1300 ip.history_manager.reset() # Clear any existing history.
1302 ip.history_manager.reset() # Clear any existing history.
1301 cmds = ["a=1", "def b():\n return a**2", "print(a, b())"]
1303 cmds = ["a=1", "def b():\n return a**2", "print(a, b())"]
1302 for i, cmd in enumerate(cmds, start=1):
1304 for i, cmd in enumerate(cmds, start=1):
1303 ip.history_manager.store_inputs(i, cmd)
1305 ip.history_manager.store_inputs(i, cmd)
1304 with TemporaryDirectory() as tmpdir:
1306 with TemporaryDirectory() as tmpdir:
1305 file = os.path.join(tmpdir, "testsave.py")
1307 file = os.path.join(tmpdir, "testsave.py")
1306 ip.run_line_magic("save", "%s 1-10" % file)
1308 ip.run_line_magic("save", "%s 1-10" % file)
1307 content = Path(file).read_text(encoding="utf-8")
1309 content = Path(file).read_text(encoding="utf-8")
1308 assert content.count(cmds[0]) == 1
1310 assert content.count(cmds[0]) == 1
1309 assert "coding: utf-8" in content
1311 assert "coding: utf-8" in content
1310 ip.run_line_magic("save", "-a %s 1-10" % file)
1312 ip.run_line_magic("save", "-a %s 1-10" % file)
1311 content = Path(file).read_text(encoding="utf-8")
1313 content = Path(file).read_text(encoding="utf-8")
1312 assert content.count(cmds[0]) == 2
1314 assert content.count(cmds[0]) == 2
1313 assert "coding: utf-8" in content
1315 assert "coding: utf-8" in content
1314
1316
1315
1317
1316 def test_save_with_no_args():
1318 def test_save_with_no_args():
1317 ip = get_ipython()
1319 ip = get_ipython()
1318 ip.history_manager.reset() # Clear any existing history.
1320 ip.history_manager.reset() # Clear any existing history.
1319 cmds = ["a=1", "def b():\n return a**2", "print(a, b())", "%save"]
1321 cmds = ["a=1", "def b():\n return a**2", "print(a, b())", "%save"]
1320 for i, cmd in enumerate(cmds, start=1):
1322 for i, cmd in enumerate(cmds, start=1):
1321 ip.history_manager.store_inputs(i, cmd)
1323 ip.history_manager.store_inputs(i, cmd)
1322
1324
1323 with TemporaryDirectory() as tmpdir:
1325 with TemporaryDirectory() as tmpdir:
1324 path = os.path.join(tmpdir, "testsave.py")
1326 path = os.path.join(tmpdir, "testsave.py")
1325 ip.run_line_magic("save", path)
1327 ip.run_line_magic("save", path)
1326 content = Path(path).read_text(encoding="utf-8")
1328 content = Path(path).read_text(encoding="utf-8")
1327 expected_content = dedent(
1329 expected_content = dedent(
1328 """\
1330 """\
1329 # coding: utf-8
1331 # coding: utf-8
1330 a=1
1332 a=1
1331 def b():
1333 def b():
1332 return a**2
1334 return a**2
1333 print(a, b())
1335 print(a, b())
1334 """
1336 """
1335 )
1337 )
1336 assert content == expected_content
1338 assert content == expected_content
1337
1339
1338
1340
1339 def test_store():
1341 def test_store():
1340 """Test %store."""
1342 """Test %store."""
1341 ip = get_ipython()
1343 ip = get_ipython()
1342 ip.run_line_magic('load_ext', 'storemagic')
1344 ip.run_line_magic('load_ext', 'storemagic')
1343
1345
1344 # make sure the storage is empty
1346 # make sure the storage is empty
1345 ip.run_line_magic("store", "-z")
1347 ip.run_line_magic("store", "-z")
1346 ip.user_ns["var"] = 42
1348 ip.user_ns["var"] = 42
1347 ip.run_line_magic("store", "var")
1349 ip.run_line_magic("store", "var")
1348 ip.user_ns["var"] = 39
1350 ip.user_ns["var"] = 39
1349 ip.run_line_magic("store", "-r")
1351 ip.run_line_magic("store", "-r")
1350 assert ip.user_ns["var"] == 42
1352 assert ip.user_ns["var"] == 42
1351
1353
1352 ip.run_line_magic("store", "-d var")
1354 ip.run_line_magic("store", "-d var")
1353 ip.user_ns["var"] = 39
1355 ip.user_ns["var"] = 39
1354 ip.run_line_magic("store", "-r")
1356 ip.run_line_magic("store", "-r")
1355 assert ip.user_ns["var"] == 39
1357 assert ip.user_ns["var"] == 39
1356
1358
1357
1359
1358 def _run_edit_test(arg_s, exp_filename=None,
1360 def _run_edit_test(arg_s, exp_filename=None,
1359 exp_lineno=-1,
1361 exp_lineno=-1,
1360 exp_contents=None,
1362 exp_contents=None,
1361 exp_is_temp=None):
1363 exp_is_temp=None):
1362 ip = get_ipython()
1364 ip = get_ipython()
1363 M = code.CodeMagics(ip)
1365 M = code.CodeMagics(ip)
1364 last_call = ['','']
1366 last_call = ['','']
1365 opts,args = M.parse_options(arg_s,'prxn:')
1367 opts,args = M.parse_options(arg_s,'prxn:')
1366 filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call)
1368 filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call)
1367
1369
1368 if exp_filename is not None:
1370 if exp_filename is not None:
1369 assert exp_filename == filename
1371 assert exp_filename == filename
1370 if exp_contents is not None:
1372 if exp_contents is not None:
1371 with io.open(filename, 'r', encoding='utf-8') as f:
1373 with io.open(filename, 'r', encoding='utf-8') as f:
1372 contents = f.read()
1374 contents = f.read()
1373 assert exp_contents == contents
1375 assert exp_contents == contents
1374 if exp_lineno != -1:
1376 if exp_lineno != -1:
1375 assert exp_lineno == lineno
1377 assert exp_lineno == lineno
1376 if exp_is_temp is not None:
1378 if exp_is_temp is not None:
1377 assert exp_is_temp == is_temp
1379 assert exp_is_temp == is_temp
1378
1380
1379
1381
1380 def test_edit_interactive():
1382 def test_edit_interactive():
1381 """%edit on interactively defined objects"""
1383 """%edit on interactively defined objects"""
1382 ip = get_ipython()
1384 ip = get_ipython()
1383 n = ip.execution_count
1385 n = ip.execution_count
1384 ip.run_cell("def foo(): return 1", store_history=True)
1386 ip.run_cell("def foo(): return 1", store_history=True)
1385
1387
1386 with pytest.raises(code.InteractivelyDefined) as e:
1388 with pytest.raises(code.InteractivelyDefined) as e:
1387 _run_edit_test("foo")
1389 _run_edit_test("foo")
1388 assert e.value.index == n
1390 assert e.value.index == n
1389
1391
1390
1392
1391 def test_edit_cell():
1393 def test_edit_cell():
1392 """%edit [cell id]"""
1394 """%edit [cell id]"""
1393 ip = get_ipython()
1395 ip = get_ipython()
1394
1396
1395 ip.run_cell("def foo(): return 1", store_history=True)
1397 ip.run_cell("def foo(): return 1", store_history=True)
1396
1398
1397 # test
1399 # test
1398 _run_edit_test("1", exp_contents=ip.user_ns['In'][1], exp_is_temp=True)
1400 _run_edit_test("1", exp_contents=ip.user_ns['In'][1], exp_is_temp=True)
1399
1401
1400 def test_edit_fname():
1402 def test_edit_fname():
1401 """%edit file"""
1403 """%edit file"""
1402 # test
1404 # test
1403 _run_edit_test("test file.py", exp_filename="test file.py")
1405 _run_edit_test("test file.py", exp_filename="test file.py")
1404
1406
1405 def test_bookmark():
1407 def test_bookmark():
1406 ip = get_ipython()
1408 ip = get_ipython()
1407 ip.run_line_magic('bookmark', 'bmname')
1409 ip.run_line_magic('bookmark', 'bmname')
1408 with tt.AssertPrints('bmname'):
1410 with tt.AssertPrints('bmname'):
1409 ip.run_line_magic('bookmark', '-l')
1411 ip.run_line_magic('bookmark', '-l')
1410 ip.run_line_magic('bookmark', '-d bmname')
1412 ip.run_line_magic('bookmark', '-d bmname')
1411
1413
1412 def test_ls_magic():
1414 def test_ls_magic():
1413 ip = get_ipython()
1415 ip = get_ipython()
1414 json_formatter = ip.display_formatter.formatters['application/json']
1416 json_formatter = ip.display_formatter.formatters['application/json']
1415 json_formatter.enabled = True
1417 json_formatter.enabled = True
1416 lsmagic = ip.run_line_magic("lsmagic", "")
1418 lsmagic = ip.run_line_magic("lsmagic", "")
1417 with warnings.catch_warnings(record=True) as w:
1419 with warnings.catch_warnings(record=True) as w:
1418 j = json_formatter(lsmagic)
1420 j = json_formatter(lsmagic)
1419 assert sorted(j) == ["cell", "line"]
1421 assert sorted(j) == ["cell", "line"]
1420 assert w == [] # no warnings
1422 assert w == [] # no warnings
1421
1423
1422
1424
1423 def test_strip_initial_indent():
1425 def test_strip_initial_indent():
1424 def sii(s):
1426 def sii(s):
1425 lines = s.splitlines()
1427 lines = s.splitlines()
1426 return '\n'.join(code.strip_initial_indent(lines))
1428 return '\n'.join(code.strip_initial_indent(lines))
1427
1429
1428 assert sii(" a = 1\nb = 2") == "a = 1\nb = 2"
1430 assert sii(" a = 1\nb = 2") == "a = 1\nb = 2"
1429 assert sii(" a\n b\nc") == "a\n b\nc"
1431 assert sii(" a\n b\nc") == "a\n b\nc"
1430 assert sii("a\n b") == "a\n b"
1432 assert sii("a\n b") == "a\n b"
1431
1433
1432 def test_logging_magic_quiet_from_arg():
1434 def test_logging_magic_quiet_from_arg():
1433 _ip.config.LoggingMagics.quiet = False
1435 _ip.config.LoggingMagics.quiet = False
1434 lm = logging.LoggingMagics(shell=_ip)
1436 lm = logging.LoggingMagics(shell=_ip)
1435 with TemporaryDirectory() as td:
1437 with TemporaryDirectory() as td:
1436 try:
1438 try:
1437 with tt.AssertNotPrints(re.compile("Activating.*")):
1439 with tt.AssertNotPrints(re.compile("Activating.*")):
1438 lm.logstart('-q {}'.format(
1440 lm.logstart('-q {}'.format(
1439 os.path.join(td, "quiet_from_arg.log")))
1441 os.path.join(td, "quiet_from_arg.log")))
1440 finally:
1442 finally:
1441 _ip.logger.logstop()
1443 _ip.logger.logstop()
1442
1444
1443 def test_logging_magic_quiet_from_config():
1445 def test_logging_magic_quiet_from_config():
1444 _ip.config.LoggingMagics.quiet = True
1446 _ip.config.LoggingMagics.quiet = True
1445 lm = logging.LoggingMagics(shell=_ip)
1447 lm = logging.LoggingMagics(shell=_ip)
1446 with TemporaryDirectory() as td:
1448 with TemporaryDirectory() as td:
1447 try:
1449 try:
1448 with tt.AssertNotPrints(re.compile("Activating.*")):
1450 with tt.AssertNotPrints(re.compile("Activating.*")):
1449 lm.logstart(os.path.join(td, "quiet_from_config.log"))
1451 lm.logstart(os.path.join(td, "quiet_from_config.log"))
1450 finally:
1452 finally:
1451 _ip.logger.logstop()
1453 _ip.logger.logstop()
1452
1454
1453
1455
1454 def test_logging_magic_not_quiet():
1456 def test_logging_magic_not_quiet():
1455 _ip.config.LoggingMagics.quiet = False
1457 _ip.config.LoggingMagics.quiet = False
1456 lm = logging.LoggingMagics(shell=_ip)
1458 lm = logging.LoggingMagics(shell=_ip)
1457 with TemporaryDirectory() as td:
1459 with TemporaryDirectory() as td:
1458 try:
1460 try:
1459 with tt.AssertPrints(re.compile("Activating.*")):
1461 with tt.AssertPrints(re.compile("Activating.*")):
1460 lm.logstart(os.path.join(td, "not_quiet.log"))
1462 lm.logstart(os.path.join(td, "not_quiet.log"))
1461 finally:
1463 finally:
1462 _ip.logger.logstop()
1464 _ip.logger.logstop()
1463
1465
1464
1466
1465 def test_time_no_var_expand():
1467 def test_time_no_var_expand():
1466 _ip.user_ns["a"] = 5
1468 _ip.user_ns["a"] = 5
1467 _ip.user_ns["b"] = []
1469 _ip.user_ns["b"] = []
1468 _ip.run_line_magic("time", 'b.append("{a}")')
1470 _ip.run_line_magic("time", 'b.append("{a}")')
1469 assert _ip.user_ns["b"] == ["{a}"]
1471 assert _ip.user_ns["b"] == ["{a}"]
1470
1472
1471
1473
1472 # this is slow, put at the end for local testing.
1474 # this is slow, put at the end for local testing.
1473 def test_timeit_arguments():
1475 def test_timeit_arguments():
1474 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
1476 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
1475 _ip.run_line_magic("timeit", "-n1 -r1 a=('#')")
1477 _ip.run_line_magic("timeit", "-n1 -r1 a=('#')")
1476
1478
1477
1479
1478 MINIMAL_LAZY_MAGIC = """
1480 MINIMAL_LAZY_MAGIC = """
1479 from IPython.core.magic import (
1481 from IPython.core.magic import (
1480 Magics,
1482 Magics,
1481 magics_class,
1483 magics_class,
1482 line_magic,
1484 line_magic,
1483 cell_magic,
1485 cell_magic,
1484 )
1486 )
1485
1487
1486
1488
1487 @magics_class
1489 @magics_class
1488 class LazyMagics(Magics):
1490 class LazyMagics(Magics):
1489 @line_magic
1491 @line_magic
1490 def lazy_line(self, line):
1492 def lazy_line(self, line):
1491 print("Lazy Line")
1493 print("Lazy Line")
1492
1494
1493 @cell_magic
1495 @cell_magic
1494 def lazy_cell(self, line, cell):
1496 def lazy_cell(self, line, cell):
1495 print("Lazy Cell")
1497 print("Lazy Cell")
1496
1498
1497
1499
1498 def load_ipython_extension(ipython):
1500 def load_ipython_extension(ipython):
1499 ipython.register_magics(LazyMagics)
1501 ipython.register_magics(LazyMagics)
1500 """
1502 """
1501
1503
1502
1504
1503 def test_lazy_magics():
1505 def test_lazy_magics():
1504 with pytest.raises(UsageError):
1506 with pytest.raises(UsageError):
1505 ip.run_line_magic("lazy_line", "")
1507 _ip.run_line_magic("lazy_line", "")
1506
1507 startdir = os.getcwd()
1508
1508
1509 with TemporaryDirectory() as tmpdir:
1509 with TemporaryDirectory() as tmpdir:
1510 with prepended_to_syspath(tmpdir):
1510 with prepended_to_syspath(tmpdir):
1511 ptempdir = Path(tmpdir)
1511 ptempdir = Path(tmpdir)
1512 tf = ptempdir / "lazy_magic_module.py"
1512 tf = ptempdir / "lazy_magic_module.py"
1513 tf.write_text(MINIMAL_LAZY_MAGIC)
1513 tf.write_text(MINIMAL_LAZY_MAGIC)
1514 ip.magics_manager.register_lazy("lazy_line", Path(tf.name).name[:-3])
1514 _ip.magics_manager.register_lazy("lazy_line", Path(tf.name).name[:-3])
1515 with tt.AssertPrints("Lazy Line"):
1515 with tt.AssertPrints("Lazy Line"):
1516 ip.run_line_magic("lazy_line", "")
1516 _ip.run_line_magic("lazy_line", "")
1517
1517
1518
1518
1519 TEST_MODULE = """
1519 TEST_MODULE = """
1520 print('Loaded my_tmp')
1520 print('Loaded my_tmp')
1521 if __name__ == "__main__":
1521 if __name__ == "__main__":
1522 print('I just ran a script')
1522 print('I just ran a script')
1523 """
1523 """
1524
1524
1525 def test_run_module_from_import_hook():
1525 def test_run_module_from_import_hook():
1526 "Test that a module can be loaded via an import hook"
1526 "Test that a module can be loaded via an import hook"
1527 with TemporaryDirectory() as tmpdir:
1527 with TemporaryDirectory() as tmpdir:
1528 fullpath = os.path.join(tmpdir, "my_tmp.py")
1528 fullpath = os.path.join(tmpdir, "my_tmp.py")
1529 Path(fullpath).write_text(TEST_MODULE, encoding="utf-8")
1529 Path(fullpath).write_text(TEST_MODULE, encoding="utf-8")
1530
1530
1531 import importlib.abc
1531 import importlib.abc
1532 import importlib.util
1532 import importlib.util
1533
1533
1534 class MyTempImporter(importlib.abc.MetaPathFinder, importlib.abc.SourceLoader):
1534 class MyTempImporter(importlib.abc.MetaPathFinder, importlib.abc.SourceLoader):
1535 def find_spec(self, fullname, path, target=None):
1535 def find_spec(self, fullname, path, target=None):
1536 if fullname == "my_tmp":
1536 if fullname == "my_tmp":
1537 return importlib.util.spec_from_loader(fullname, self)
1537 return importlib.util.spec_from_loader(fullname, self)
1538
1538
1539 def get_filename(self, fullname):
1539 def get_filename(self, fullname):
1540 assert fullname == "my_tmp"
1540 assert fullname == "my_tmp"
1541 return fullpath
1541 return fullpath
1542
1542
1543 def get_data(self, path):
1543 def get_data(self, path):
1544 assert Path(path).samefile(fullpath)
1544 assert Path(path).samefile(fullpath)
1545 return Path(fullpath).read_text(encoding="utf-8")
1545 return Path(fullpath).read_text(encoding="utf-8")
1546
1546
1547 sys.meta_path.insert(0, MyTempImporter())
1547 sys.meta_path.insert(0, MyTempImporter())
1548
1548
1549 with capture_output() as captured:
1549 with capture_output() as captured:
1550 _ip.run_line_magic("run", "-m my_tmp")
1550 _ip.run_line_magic("run", "-m my_tmp")
1551 _ip.run_cell("import my_tmp")
1551 _ip.run_cell("import my_tmp")
1552
1552
1553 output = "Loaded my_tmp\nI just ran a script\nLoaded my_tmp\n"
1553 output = "Loaded my_tmp\nI just ran a script\nLoaded my_tmp\n"
1554 assert output == captured.stdout
1554 assert output == captured.stdout
1555
1555
1556 sys.meta_path.pop(0)
1556 sys.meta_path.pop(0)
@@ -1,165 +1,166
1 """Define text roles for GitHub
1 """Define text roles for GitHub
2
2
3 * ghissue - Issue
3 * ghissue - Issue
4 * ghpull - Pull Request
4 * ghpull - Pull Request
5 * ghuser - User
5 * ghuser - User
6
6
7 Adapted from bitbucket example here:
7 Adapted from bitbucket example here:
8 https://bitbucket.org/birkenfeld/sphinx-contrib/src/tip/bitbucket/sphinxcontrib/bitbucket.py
8 https://bitbucket.org/birkenfeld/sphinx-contrib/src/tip/bitbucket/sphinxcontrib/bitbucket.py
9
9
10 Authors
10 Authors
11 -------
11 -------
12
12
13 * Doug Hellmann
13 * Doug Hellmann
14 * Min RK
14 * Min RK
15 """
15 """
16 #
16 #
17 # Original Copyright (c) 2010 Doug Hellmann. All rights reserved.
17 # Original Copyright (c) 2010 Doug Hellmann. All rights reserved.
18 #
18 #
19
19
20 from docutils import nodes, utils
20 from docutils import nodes, utils
21 from docutils.parsers.rst.roles import set_classes
21 from docutils.parsers.rst.roles import set_classes
22 from sphinx.util.logging import getLogger
22 from sphinx.util.logging import getLogger
23
23
24 info = getLogger(__name__).info
24 info = getLogger(__name__).info
25
25
26 def make_link_node(rawtext, app, type, slug, options):
26 def make_link_node(rawtext, app, type, slug, options):
27 """Create a link to a github resource.
27 """Create a link to a github resource.
28
28
29 :param rawtext: Text being replaced with link node.
29 :param rawtext: Text being replaced with link node.
30 :param app: Sphinx application context
30 :param app: Sphinx application context
31 :param type: Link type (issues, changeset, etc.)
31 :param type: Link type (issues, changeset, etc.)
32 :param slug: ID of the thing to link to
32 :param slug: ID of the thing to link to
33 :param options: Options dictionary passed to role func.
33 :param options: Options dictionary passed to role func.
34 """
34 """
35
35
36 try:
36 try:
37 base = app.config.github_project_url
37 base = app.config.github_project_url
38 if not base:
38 if not base:
39 raise AttributeError
39 raise AttributeError
40 if not base.endswith('/'):
40 if not base.endswith('/'):
41 base += '/'
41 base += '/'
42 except AttributeError as err:
42 except AttributeError as err:
43 raise ValueError('github_project_url configuration value is not set (%s)' % str(err)) from err
43 raise ValueError('github_project_url configuration value is not set (%s)' % str(err)) from err
44
44
45 ref = base + type + '/' + slug + '/'
45 ref = base + type + '/' + slug + '/'
46 set_classes(options)
46 set_classes(options)
47 prefix = "#"
47 prefix = "#"
48 if type == 'pull':
48 if type == 'pull':
49 prefix = "PR " + prefix
49 prefix = "PR " + prefix
50 node = nodes.reference(rawtext, prefix + utils.unescape(slug), refuri=ref,
50 node = nodes.reference(rawtext, prefix + utils.unescape(slug), refuri=ref,
51 **options)
51 **options)
52 return node
52 return node
53
53
54 def ghissue_role(name, rawtext, text, lineno, inliner, options=None, content=None):
54 def ghissue_role(name, rawtext, text, lineno, inliner, options=None, content=None):
55 """Link to a GitHub issue.
55 """Link to a GitHub issue.
56
56
57 Returns 2 part tuple containing list of nodes to insert into the
57 Returns 2 part tuple containing list of nodes to insert into the
58 document and a list of system messages. Both are allowed to be
58 document and a list of system messages. Both are allowed to be
59 empty.
59 empty.
60
60
61 :param name: The role name used in the document.
61 :param name: The role name used in the document.
62 :param rawtext: The entire markup snippet, with role.
62 :param rawtext: The entire markup snippet, with role.
63 :param text: The text marked with the role.
63 :param text: The text marked with the role.
64 :param lineno: The line number where rawtext appears in the input.
64 :param lineno: The line number where rawtext appears in the input.
65 :param inliner: The inliner instance that called us.
65 :param inliner: The inliner instance that called us.
66 :param options: Directive options for customization.
66 :param options: Directive options for customization.
67 :param content: The directive content for customization.
67 :param content: The directive content for customization.
68 """
68 """
69 if options is None:
69 if options is None:
70 options = {}
70 options = {}
71
71
72 try:
72 try:
73 issue_num = int(text)
73 issue_num = int(text)
74 if issue_num <= 0:
74 if issue_num <= 0:
75 raise ValueError
75 raise ValueError
76 except ValueError:
76 except ValueError:
77 msg = inliner.reporter.error(
77 msg = inliner.reporter.error(
78 'GitHub issue number must be a number greater than or equal to 1; '
78 'GitHub issue number must be a number greater than or equal to 1; '
79 '"%s" is invalid.' % text, line=lineno)
79 '"%s" is invalid.' % text, line=lineno)
80 prb = inliner.problematic(rawtext, rawtext, msg)
80 prb = inliner.problematic(rawtext, rawtext, msg)
81 return [prb], [msg]
81 return [prb], [msg]
82 #info('issue %r' % text)
82 #info('issue %r' % text)
83 if 'pull' in name.lower():
83 if 'pull' in name.lower():
84 category = 'pull'
84 category = 'pull'
85 elif 'issue' in name.lower():
85 elif 'issue' in name.lower():
86 category = 'issues'
86 category = 'issues'
87 else:
87 else:
88 msg = inliner.reporter.error(
88 msg = inliner.reporter.error(
89 'GitHub roles include "ghpull" and "ghissue", '
89 'GitHub roles include "ghpull" and "ghissue", '
90 '"%s" is invalid.' % name, line=lineno)
90 '"%s" is invalid.' % name, line=lineno)
91 prb = inliner.problematic(rawtext, rawtext, msg)
91 prb = inliner.problematic(rawtext, rawtext, msg)
92 return [prb], [msg]
92 return [prb], [msg]
93 app = inliner.document.settings.env.app
93 node = make_link_node(rawtext, app, category, str(issue_num), options)
94 node = make_link_node(rawtext, app, category, str(issue_num), options)
94 return [node], []
95 return [node], []
95
96
96 def ghuser_role(name, rawtext, text, lineno, inliner, options=None, content=None):
97 def ghuser_role(name, rawtext, text, lineno, inliner, options=None, content=None):
97 """Link to a GitHub user.
98 """Link to a GitHub user.
98
99
99 Returns 2 part tuple containing list of nodes to insert into the
100 Returns 2 part tuple containing list of nodes to insert into the
100 document and a list of system messages. Both are allowed to be
101 document and a list of system messages. Both are allowed to be
101 empty.
102 empty.
102
103
103 :param name: The role name used in the document.
104 :param name: The role name used in the document.
104 :param rawtext: The entire markup snippet, with role.
105 :param rawtext: The entire markup snippet, with role.
105 :param text: The text marked with the role.
106 :param text: The text marked with the role.
106 :param lineno: The line number where rawtext appears in the input.
107 :param lineno: The line number where rawtext appears in the input.
107 :param inliner: The inliner instance that called us.
108 :param inliner: The inliner instance that called us.
108 :param options: Directive options for customization.
109 :param options: Directive options for customization.
109 :param content: The directive content for customization.
110 :param content: The directive content for customization.
110 """
111 """
111 if options is None:
112 if options is None:
112 options = {}
113 options = {}
113
114
114 #info('user link %r' % text)
115 #info('user link %r' % text)
115 ref = 'https://www.github.com/' + text
116 ref = 'https://www.github.com/' + text
116 node = nodes.reference(rawtext, text, refuri=ref, **options)
117 node = nodes.reference(rawtext, text, refuri=ref, **options)
117 return [node], []
118 return [node], []
118
119
119 def ghcommit_role(name, rawtext, text, lineno, inliner, options=None, content=None):
120 def ghcommit_role(name, rawtext, text, lineno, inliner, options=None, content=None):
120 """Link to a GitHub commit.
121 """Link to a GitHub commit.
121
122
122 Returns 2 part tuple containing list of nodes to insert into the
123 Returns 2 part tuple containing list of nodes to insert into the
123 document and a list of system messages. Both are allowed to be
124 document and a list of system messages. Both are allowed to be
124 empty.
125 empty.
125
126
126 :param name: The role name used in the document.
127 :param name: The role name used in the document.
127 :param rawtext: The entire markup snippet, with role.
128 :param rawtext: The entire markup snippet, with role.
128 :param text: The text marked with the role.
129 :param text: The text marked with the role.
129 :param lineno: The line number where rawtext appears in the input.
130 :param lineno: The line number where rawtext appears in the input.
130 :param inliner: The inliner instance that called us.
131 :param inliner: The inliner instance that called us.
131 :param options: Directive options for customization.
132 :param options: Directive options for customization.
132 :param content: The directive content for customization.
133 :param content: The directive content for customization.
133 """
134 """
134 if options is None:
135 if options is None:
135 options = {}
136 options = {}
136
137
137 #info('user link %r' % text)
138 #info('user link %r' % text)
138 try:
139 try:
139 base = app.config.github_project_url
140 base = app.config.github_project_url
140 if not base:
141 if not base:
141 raise AttributeError
142 raise AttributeError
142 if not base.endswith('/'):
143 if not base.endswith('/'):
143 base += '/'
144 base += '/'
144 except AttributeError as err:
145 except AttributeError as err:
145 raise ValueError('github_project_url configuration value is not set (%s)' % str(err)) from err
146 raise ValueError('github_project_url configuration value is not set (%s)' % str(err)) from err
146
147
147 ref = base + text
148 ref = base + text
148 node = nodes.reference(rawtext, text[:6], refuri=ref, **options)
149 node = nodes.reference(rawtext, text[:6], refuri=ref, **options)
149 return [node], []
150 return [node], []
150
151
151
152
152 def setup(app):
153 def setup(app):
153 """Install the plugin.
154 """Install the plugin.
154
155
155 :param app: Sphinx application context.
156 :param app: Sphinx application context.
156 """
157 """
157 info('Initializing GitHub plugin')
158 info('Initializing GitHub plugin')
158 app.add_role('ghissue', ghissue_role)
159 app.add_role('ghissue', ghissue_role)
159 app.add_role('ghpull', ghissue_role)
160 app.add_role('ghpull', ghissue_role)
160 app.add_role('ghuser', ghuser_role)
161 app.add_role('ghuser', ghuser_role)
161 app.add_role('ghcommit', ghcommit_role)
162 app.add_role('ghcommit', ghcommit_role)
162 app.add_config_value('github_project_url', None, 'env')
163 app.add_config_value('github_project_url', None, 'env')
163
164
164 metadata = {'parallel_read_safe': True, 'parallel_write_safe': True}
165 metadata = {'parallel_read_safe': True, 'parallel_write_safe': True}
165 return metadata
166 return metadata
General Comments 0
You need to be logged in to leave comments. Login now