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