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