##// END OF EJS Templates
don't install test extension...
Min RK -
Show More
@@ -1,1000 +1,996 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 from __future__ import absolute_import
7 7
8 8 import io
9 9 import os
10 10 import sys
11 11 import warnings
12 12 from unittest import TestCase
13 13
14 14 try:
15 15 from importlib import invalidate_caches # Required from Python 3.3
16 16 except ImportError:
17 17 def invalidate_caches():
18 18 pass
19 19
20 20 import nose.tools as nt
21 21
22 22 from IPython import get_ipython
23 23 from IPython.core import magic
24 24 from IPython.core.error import UsageError
25 25 from IPython.core.magic import (Magics, magics_class, line_magic,
26 26 cell_magic,
27 27 register_line_magic, register_cell_magic)
28 28 from IPython.core.magics import execution, script, code
29 29 from IPython.testing import decorators as dec
30 30 from IPython.testing import tools as tt
31 31 from IPython.utils import py3compat
32 32 from IPython.utils.io import capture_output
33 33 from IPython.utils.tempdir import TemporaryDirectory
34 34 from IPython.utils.process import find_cmd
35 35
36 36 if py3compat.PY3:
37 37 from io import StringIO
38 38 else:
39 39 from StringIO import StringIO
40 40
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 = [(0, 1),
48 48 (2, 3),
49 49 (4, 6),
50 50 (6, 9),
51 51 (9, 14),
52 52 (16, None),
53 53 (None, 9),
54 54 (9, None),
55 55 (None, 13),
56 56 (None, None)]
57 57 actual = list(code.extract_code_ranges(instr))
58 58 nt.assert_equal(actual, expected)
59 59
60 60 def test_extract_symbols():
61 61 source = """import foo\na = 10\ndef b():\n return 42\n\n\nclass A: pass\n\n\n"""
62 62 symbols_args = ["a", "b", "A", "A,b", "A,a", "z"]
63 63 expected = [([], ['a']),
64 64 (["def b():\n return 42\n"], []),
65 65 (["class A: pass\n"], []),
66 66 (["class A: pass\n", "def b():\n return 42\n"], []),
67 67 (["class A: pass\n"], ['a']),
68 68 ([], ['z'])]
69 69 for symbols, exp in zip(symbols_args, expected):
70 70 nt.assert_equal(code.extract_symbols(source, symbols), exp)
71 71
72 72
73 73 def test_extract_symbols_raises_exception_with_non_python_code():
74 74 source = ("=begin A Ruby program :)=end\n"
75 75 "def hello\n"
76 76 "puts 'Hello world'\n"
77 77 "end")
78 78 with nt.assert_raises(SyntaxError):
79 79 code.extract_symbols(source, "hello")
80 80
81 81 def test_config():
82 82 """ test that config magic does not raise
83 83 can happen if Configurable init is moved too early into
84 84 Magics.__init__ as then a Config object will be registerd as a
85 85 magic.
86 86 """
87 87 ## should not raise.
88 88 _ip.magic('config')
89 89
90 90 def test_rehashx():
91 91 # clear up everything
92 92 _ip = get_ipython()
93 93 _ip.alias_manager.clear_aliases()
94 94 del _ip.db['syscmdlist']
95 95
96 96 _ip.magic('rehashx')
97 97 # Practically ALL ipython development systems will have more than 10 aliases
98 98
99 99 nt.assert_true(len(_ip.alias_manager.aliases) > 10)
100 100 for name, cmd in _ip.alias_manager.aliases:
101 101 # we must strip dots from alias names
102 102 nt.assert_not_in('.', name)
103 103
104 104 # rehashx must fill up syscmdlist
105 105 scoms = _ip.db['syscmdlist']
106 106 nt.assert_true(len(scoms) > 10)
107 107
108 108
109 109 def test_magic_parse_options():
110 110 """Test that we don't mangle paths when parsing magic options."""
111 111 ip = get_ipython()
112 112 path = 'c:\\x'
113 113 m = DummyMagics(ip)
114 114 opts = m.parse_options('-f %s' % path,'f:')[0]
115 115 # argv splitting is os-dependent
116 116 if os.name == 'posix':
117 117 expected = 'c:x'
118 118 else:
119 119 expected = path
120 120 nt.assert_equal(opts['f'], expected)
121 121
122 122 def test_magic_parse_long_options():
123 123 """Magic.parse_options can handle --foo=bar long options"""
124 124 ip = get_ipython()
125 125 m = DummyMagics(ip)
126 126 opts, _ = m.parse_options('--foo --bar=bubble', 'a', 'foo', 'bar=')
127 127 nt.assert_in('foo', opts)
128 128 nt.assert_in('bar', opts)
129 129 nt.assert_equal(opts['bar'], "bubble")
130 130
131 131
132 132 @dec.skip_without('sqlite3')
133 133 def doctest_hist_f():
134 134 """Test %hist -f with temporary filename.
135 135
136 136 In [9]: import tempfile
137 137
138 138 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
139 139
140 140 In [11]: %hist -nl -f $tfile 3
141 141
142 142 In [13]: import os; os.unlink(tfile)
143 143 """
144 144
145 145
146 146 @dec.skip_without('sqlite3')
147 147 def doctest_hist_r():
148 148 """Test %hist -r
149 149
150 150 XXX - This test is not recording the output correctly. For some reason, in
151 151 testing mode the raw history isn't getting populated. No idea why.
152 152 Disabling the output checking for now, though at least we do run it.
153 153
154 154 In [1]: 'hist' in _ip.lsmagic()
155 155 Out[1]: True
156 156
157 157 In [2]: x=1
158 158
159 159 In [3]: %hist -rl 2
160 160 x=1 # random
161 161 %hist -r 2
162 162 """
163 163
164 164
165 165 @dec.skip_without('sqlite3')
166 166 def doctest_hist_op():
167 167 """Test %hist -op
168 168
169 169 In [1]: class b(float):
170 170 ...: pass
171 171 ...:
172 172
173 173 In [2]: class s(object):
174 174 ...: def __str__(self):
175 175 ...: return 's'
176 176 ...:
177 177
178 178 In [3]:
179 179
180 180 In [4]: class r(b):
181 181 ...: def __repr__(self):
182 182 ...: return 'r'
183 183 ...:
184 184
185 185 In [5]: class sr(s,r): pass
186 186 ...:
187 187
188 188 In [6]:
189 189
190 190 In [7]: bb=b()
191 191
192 192 In [8]: ss=s()
193 193
194 194 In [9]: rr=r()
195 195
196 196 In [10]: ssrr=sr()
197 197
198 198 In [11]: 4.5
199 199 Out[11]: 4.5
200 200
201 201 In [12]: str(ss)
202 202 Out[12]: 's'
203 203
204 204 In [13]:
205 205
206 206 In [14]: %hist -op
207 207 >>> class b:
208 208 ... pass
209 209 ...
210 210 >>> class s(b):
211 211 ... def __str__(self):
212 212 ... return 's'
213 213 ...
214 214 >>>
215 215 >>> class r(b):
216 216 ... def __repr__(self):
217 217 ... return 'r'
218 218 ...
219 219 >>> class sr(s,r): pass
220 220 >>>
221 221 >>> bb=b()
222 222 >>> ss=s()
223 223 >>> rr=r()
224 224 >>> ssrr=sr()
225 225 >>> 4.5
226 226 4.5
227 227 >>> str(ss)
228 228 's'
229 229 >>>
230 230 """
231 231
232 232 def test_hist_pof():
233 233 ip = get_ipython()
234 234 ip.run_cell(u"1+2", store_history=True)
235 235 #raise Exception(ip.history_manager.session_number)
236 236 #raise Exception(list(ip.history_manager._get_range_session()))
237 237 with TemporaryDirectory() as td:
238 238 tf = os.path.join(td, 'hist.py')
239 239 ip.run_line_magic('history', '-pof %s' % tf)
240 240 assert os.path.isfile(tf)
241 241
242 242
243 243 @dec.skip_without('sqlite3')
244 244 def test_macro():
245 245 ip = get_ipython()
246 246 ip.history_manager.reset() # Clear any existing history.
247 247 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
248 248 for i, cmd in enumerate(cmds, start=1):
249 249 ip.history_manager.store_inputs(i, cmd)
250 250 ip.magic("macro test 1-3")
251 251 nt.assert_equal(ip.user_ns["test"].value, "\n".join(cmds)+"\n")
252 252
253 253 # List macros
254 254 nt.assert_in("test", ip.magic("macro"))
255 255
256 256
257 257 @dec.skip_without('sqlite3')
258 258 def test_macro_run():
259 259 """Test that we can run a multi-line macro successfully."""
260 260 ip = get_ipython()
261 261 ip.history_manager.reset()
262 262 cmds = ["a=10", "a+=1", py3compat.doctest_refactor_print("print a"),
263 263 "%macro test 2-3"]
264 264 for cmd in cmds:
265 265 ip.run_cell(cmd, store_history=True)
266 266 nt.assert_equal(ip.user_ns["test"].value,
267 267 py3compat.doctest_refactor_print("a+=1\nprint a\n"))
268 268 with tt.AssertPrints("12"):
269 269 ip.run_cell("test")
270 270 with tt.AssertPrints("13"):
271 271 ip.run_cell("test")
272 272
273 273
274 274 def test_magic_magic():
275 275 """Test %magic"""
276 276 ip = get_ipython()
277 277 with capture_output() as captured:
278 278 ip.magic("magic")
279 279
280 280 stdout = captured.stdout
281 281 nt.assert_in('%magic', stdout)
282 282 nt.assert_in('IPython', stdout)
283 283 nt.assert_in('Available', stdout)
284 284
285 285
286 286 @dec.skipif_not_numpy
287 287 def test_numpy_reset_array_undec():
288 288 "Test '%reset array' functionality"
289 289 _ip.ex('import numpy as np')
290 290 _ip.ex('a = np.empty(2)')
291 291 nt.assert_in('a', _ip.user_ns)
292 292 _ip.magic('reset -f array')
293 293 nt.assert_not_in('a', _ip.user_ns)
294 294
295 295 def test_reset_out():
296 296 "Test '%reset out' magic"
297 297 _ip.run_cell("parrot = 'dead'", store_history=True)
298 298 # test '%reset -f out', make an Out prompt
299 299 _ip.run_cell("parrot", store_history=True)
300 300 nt.assert_true('dead' in [_ip.user_ns[x] for x in ('_','__','___')])
301 301 _ip.magic('reset -f out')
302 302 nt.assert_false('dead' in [_ip.user_ns[x] for x in ('_','__','___')])
303 303 nt.assert_equal(len(_ip.user_ns['Out']), 0)
304 304
305 305 def test_reset_in():
306 306 "Test '%reset in' magic"
307 307 # test '%reset -f in'
308 308 _ip.run_cell("parrot", store_history=True)
309 309 nt.assert_true('parrot' in [_ip.user_ns[x] for x in ('_i','_ii','_iii')])
310 310 _ip.magic('%reset -f in')
311 311 nt.assert_false('parrot' in [_ip.user_ns[x] for x in ('_i','_ii','_iii')])
312 312 nt.assert_equal(len(set(_ip.user_ns['In'])), 1)
313 313
314 314 def test_reset_dhist():
315 315 "Test '%reset dhist' magic"
316 316 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
317 317 _ip.magic('cd ' + os.path.dirname(nt.__file__))
318 318 _ip.magic('cd -')
319 319 nt.assert_true(len(_ip.user_ns['_dh']) > 0)
320 320 _ip.magic('reset -f dhist')
321 321 nt.assert_equal(len(_ip.user_ns['_dh']), 0)
322 322 _ip.run_cell("_dh = [d for d in tmp]") #restore
323 323
324 324 def test_reset_in_length():
325 325 "Test that '%reset in' preserves In[] length"
326 326 _ip.run_cell("print 'foo'")
327 327 _ip.run_cell("reset -f in")
328 328 nt.assert_equal(len(_ip.user_ns['In']), _ip.displayhook.prompt_count+1)
329 329
330 330 def test_tb_syntaxerror():
331 331 """test %tb after a SyntaxError"""
332 332 ip = get_ipython()
333 333 ip.run_cell("for")
334 334
335 335 # trap and validate stdout
336 336 save_stdout = sys.stdout
337 337 try:
338 338 sys.stdout = StringIO()
339 339 ip.run_cell("%tb")
340 340 out = sys.stdout.getvalue()
341 341 finally:
342 342 sys.stdout = save_stdout
343 343 # trim output, and only check the last line
344 344 last_line = out.rstrip().splitlines()[-1].strip()
345 345 nt.assert_equal(last_line, "SyntaxError: invalid syntax")
346 346
347 347
348 348 def test_time():
349 349 ip = get_ipython()
350 350
351 351 with tt.AssertPrints("Wall time: "):
352 352 ip.run_cell("%time None")
353 353
354 354 ip.run_cell("def f(kmjy):\n"
355 355 " %time print (2*kmjy)")
356 356
357 357 with tt.AssertPrints("Wall time: "):
358 358 with tt.AssertPrints("hihi", suppress=False):
359 359 ip.run_cell("f('hi')")
360 360
361 361
362 362 @dec.skip_win32
363 363 def test_time2():
364 364 ip = get_ipython()
365 365
366 366 with tt.AssertPrints("CPU times: user "):
367 367 ip.run_cell("%time None")
368 368
369 369 def test_time3():
370 370 """Erroneous magic function calls, issue gh-3334"""
371 371 ip = get_ipython()
372 372 ip.user_ns.pop('run', None)
373 373
374 374 with tt.AssertNotPrints("not found", channel='stderr'):
375 375 ip.run_cell("%%time\n"
376 376 "run = 0\n"
377 377 "run += 1")
378 378
379 379 @dec.skipif(sys.version_info[0] >= 3, "no differences with __future__ in py3")
380 380 def test_time_futures():
381 381 "Test %time with __future__ environments"
382 382 ip = get_ipython()
383 383 ip.autocall = 0
384 384 ip.run_cell("from __future__ import division")
385 385 with tt.AssertPrints('0.25'):
386 386 ip.run_line_magic('time', 'print(1/4)')
387 387 ip.compile.reset_compiler_flags()
388 388 with tt.AssertNotPrints('0.25'):
389 389 ip.run_line_magic('time', 'print(1/4)')
390 390
391 391 def test_doctest_mode():
392 392 "Toggle doctest_mode twice, it should be a no-op and run without error"
393 393 _ip.magic('doctest_mode')
394 394 _ip.magic('doctest_mode')
395 395
396 396
397 397 def test_parse_options():
398 398 """Tests for basic options parsing in magics."""
399 399 # These are only the most minimal of tests, more should be added later. At
400 400 # the very least we check that basic text/unicode calls work OK.
401 401 m = DummyMagics(_ip)
402 402 nt.assert_equal(m.parse_options('foo', '')[1], 'foo')
403 403 nt.assert_equal(m.parse_options(u'foo', '')[1], u'foo')
404 404
405 405
406 406 def test_dirops():
407 407 """Test various directory handling operations."""
408 408 # curpath = lambda :os.path.splitdrive(py3compat.getcwd())[1].replace('\\','/')
409 409 curpath = py3compat.getcwd
410 410 startdir = py3compat.getcwd()
411 411 ipdir = os.path.realpath(_ip.ipython_dir)
412 412 try:
413 413 _ip.magic('cd "%s"' % ipdir)
414 414 nt.assert_equal(curpath(), ipdir)
415 415 _ip.magic('cd -')
416 416 nt.assert_equal(curpath(), startdir)
417 417 _ip.magic('pushd "%s"' % ipdir)
418 418 nt.assert_equal(curpath(), ipdir)
419 419 _ip.magic('popd')
420 420 nt.assert_equal(curpath(), startdir)
421 421 finally:
422 422 os.chdir(startdir)
423 423
424 424
425 425 def test_xmode():
426 426 # Calling xmode three times should be a no-op
427 427 xmode = _ip.InteractiveTB.mode
428 428 for i in range(3):
429 429 _ip.magic("xmode")
430 430 nt.assert_equal(_ip.InteractiveTB.mode, xmode)
431 431
432 432 def test_reset_hard():
433 433 monitor = []
434 434 class A(object):
435 435 def __del__(self):
436 436 monitor.append(1)
437 437 def __repr__(self):
438 438 return "<A instance>"
439 439
440 440 _ip.user_ns["a"] = A()
441 441 _ip.run_cell("a")
442 442
443 443 nt.assert_equal(monitor, [])
444 444 _ip.magic("reset -f")
445 445 nt.assert_equal(monitor, [1])
446 446
447 447 class TestXdel(tt.TempFileMixin):
448 448 def test_xdel(self):
449 449 """Test that references from %run are cleared by xdel."""
450 450 src = ("class A(object):\n"
451 451 " monitor = []\n"
452 452 " def __del__(self):\n"
453 453 " self.monitor.append(1)\n"
454 454 "a = A()\n")
455 455 self.mktmp(src)
456 456 # %run creates some hidden references...
457 457 _ip.magic("run %s" % self.fname)
458 458 # ... as does the displayhook.
459 459 _ip.run_cell("a")
460 460
461 461 monitor = _ip.user_ns["A"].monitor
462 462 nt.assert_equal(monitor, [])
463 463
464 464 _ip.magic("xdel a")
465 465
466 466 # Check that a's __del__ method has been called.
467 467 nt.assert_equal(monitor, [1])
468 468
469 469 def doctest_who():
470 470 """doctest for %who
471 471
472 472 In [1]: %reset -f
473 473
474 474 In [2]: alpha = 123
475 475
476 476 In [3]: beta = 'beta'
477 477
478 478 In [4]: %who int
479 479 alpha
480 480
481 481 In [5]: %who str
482 482 beta
483 483
484 484 In [6]: %whos
485 485 Variable Type Data/Info
486 486 ----------------------------
487 487 alpha int 123
488 488 beta str beta
489 489
490 490 In [7]: %who_ls
491 491 Out[7]: ['alpha', 'beta']
492 492 """
493 493
494 494 def test_whos():
495 495 """Check that whos is protected against objects where repr() fails."""
496 496 class A(object):
497 497 def __repr__(self):
498 498 raise Exception()
499 499 _ip.user_ns['a'] = A()
500 500 _ip.magic("whos")
501 501
502 502 @py3compat.u_format
503 503 def doctest_precision():
504 504 """doctest for %precision
505 505
506 506 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
507 507
508 508 In [2]: %precision 5
509 509 Out[2]: {u}'%.5f'
510 510
511 511 In [3]: f.float_format
512 512 Out[3]: {u}'%.5f'
513 513
514 514 In [4]: %precision %e
515 515 Out[4]: {u}'%e'
516 516
517 517 In [5]: f(3.1415927)
518 518 Out[5]: {u}'3.141593e+00'
519 519 """
520 520
521 521 def test_psearch():
522 522 with tt.AssertPrints("dict.fromkeys"):
523 523 _ip.run_cell("dict.fr*?")
524 524
525 525 def test_timeit_shlex():
526 526 """test shlex issues with timeit (#1109)"""
527 527 _ip.ex("def f(*a,**kw): pass")
528 528 _ip.magic('timeit -n1 "this is a bug".count(" ")')
529 529 _ip.magic('timeit -r1 -n1 f(" ", 1)')
530 530 _ip.magic('timeit -r1 -n1 f(" ", 1, " ", 2, " ")')
531 531 _ip.magic('timeit -r1 -n1 ("a " + "b")')
532 532 _ip.magic('timeit -r1 -n1 f("a " + "b")')
533 533 _ip.magic('timeit -r1 -n1 f("a " + "b ")')
534 534
535 535
536 536 def test_timeit_arguments():
537 537 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
538 538 _ip.magic("timeit ('#')")
539 539
540 540
541 541 def test_timeit_special_syntax():
542 542 "Test %%timeit with IPython special syntax"
543 543 @register_line_magic
544 544 def lmagic(line):
545 545 ip = get_ipython()
546 546 ip.user_ns['lmagic_out'] = line
547 547
548 548 # line mode test
549 549 _ip.run_line_magic('timeit', '-n1 -r1 %lmagic my line')
550 550 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
551 551 # cell mode test
552 552 _ip.run_cell_magic('timeit', '-n1 -r1', '%lmagic my line2')
553 553 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
554 554
555 555 def test_timeit_return():
556 556 """
557 557 test wether timeit -o return object
558 558 """
559 559
560 560 res = _ip.run_line_magic('timeit','-n10 -r10 -o 1')
561 561 assert(res is not None)
562 562
563 563 def test_timeit_quiet():
564 564 """
565 565 test quiet option of timeit magic
566 566 """
567 567 with tt.AssertNotPrints("loops"):
568 568 _ip.run_cell("%timeit -n1 -r1 -q 1")
569 569
570 570 def test_timeit_return_quiet():
571 571 with tt.AssertNotPrints("loops"):
572 572 res = _ip.run_line_magic('timeit', '-n1 -r1 -q -o 1')
573 573 assert (res is not None)
574 574
575 575 @dec.skipif(sys.version_info[0] >= 3, "no differences with __future__ in py3")
576 576 def test_timeit_futures():
577 577 "Test %timeit with __future__ environments"
578 578 ip = get_ipython()
579 579 ip.run_cell("from __future__ import division")
580 580 with tt.AssertPrints('0.25'):
581 581 ip.run_line_magic('timeit', '-n1 -r1 print(1/4)')
582 582 ip.compile.reset_compiler_flags()
583 583 with tt.AssertNotPrints('0.25'):
584 584 ip.run_line_magic('timeit', '-n1 -r1 print(1/4)')
585 585
586 586 @dec.skipif(execution.profile is None)
587 587 def test_prun_special_syntax():
588 588 "Test %%prun with IPython special syntax"
589 589 @register_line_magic
590 590 def lmagic(line):
591 591 ip = get_ipython()
592 592 ip.user_ns['lmagic_out'] = line
593 593
594 594 # line mode test
595 595 _ip.run_line_magic('prun', '-q %lmagic my line')
596 596 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
597 597 # cell mode test
598 598 _ip.run_cell_magic('prun', '-q', '%lmagic my line2')
599 599 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
600 600
601 601 @dec.skipif(execution.profile is None)
602 602 def test_prun_quotes():
603 603 "Test that prun does not clobber string escapes (GH #1302)"
604 604 _ip.magic(r"prun -q x = '\t'")
605 605 nt.assert_equal(_ip.user_ns['x'], '\t')
606 606
607 607 def test_extension():
608 tmpdir = TemporaryDirectory()
609 orig_ipython_dir = _ip.ipython_dir
608 nt.assert_raises(ImportError, _ip.magic, "load_ext daft_extension")
609 daft_path = os.path.join(os.path.dirname(__file__), "daft_extension")
610 sys.path.insert(0, daft_path)
610 611 try:
611 _ip.ipython_dir = tmpdir.name
612 nt.assert_raises(ImportError, _ip.magic, "load_ext daft_extension")
613 url = os.path.join(os.path.dirname(__file__), "daft_extension")
614 _ip.system("%s -m pip install %s" % (sys.executable, url))
615 612 _ip.user_ns.pop('arq', None)
616 613 invalidate_caches() # Clear import caches
617 614 _ip.magic("load_ext daft_extension")
618 615 nt.assert_equal(_ip.user_ns['arq'], 185)
619 616 _ip.magic("unload_ext daft_extension")
620 617 assert 'arq' not in _ip.user_ns
621 618 finally:
622 _ip.ipython_dir = orig_ipython_dir
623 tmpdir.cleanup()
619 sys.path.remove(daft_path)
624 620
625 621
626 622 @dec.skip_without('nbformat')
627 623 def test_notebook_export_json():
628 624 _ip = get_ipython()
629 625 _ip.history_manager.reset() # Clear any existing history.
630 626 cmds = [u"a=1", u"def b():\n return a**2", u"print('noël, été', b())"]
631 627 for i, cmd in enumerate(cmds, start=1):
632 628 _ip.history_manager.store_inputs(i, cmd)
633 629 with TemporaryDirectory() as td:
634 630 outfile = os.path.join(td, "nb.ipynb")
635 631 _ip.magic("notebook -e %s" % outfile)
636 632
637 633
638 634 class TestEnv(TestCase):
639 635
640 636 def test_env(self):
641 637 env = _ip.magic("env")
642 638 self.assertTrue(isinstance(env, dict))
643 639
644 640 def test_env_get_set_simple(self):
645 641 env = _ip.magic("env var val1")
646 642 self.assertEqual(env, None)
647 643 self.assertEqual(os.environ['var'], 'val1')
648 644 self.assertEqual(_ip.magic("env var"), 'val1')
649 645 env = _ip.magic("env var=val2")
650 646 self.assertEqual(env, None)
651 647 self.assertEqual(os.environ['var'], 'val2')
652 648
653 649 def test_env_get_set_complex(self):
654 650 env = _ip.magic("env var 'val1 '' 'val2")
655 651 self.assertEqual(env, None)
656 652 self.assertEqual(os.environ['var'], "'val1 '' 'val2")
657 653 self.assertEqual(_ip.magic("env var"), "'val1 '' 'val2")
658 654 env = _ip.magic('env var=val2 val3="val4')
659 655 self.assertEqual(env, None)
660 656 self.assertEqual(os.environ['var'], 'val2 val3="val4')
661 657
662 658 def test_env_set_bad_input(self):
663 659 self.assertRaises(UsageError, lambda: _ip.magic("set_env var"))
664 660
665 661 def test_env_set_whitespace(self):
666 662 self.assertRaises(UsageError, lambda: _ip.magic("env var A=B"))
667 663
668 664
669 665 class CellMagicTestCase(TestCase):
670 666
671 667 def check_ident(self, magic):
672 668 # Manually called, we get the result
673 669 out = _ip.run_cell_magic(magic, 'a', 'b')
674 670 nt.assert_equal(out, ('a','b'))
675 671 # Via run_cell, it goes into the user's namespace via displayhook
676 672 _ip.run_cell('%%' + magic +' c\nd')
677 673 nt.assert_equal(_ip.user_ns['_'], ('c','d'))
678 674
679 675 def test_cell_magic_func_deco(self):
680 676 "Cell magic using simple decorator"
681 677 @register_cell_magic
682 678 def cellm(line, cell):
683 679 return line, cell
684 680
685 681 self.check_ident('cellm')
686 682
687 683 def test_cell_magic_reg(self):
688 684 "Cell magic manually registered"
689 685 def cellm(line, cell):
690 686 return line, cell
691 687
692 688 _ip.register_magic_function(cellm, 'cell', 'cellm2')
693 689 self.check_ident('cellm2')
694 690
695 691 def test_cell_magic_class(self):
696 692 "Cell magics declared via a class"
697 693 @magics_class
698 694 class MyMagics(Magics):
699 695
700 696 @cell_magic
701 697 def cellm3(self, line, cell):
702 698 return line, cell
703 699
704 700 _ip.register_magics(MyMagics)
705 701 self.check_ident('cellm3')
706 702
707 703 def test_cell_magic_class2(self):
708 704 "Cell magics declared via a class, #2"
709 705 @magics_class
710 706 class MyMagics2(Magics):
711 707
712 708 @cell_magic('cellm4')
713 709 def cellm33(self, line, cell):
714 710 return line, cell
715 711
716 712 _ip.register_magics(MyMagics2)
717 713 self.check_ident('cellm4')
718 714 # Check that nothing is registered as 'cellm33'
719 715 c33 = _ip.find_cell_magic('cellm33')
720 716 nt.assert_equal(c33, None)
721 717
722 718 def test_file():
723 719 """Basic %%file"""
724 720 ip = get_ipython()
725 721 with TemporaryDirectory() as td:
726 722 fname = os.path.join(td, 'file1')
727 723 ip.run_cell_magic("file", fname, u'\n'.join([
728 724 'line1',
729 725 'line2',
730 726 ]))
731 727 with open(fname) as f:
732 728 s = f.read()
733 729 nt.assert_in('line1\n', s)
734 730 nt.assert_in('line2', s)
735 731
736 732 def test_file_var_expand():
737 733 """%%file $filename"""
738 734 ip = get_ipython()
739 735 with TemporaryDirectory() as td:
740 736 fname = os.path.join(td, 'file1')
741 737 ip.user_ns['filename'] = fname
742 738 ip.run_cell_magic("file", '$filename', u'\n'.join([
743 739 'line1',
744 740 'line2',
745 741 ]))
746 742 with open(fname) as f:
747 743 s = f.read()
748 744 nt.assert_in('line1\n', s)
749 745 nt.assert_in('line2', s)
750 746
751 747 def test_file_unicode():
752 748 """%%file with unicode cell"""
753 749 ip = get_ipython()
754 750 with TemporaryDirectory() as td:
755 751 fname = os.path.join(td, 'file1')
756 752 ip.run_cell_magic("file", fname, u'\n'.join([
757 753 u'liné1',
758 754 u'liné2',
759 755 ]))
760 756 with io.open(fname, encoding='utf-8') as f:
761 757 s = f.read()
762 758 nt.assert_in(u'liné1\n', s)
763 759 nt.assert_in(u'liné2', s)
764 760
765 761 def test_file_amend():
766 762 """%%file -a amends files"""
767 763 ip = get_ipython()
768 764 with TemporaryDirectory() as td:
769 765 fname = os.path.join(td, 'file2')
770 766 ip.run_cell_magic("file", fname, u'\n'.join([
771 767 'line1',
772 768 'line2',
773 769 ]))
774 770 ip.run_cell_magic("file", "-a %s" % fname, u'\n'.join([
775 771 'line3',
776 772 'line4',
777 773 ]))
778 774 with open(fname) as f:
779 775 s = f.read()
780 776 nt.assert_in('line1\n', s)
781 777 nt.assert_in('line3\n', s)
782 778
783 779
784 780 def test_script_config():
785 781 ip = get_ipython()
786 782 ip.config.ScriptMagics.script_magics = ['whoda']
787 783 sm = script.ScriptMagics(shell=ip)
788 784 nt.assert_in('whoda', sm.magics['cell'])
789 785
790 786 @dec.skip_win32
791 787 def test_script_out():
792 788 ip = get_ipython()
793 789 ip.run_cell_magic("script", "--out output sh", "echo 'hi'")
794 790 nt.assert_equal(ip.user_ns['output'], 'hi\n')
795 791
796 792 @dec.skip_win32
797 793 def test_script_err():
798 794 ip = get_ipython()
799 795 ip.run_cell_magic("script", "--err error sh", "echo 'hello' >&2")
800 796 nt.assert_equal(ip.user_ns['error'], 'hello\n')
801 797
802 798 @dec.skip_win32
803 799 def test_script_out_err():
804 800 ip = get_ipython()
805 801 ip.run_cell_magic("script", "--out output --err error sh", "echo 'hi'\necho 'hello' >&2")
806 802 nt.assert_equal(ip.user_ns['output'], 'hi\n')
807 803 nt.assert_equal(ip.user_ns['error'], 'hello\n')
808 804
809 805 @dec.skip_win32
810 806 def test_script_bg_out():
811 807 ip = get_ipython()
812 808 ip.run_cell_magic("script", "--bg --out output sh", "echo 'hi'")
813 809 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
814 810
815 811 @dec.skip_win32
816 812 def test_script_bg_err():
817 813 ip = get_ipython()
818 814 ip.run_cell_magic("script", "--bg --err error sh", "echo 'hello' >&2")
819 815 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
820 816
821 817 @dec.skip_win32
822 818 def test_script_bg_out_err():
823 819 ip = get_ipython()
824 820 ip.run_cell_magic("script", "--bg --out output --err error sh", "echo 'hi'\necho 'hello' >&2")
825 821 nt.assert_equal(ip.user_ns['output'].read(), b'hi\n')
826 822 nt.assert_equal(ip.user_ns['error'].read(), b'hello\n')
827 823
828 824 def test_script_defaults():
829 825 ip = get_ipython()
830 826 for cmd in ['sh', 'bash', 'perl', 'ruby']:
831 827 try:
832 828 find_cmd(cmd)
833 829 except Exception:
834 830 pass
835 831 else:
836 832 nt.assert_in(cmd, ip.magics_manager.magics['cell'])
837 833
838 834
839 835 @magics_class
840 836 class FooFoo(Magics):
841 837 """class with both %foo and %%foo magics"""
842 838 @line_magic('foo')
843 839 def line_foo(self, line):
844 840 "I am line foo"
845 841 pass
846 842
847 843 @cell_magic("foo")
848 844 def cell_foo(self, line, cell):
849 845 "I am cell foo, not line foo"
850 846 pass
851 847
852 848 def test_line_cell_info():
853 849 """%%foo and %foo magics are distinguishable to inspect"""
854 850 ip = get_ipython()
855 851 ip.magics_manager.register(FooFoo)
856 852 oinfo = ip.object_inspect('foo')
857 853 nt.assert_true(oinfo['found'])
858 854 nt.assert_true(oinfo['ismagic'])
859 855
860 856 oinfo = ip.object_inspect('%%foo')
861 857 nt.assert_true(oinfo['found'])
862 858 nt.assert_true(oinfo['ismagic'])
863 859 nt.assert_equal(oinfo['docstring'], FooFoo.cell_foo.__doc__)
864 860
865 861 oinfo = ip.object_inspect('%foo')
866 862 nt.assert_true(oinfo['found'])
867 863 nt.assert_true(oinfo['ismagic'])
868 864 nt.assert_equal(oinfo['docstring'], FooFoo.line_foo.__doc__)
869 865
870 866 def test_multiple_magics():
871 867 ip = get_ipython()
872 868 foo1 = FooFoo(ip)
873 869 foo2 = FooFoo(ip)
874 870 mm = ip.magics_manager
875 871 mm.register(foo1)
876 872 nt.assert_true(mm.magics['line']['foo'].__self__ is foo1)
877 873 mm.register(foo2)
878 874 nt.assert_true(mm.magics['line']['foo'].__self__ is foo2)
879 875
880 876 def test_alias_magic():
881 877 """Test %alias_magic."""
882 878 ip = get_ipython()
883 879 mm = ip.magics_manager
884 880
885 881 # Basic operation: both cell and line magics are created, if possible.
886 882 ip.run_line_magic('alias_magic', 'timeit_alias timeit')
887 883 nt.assert_in('timeit_alias', mm.magics['line'])
888 884 nt.assert_in('timeit_alias', mm.magics['cell'])
889 885
890 886 # --cell is specified, line magic not created.
891 887 ip.run_line_magic('alias_magic', '--cell timeit_cell_alias timeit')
892 888 nt.assert_not_in('timeit_cell_alias', mm.magics['line'])
893 889 nt.assert_in('timeit_cell_alias', mm.magics['cell'])
894 890
895 891 # Test that line alias is created successfully.
896 892 ip.run_line_magic('alias_magic', '--line env_alias env')
897 893 nt.assert_equal(ip.run_line_magic('env', ''),
898 894 ip.run_line_magic('env_alias', ''))
899 895
900 896 def test_save():
901 897 """Test %save."""
902 898 ip = get_ipython()
903 899 ip.history_manager.reset() # Clear any existing history.
904 900 cmds = [u"a=1", u"def b():\n return a**2", u"print(a, b())"]
905 901 for i, cmd in enumerate(cmds, start=1):
906 902 ip.history_manager.store_inputs(i, cmd)
907 903 with TemporaryDirectory() as tmpdir:
908 904 file = os.path.join(tmpdir, "testsave.py")
909 905 ip.run_line_magic("save", "%s 1-10" % file)
910 906 with open(file) as f:
911 907 content = f.read()
912 908 nt.assert_equal(content.count(cmds[0]), 1)
913 909 nt.assert_in('coding: utf-8', content)
914 910 ip.run_line_magic("save", "-a %s 1-10" % file)
915 911 with open(file) as f:
916 912 content = f.read()
917 913 nt.assert_equal(content.count(cmds[0]), 2)
918 914 nt.assert_in('coding: utf-8', content)
919 915
920 916
921 917 def test_store():
922 918 """Test %store."""
923 919 ip = get_ipython()
924 920 ip.run_line_magic('load_ext', 'storemagic')
925 921
926 922 # make sure the storage is empty
927 923 ip.run_line_magic('store', '-z')
928 924 ip.user_ns['var'] = 42
929 925 ip.run_line_magic('store', 'var')
930 926 ip.user_ns['var'] = 39
931 927 ip.run_line_magic('store', '-r')
932 928 nt.assert_equal(ip.user_ns['var'], 42)
933 929
934 930 ip.run_line_magic('store', '-d var')
935 931 ip.user_ns['var'] = 39
936 932 ip.run_line_magic('store' , '-r')
937 933 nt.assert_equal(ip.user_ns['var'], 39)
938 934
939 935
940 936 def _run_edit_test(arg_s, exp_filename=None,
941 937 exp_lineno=-1,
942 938 exp_contents=None,
943 939 exp_is_temp=None):
944 940 ip = get_ipython()
945 941 M = code.CodeMagics(ip)
946 942 last_call = ['','']
947 943 opts,args = M.parse_options(arg_s,'prxn:')
948 944 filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call)
949 945
950 946 if exp_filename is not None:
951 947 nt.assert_equal(exp_filename, filename)
952 948 if exp_contents is not None:
953 949 with io.open(filename, 'r', encoding='utf-8') as f:
954 950 contents = f.read()
955 951 nt.assert_equal(exp_contents, contents)
956 952 if exp_lineno != -1:
957 953 nt.assert_equal(exp_lineno, lineno)
958 954 if exp_is_temp is not None:
959 955 nt.assert_equal(exp_is_temp, is_temp)
960 956
961 957
962 958 def test_edit_interactive():
963 959 """%edit on interactively defined objects"""
964 960 ip = get_ipython()
965 961 n = ip.execution_count
966 962 ip.run_cell(u"def foo(): return 1", store_history=True)
967 963
968 964 try:
969 965 _run_edit_test("foo")
970 966 except code.InteractivelyDefined as e:
971 967 nt.assert_equal(e.index, n)
972 968 else:
973 969 raise AssertionError("Should have raised InteractivelyDefined")
974 970
975 971
976 972 def test_edit_cell():
977 973 """%edit [cell id]"""
978 974 ip = get_ipython()
979 975
980 976 ip.run_cell(u"def foo(): return 1", store_history=True)
981 977
982 978 # test
983 979 _run_edit_test("1", exp_contents=ip.user_ns['In'][1], exp_is_temp=True)
984 980
985 981 def test_bookmark():
986 982 ip = get_ipython()
987 983 ip.run_line_magic('bookmark', 'bmname')
988 984 with tt.AssertPrints('bmname'):
989 985 ip.run_line_magic('bookmark', '-l')
990 986 ip.run_line_magic('bookmark', '-d bmname')
991 987
992 988 def test_ls_magic():
993 989 ip = get_ipython()
994 990 json_formatter = ip.display_formatter.formatters['application/json']
995 991 json_formatter.enabled = True
996 992 lsmagic = ip.magic('lsmagic')
997 993 with warnings.catch_warnings(record=True) as w:
998 994 j = json_formatter(lsmagic)
999 995 nt.assert_equal(sorted(j), ['cell', 'line'])
1000 996 nt.assert_equal(w, []) # no warnings
@@ -1,466 +1,466 b''
1 1 # encoding: utf-8
2 2 """
3 3 This module defines the things that are used in setup.py for building IPython
4 4
5 5 This includes:
6 6
7 7 * The basic arguments to setup
8 8 * Functions for finding things like packages, package data, etc.
9 9 * A function for checking dependencies.
10 10 """
11 11
12 12 # Copyright (c) IPython Development Team.
13 13 # Distributed under the terms of the Modified BSD License.
14 14
15 15 from __future__ import print_function
16 16
17 17 import errno
18 18 import os
19 19 import sys
20 20
21 21 from distutils import log
22 22 from distutils.command.build_py import build_py
23 23 from distutils.command.build_scripts import build_scripts
24 24 from distutils.command.install import install
25 25 from distutils.command.install_scripts import install_scripts
26 26 from distutils.cmd import Command
27 27 from distutils.errors import DistutilsExecError
28 28 from fnmatch import fnmatch
29 29 from glob import glob
30 30 from subprocess import Popen, PIPE
31 31
32 32 from setupext import install_data_ext
33 33
34 34 #-------------------------------------------------------------------------------
35 35 # Useful globals and utility functions
36 36 #-------------------------------------------------------------------------------
37 37
38 38 # A few handy globals
39 39 isfile = os.path.isfile
40 40 pjoin = os.path.join
41 41 repo_root = os.path.dirname(os.path.abspath(__file__))
42 42
43 43 def oscmd(s):
44 44 print(">", s)
45 45 os.system(s)
46 46
47 47 # Py3 compatibility hacks, without assuming IPython itself is installed with
48 48 # the full py3compat machinery.
49 49
50 50 try:
51 51 execfile
52 52 except NameError:
53 53 def execfile(fname, globs, locs=None):
54 54 locs = locs or globs
55 55 exec(compile(open(fname).read(), fname, "exec"), globs, locs)
56 56
57 57 # A little utility we'll need below, since glob() does NOT allow you to do
58 58 # exclusion on multiple endings!
59 59 def file_doesnt_endwith(test,endings):
60 60 """Return true if test is a file and its name does NOT end with any
61 61 of the strings listed in endings."""
62 62 if not isfile(test):
63 63 return False
64 64 for e in endings:
65 65 if test.endswith(e):
66 66 return False
67 67 return True
68 68
69 69 #---------------------------------------------------------------------------
70 70 # Basic project information
71 71 #---------------------------------------------------------------------------
72 72
73 73 # release.py contains version, authors, license, url, keywords, etc.
74 74 execfile(pjoin(repo_root, 'IPython','core','release.py'), globals())
75 75
76 76 # Create a dict with the basic information
77 77 # This dict is eventually passed to setup after additional keys are added.
78 78 setup_args = dict(
79 79 name = name,
80 80 version = version,
81 81 description = description,
82 82 long_description = long_description,
83 83 author = author,
84 84 author_email = author_email,
85 85 url = url,
86 86 download_url = download_url,
87 87 license = license,
88 88 platforms = platforms,
89 89 keywords = keywords,
90 90 classifiers = classifiers,
91 91 cmdclass = {'install_data': install_data_ext},
92 92 )
93 93
94 94
95 95 #---------------------------------------------------------------------------
96 96 # Find packages
97 97 #---------------------------------------------------------------------------
98 98
99 99 def find_packages():
100 100 """
101 101 Find all of IPython's packages.
102 102 """
103 103 excludes = ['deathrow', 'quarantine']
104 104 packages = []
105 105 for dir,subdirs,files in os.walk('IPython'):
106 106 package = dir.replace(os.path.sep, '.')
107 107 if any(package.startswith('IPython.'+exc) for exc in excludes):
108 108 # package is to be excluded (e.g. deathrow)
109 109 continue
110 110 if '__init__.py' not in files:
111 111 # not a package
112 112 continue
113 113 packages.append(package)
114 114 return packages
115 115
116 116 #---------------------------------------------------------------------------
117 117 # Find package data
118 118 #---------------------------------------------------------------------------
119 119
120 120 def find_package_data():
121 121 """
122 122 Find IPython's package_data.
123 123 """
124 124 # This is not enough for these things to appear in an sdist.
125 125 # We need to muck with the MANIFEST to get this to work
126 126
127 127 package_data = {
128 128 'IPython.core' : ['profile/README*'],
129 'IPython.core.tests' : ['*.png', '*.jpg'],
129 'IPython.core.tests' : ['*.png', '*.jpg', 'daft_extension/*.py'],
130 130 'IPython.lib.tests' : ['*.wav'],
131 131 'IPython.testing.plugin' : ['*.txt'],
132 132 }
133 133
134 134 return package_data
135 135
136 136
137 137 def check_package_data(package_data):
138 138 """verify that package_data globs make sense"""
139 139 print("checking package data")
140 140 for pkg, data in package_data.items():
141 141 pkg_root = pjoin(*pkg.split('.'))
142 142 for d in data:
143 143 path = pjoin(pkg_root, d)
144 144 if '*' in path:
145 145 assert len(glob(path)) > 0, "No files match pattern %s" % path
146 146 else:
147 147 assert os.path.exists(path), "Missing package data: %s" % path
148 148
149 149
150 150 def check_package_data_first(command):
151 151 """decorator for checking package_data before running a given command
152 152
153 153 Probably only needs to wrap build_py
154 154 """
155 155 class DecoratedCommand(command):
156 156 def run(self):
157 157 check_package_data(self.package_data)
158 158 command.run(self)
159 159 return DecoratedCommand
160 160
161 161
162 162 #---------------------------------------------------------------------------
163 163 # Find data files
164 164 #---------------------------------------------------------------------------
165 165
166 166 def make_dir_struct(tag,base,out_base):
167 167 """Make the directory structure of all files below a starting dir.
168 168
169 169 This is just a convenience routine to help build a nested directory
170 170 hierarchy because distutils is too stupid to do this by itself.
171 171
172 172 XXX - this needs a proper docstring!
173 173 """
174 174
175 175 # we'll use these a lot below
176 176 lbase = len(base)
177 177 pathsep = os.path.sep
178 178 lpathsep = len(pathsep)
179 179
180 180 out = []
181 181 for (dirpath,dirnames,filenames) in os.walk(base):
182 182 # we need to strip out the dirpath from the base to map it to the
183 183 # output (installation) path. This requires possibly stripping the
184 184 # path separator, because otherwise pjoin will not work correctly
185 185 # (pjoin('foo/','/bar') returns '/bar').
186 186
187 187 dp_eff = dirpath[lbase:]
188 188 if dp_eff.startswith(pathsep):
189 189 dp_eff = dp_eff[lpathsep:]
190 190 # The output path must be anchored at the out_base marker
191 191 out_path = pjoin(out_base,dp_eff)
192 192 # Now we can generate the final filenames. Since os.walk only produces
193 193 # filenames, we must join back with the dirpath to get full valid file
194 194 # paths:
195 195 pfiles = [pjoin(dirpath,f) for f in filenames]
196 196 # Finally, generate the entry we need, which is a pari of (output
197 197 # path, files) for use as a data_files parameter in install_data.
198 198 out.append((out_path, pfiles))
199 199
200 200 return out
201 201
202 202
203 203 def find_data_files():
204 204 """
205 205 Find IPython's data_files.
206 206
207 207 Just man pages at this point.
208 208 """
209 209
210 210 manpagebase = pjoin('share', 'man', 'man1')
211 211
212 212 # Simple file lists can be made by hand
213 213 manpages = [f for f in glob(pjoin('docs','man','*.1.gz')) if isfile(f)]
214 214 if not manpages:
215 215 # When running from a source tree, the manpages aren't gzipped
216 216 manpages = [f for f in glob(pjoin('docs','man','*.1')) if isfile(f)]
217 217
218 218 # And assemble the entire output list
219 219 data_files = [ (manpagebase, manpages) ]
220 220
221 221 return data_files
222 222
223 223
224 224 def make_man_update_target(manpage):
225 225 """Return a target_update-compliant tuple for the given manpage.
226 226
227 227 Parameters
228 228 ----------
229 229 manpage : string
230 230 Name of the manpage, must include the section number (trailing number).
231 231
232 232 Example
233 233 -------
234 234
235 235 >>> make_man_update_target('ipython.1') #doctest: +NORMALIZE_WHITESPACE
236 236 ('docs/man/ipython.1.gz',
237 237 ['docs/man/ipython.1'],
238 238 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz')
239 239 """
240 240 man_dir = pjoin('docs', 'man')
241 241 manpage_gz = manpage + '.gz'
242 242 manpath = pjoin(man_dir, manpage)
243 243 manpath_gz = pjoin(man_dir, manpage_gz)
244 244 gz_cmd = ( "cd %(man_dir)s && gzip -9c %(manpage)s > %(manpage_gz)s" %
245 245 locals() )
246 246 return (manpath_gz, [manpath], gz_cmd)
247 247
248 248 # The two functions below are copied from IPython.utils.path, so we don't need
249 249 # to import IPython during setup, which fails on Python 3.
250 250
251 251 def target_outdated(target,deps):
252 252 """Determine whether a target is out of date.
253 253
254 254 target_outdated(target,deps) -> 1/0
255 255
256 256 deps: list of filenames which MUST exist.
257 257 target: single filename which may or may not exist.
258 258
259 259 If target doesn't exist or is older than any file listed in deps, return
260 260 true, otherwise return false.
261 261 """
262 262 try:
263 263 target_time = os.path.getmtime(target)
264 264 except os.error:
265 265 return 1
266 266 for dep in deps:
267 267 dep_time = os.path.getmtime(dep)
268 268 if dep_time > target_time:
269 269 #print "For target",target,"Dep failed:",dep # dbg
270 270 #print "times (dep,tar):",dep_time,target_time # dbg
271 271 return 1
272 272 return 0
273 273
274 274
275 275 def target_update(target,deps,cmd):
276 276 """Update a target with a given command given a list of dependencies.
277 277
278 278 target_update(target,deps,cmd) -> runs cmd if target is outdated.
279 279
280 280 This is just a wrapper around target_outdated() which calls the given
281 281 command if target is outdated."""
282 282
283 283 if target_outdated(target,deps):
284 284 os.system(cmd)
285 285
286 286 #---------------------------------------------------------------------------
287 287 # Find scripts
288 288 #---------------------------------------------------------------------------
289 289
290 290 def find_entry_points():
291 291 """Defines the command line entry points for IPython
292 292
293 293 This always uses setuptools-style entry points. When setuptools is not in
294 294 use, our own build_scripts_entrypt class below parses these and builds
295 295 command line scripts.
296 296
297 297 Each of our entry points gets both a plain name, e.g. ipython, and one
298 298 suffixed with the Python major version number, e.g. ipython3.
299 299 """
300 300 ep = [
301 301 'ipython%s = IPython:start_ipython',
302 302 'iptest%s = IPython.testing.iptestcontroller:main',
303 303 ]
304 304 suffix = str(sys.version_info[0])
305 305 return [e % '' for e in ep] + [e % suffix for e in ep]
306 306
307 307 script_src = """#!{executable}
308 308 # This script was automatically generated by setup.py
309 309 if __name__ == '__main__':
310 310 from {mod} import {func}
311 311 {func}()
312 312 """
313 313
314 314 class build_scripts_entrypt(build_scripts):
315 315 """Build the command line scripts
316 316
317 317 Parse setuptools style entry points and write simple scripts to run the
318 318 target functions.
319 319
320 320 On Windows, this also creates .cmd wrappers for the scripts so that you can
321 321 easily launch them from a command line.
322 322 """
323 323 def run(self):
324 324 self.mkpath(self.build_dir)
325 325 outfiles = []
326 326 for script in find_entry_points():
327 327 name, entrypt = script.split('=')
328 328 name = name.strip()
329 329 entrypt = entrypt.strip()
330 330 outfile = os.path.join(self.build_dir, name)
331 331 outfiles.append(outfile)
332 332 print('Writing script to', outfile)
333 333
334 334 mod, func = entrypt.split(':')
335 335 with open(outfile, 'w') as f:
336 336 f.write(script_src.format(executable=sys.executable,
337 337 mod=mod, func=func))
338 338
339 339 if sys.platform == 'win32':
340 340 # Write .cmd wrappers for Windows so 'ipython' etc. work at the
341 341 # command line
342 342 cmd_file = os.path.join(self.build_dir, name + '.cmd')
343 343 cmd = '@"{python}" "%~dp0\{script}" %*\r\n'.format(
344 344 python=sys.executable, script=name)
345 345 log.info("Writing %s wrapper script" % cmd_file)
346 346 with open(cmd_file, 'w') as f:
347 347 f.write(cmd)
348 348
349 349 return outfiles, outfiles
350 350
351 351 class install_lib_symlink(Command):
352 352 user_options = [
353 353 ('install-dir=', 'd', "directory to install to"),
354 354 ]
355 355
356 356 def initialize_options(self):
357 357 self.install_dir = None
358 358
359 359 def finalize_options(self):
360 360 self.set_undefined_options('symlink',
361 361 ('install_lib', 'install_dir'),
362 362 )
363 363
364 364 def run(self):
365 365 if sys.platform == 'win32':
366 366 raise Exception("This doesn't work on Windows.")
367 367 pkg = os.path.join(os.getcwd(), 'IPython')
368 368 dest = os.path.join(self.install_dir, 'IPython')
369 369 if os.path.islink(dest):
370 370 print('removing existing symlink at %s' % dest)
371 371 os.unlink(dest)
372 372 print('symlinking %s -> %s' % (pkg, dest))
373 373 os.symlink(pkg, dest)
374 374
375 375 class unsymlink(install):
376 376 def run(self):
377 377 dest = os.path.join(self.install_lib, 'IPython')
378 378 if os.path.islink(dest):
379 379 print('removing symlink at %s' % dest)
380 380 os.unlink(dest)
381 381 else:
382 382 print('No symlink exists at %s' % dest)
383 383
384 384 class install_symlinked(install):
385 385 def run(self):
386 386 if sys.platform == 'win32':
387 387 raise Exception("This doesn't work on Windows.")
388 388
389 389 # Run all sub-commands (at least those that need to be run)
390 390 for cmd_name in self.get_sub_commands():
391 391 self.run_command(cmd_name)
392 392
393 393 # 'sub_commands': a list of commands this command might have to run to
394 394 # get its work done. See cmd.py for more info.
395 395 sub_commands = [('install_lib_symlink', lambda self:True),
396 396 ('install_scripts_sym', lambda self:True),
397 397 ]
398 398
399 399 class install_scripts_for_symlink(install_scripts):
400 400 """Redefined to get options from 'symlink' instead of 'install'.
401 401
402 402 I love distutils almost as much as I love setuptools.
403 403 """
404 404 def finalize_options(self):
405 405 self.set_undefined_options('build', ('build_scripts', 'build_dir'))
406 406 self.set_undefined_options('symlink',
407 407 ('install_scripts', 'install_dir'),
408 408 ('force', 'force'),
409 409 ('skip_build', 'skip_build'),
410 410 )
411 411
412 412
413 413 #---------------------------------------------------------------------------
414 414 # VCS related
415 415 #---------------------------------------------------------------------------
416 416
417 417
418 418 def git_prebuild(pkg_dir, build_cmd=build_py):
419 419 """Return extended build or sdist command class for recording commit
420 420
421 421 records git commit in IPython.utils._sysinfo.commit
422 422
423 423 for use in IPython.utils.sysinfo.sys_info() calls after installation.
424 424 """
425 425
426 426 class MyBuildPy(build_cmd):
427 427 ''' Subclass to write commit data into installation tree '''
428 428 def run(self):
429 429 build_cmd.run(self)
430 430 # this one will only fire for build commands
431 431 if hasattr(self, 'build_lib'):
432 432 self._record_commit(self.build_lib)
433 433
434 434 def make_release_tree(self, base_dir, files):
435 435 # this one will fire for sdist
436 436 build_cmd.make_release_tree(self, base_dir, files)
437 437 self._record_commit(base_dir)
438 438
439 439 def _record_commit(self, base_dir):
440 440 import subprocess
441 441 proc = subprocess.Popen('git rev-parse --short HEAD',
442 442 stdout=subprocess.PIPE,
443 443 stderr=subprocess.PIPE,
444 444 shell=True)
445 445 repo_commit, _ = proc.communicate()
446 446 repo_commit = repo_commit.strip().decode("ascii")
447 447
448 448 out_pth = pjoin(base_dir, pkg_dir, 'utils', '_sysinfo.py')
449 449 if os.path.isfile(out_pth) and not repo_commit:
450 450 # nothing to write, don't clobber
451 451 return
452 452
453 453 print("writing git commit '%s' to %s" % (repo_commit, out_pth))
454 454
455 455 # remove to avoid overwriting original via hard link
456 456 try:
457 457 os.remove(out_pth)
458 458 except (IOError, OSError):
459 459 pass
460 460 with open(out_pth, 'w') as out_file:
461 461 out_file.writelines([
462 462 '# GENERATED BY setup.py\n',
463 463 'commit = u"%s"\n' % repo_commit,
464 464 ])
465 465 return MyBuildPy
466 466
1 NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now