##// END OF EJS Templates
Merge pull request #10125 from srinivasreddy/rm_python2_import...
Thomas Kluyver -
r23072:df22d46e merge
parent child Browse files
Show More
@@ -1,54 +1,51 b''
1 1 import unittest
2 try: # Python 3.3 +
3 from unittest.mock import Mock
4 except ImportError:
5 from mock import Mock
2 from unittest.mock import Mock
6 3
7 4 from IPython.core import events
8 5 import IPython.testing.tools as tt
9 6
10 7 def ping_received():
11 8 pass
12 9
13 10 class CallbackTests(unittest.TestCase):
14 11 def setUp(self):
15 12 self.em = events.EventManager(get_ipython(), {'ping_received': ping_received})
16 13
17 14 def test_register_unregister(self):
18 15 cb = Mock()
19 16
20 17 self.em.register('ping_received', cb)
21 18 self.em.trigger('ping_received')
22 19 self.assertEqual(cb.call_count, 1)
23 20
24 21 self.em.unregister('ping_received', cb)
25 22 self.em.trigger('ping_received')
26 23 self.assertEqual(cb.call_count, 1)
27 24
28 25 def test_cb_error(self):
29 26 cb = Mock(side_effect=ValueError)
30 27 self.em.register('ping_received', cb)
31 28 with tt.AssertPrints("Error in callback"):
32 29 self.em.trigger('ping_received')
33 30
34 31 def test_unregister_during_callback(self):
35 32 invoked = [False] * 3
36 33
37 34 def func1(*_):
38 35 invoked[0] = True
39 36 self.em.unregister('ping_received', func1)
40 37 self.em.register('ping_received', func3)
41 38
42 39 def func2(*_):
43 40 invoked[1] = True
44 41 self.em.unregister('ping_received', func2)
45 42
46 43 def func3(*_):
47 44 invoked[2] = True
48 45
49 46 self.em.register('ping_received', func1)
50 47 self.em.register('ping_received', func2)
51 48
52 49 self.em.trigger('ping_received')
53 50 self.assertEqual([True, True, False], invoked)
54 51 self.assertEqual([func3], self.em.callbacks['ping_received'])
@@ -1,906 +1,904 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Tests for the key interactiveshell module.
3 3
4 4 Historically the main classes in interactiveshell have been under-tested. This
5 5 module should grow as many single-method tests as possible to trap many of the
6 6 recurring bugs we seem to encounter with high-level interaction.
7 7 """
8 8
9 9 # Copyright (c) IPython Development Team.
10 10 # Distributed under the terms of the Modified BSD License.
11 11
12 12 import ast
13 13 import os
14 14 import signal
15 15 import shutil
16 16 import sys
17 17 import tempfile
18 18 import unittest
19 try:
20 from unittest import mock
21 except ImportError:
22 import mock
19 from unittest import mock
20
23 21 from os.path import join
24 22
25 23 import nose.tools as nt
26 24
27 25 from IPython.core.error import InputRejected
28 26 from IPython.core.inputtransformer import InputTransformer
29 27 from IPython.testing.decorators import (
30 28 skipif, skip_win32, onlyif_unicode_paths, onlyif_cmds_exist,
31 29 )
32 30 from IPython.testing import tools as tt
33 31 from IPython.utils.process import find_cmd
34 32 from IPython.utils import py3compat
35 33 from IPython.utils.py3compat import PY3
36 34
37 35 if PY3:
38 36 from io import StringIO
39 37 else:
40 38 from StringIO import StringIO
41 39
42 40 #-----------------------------------------------------------------------------
43 41 # Globals
44 42 #-----------------------------------------------------------------------------
45 43 # This is used by every single test, no point repeating it ad nauseam
46 44 ip = get_ipython()
47 45
48 46 #-----------------------------------------------------------------------------
49 47 # Tests
50 48 #-----------------------------------------------------------------------------
51 49
52 50 class DerivedInterrupt(KeyboardInterrupt):
53 51 pass
54 52
55 53 class InteractiveShellTestCase(unittest.TestCase):
56 54 def test_naked_string_cells(self):
57 55 """Test that cells with only naked strings are fully executed"""
58 56 # First, single-line inputs
59 57 ip.run_cell('"a"\n')
60 58 self.assertEqual(ip.user_ns['_'], 'a')
61 59 # And also multi-line cells
62 60 ip.run_cell('"""a\nb"""\n')
63 61 self.assertEqual(ip.user_ns['_'], 'a\nb')
64 62
65 63 def test_run_empty_cell(self):
66 64 """Just make sure we don't get a horrible error with a blank
67 65 cell of input. Yes, I did overlook that."""
68 66 old_xc = ip.execution_count
69 67 res = ip.run_cell('')
70 68 self.assertEqual(ip.execution_count, old_xc)
71 69 self.assertEqual(res.execution_count, None)
72 70
73 71 def test_run_cell_multiline(self):
74 72 """Multi-block, multi-line cells must execute correctly.
75 73 """
76 74 src = '\n'.join(["x=1",
77 75 "y=2",
78 76 "if 1:",
79 77 " x += 1",
80 78 " y += 1",])
81 79 res = ip.run_cell(src)
82 80 self.assertEqual(ip.user_ns['x'], 2)
83 81 self.assertEqual(ip.user_ns['y'], 3)
84 82 self.assertEqual(res.success, True)
85 83 self.assertEqual(res.result, None)
86 84
87 85 def test_multiline_string_cells(self):
88 86 "Code sprinkled with multiline strings should execute (GH-306)"
89 87 ip.run_cell('tmp=0')
90 88 self.assertEqual(ip.user_ns['tmp'], 0)
91 89 res = ip.run_cell('tmp=1;"""a\nb"""\n')
92 90 self.assertEqual(ip.user_ns['tmp'], 1)
93 91 self.assertEqual(res.success, True)
94 92 self.assertEqual(res.result, "a\nb")
95 93
96 94 def test_dont_cache_with_semicolon(self):
97 95 "Ending a line with semicolon should not cache the returned object (GH-307)"
98 96 oldlen = len(ip.user_ns['Out'])
99 97 for cell in ['1;', '1;1;']:
100 98 res = ip.run_cell(cell, store_history=True)
101 99 newlen = len(ip.user_ns['Out'])
102 100 self.assertEqual(oldlen, newlen)
103 101 self.assertIsNone(res.result)
104 102 i = 0
105 103 #also test the default caching behavior
106 104 for cell in ['1', '1;1']:
107 105 ip.run_cell(cell, store_history=True)
108 106 newlen = len(ip.user_ns['Out'])
109 107 i += 1
110 108 self.assertEqual(oldlen+i, newlen)
111 109
112 110 def test_syntax_error(self):
113 111 res = ip.run_cell("raise = 3")
114 112 self.assertIsInstance(res.error_before_exec, SyntaxError)
115 113
116 114 def test_In_variable(self):
117 115 "Verify that In variable grows with user input (GH-284)"
118 116 oldlen = len(ip.user_ns['In'])
119 117 ip.run_cell('1;', store_history=True)
120 118 newlen = len(ip.user_ns['In'])
121 119 self.assertEqual(oldlen+1, newlen)
122 120 self.assertEqual(ip.user_ns['In'][-1],'1;')
123 121
124 122 def test_magic_names_in_string(self):
125 123 ip.run_cell('a = """\n%exit\n"""')
126 124 self.assertEqual(ip.user_ns['a'], '\n%exit\n')
127 125
128 126 def test_trailing_newline(self):
129 127 """test that running !(command) does not raise a SyntaxError"""
130 128 ip.run_cell('!(true)\n', False)
131 129 ip.run_cell('!(true)\n\n\n', False)
132 130
133 131 def test_gh_597(self):
134 132 """Pretty-printing lists of objects with non-ascii reprs may cause
135 133 problems."""
136 134 class Spam(object):
137 135 def __repr__(self):
138 136 return "\xe9"*50
139 137 import IPython.core.formatters
140 138 f = IPython.core.formatters.PlainTextFormatter()
141 139 f([Spam(),Spam()])
142 140
143 141
144 142 def test_future_flags(self):
145 143 """Check that future flags are used for parsing code (gh-777)"""
146 144 ip.run_cell('from __future__ import barry_as_FLUFL')
147 145 try:
148 146 ip.run_cell('prfunc_return_val = 1 <> 2')
149 147 assert 'prfunc_return_val' in ip.user_ns
150 148 finally:
151 149 # Reset compiler flags so we don't mess up other tests.
152 150 ip.compile.reset_compiler_flags()
153 151
154 152 def test_can_pickle(self):
155 153 "Can we pickle objects defined interactively (GH-29)"
156 154 ip = get_ipython()
157 155 ip.reset()
158 156 ip.run_cell(("class Mylist(list):\n"
159 157 " def __init__(self,x=[]):\n"
160 158 " list.__init__(self,x)"))
161 159 ip.run_cell("w=Mylist([1,2,3])")
162 160
163 161 from pickle import dumps
164 162
165 163 # We need to swap in our main module - this is only necessary
166 164 # inside the test framework, because IPython puts the interactive module
167 165 # in place (but the test framework undoes this).
168 166 _main = sys.modules['__main__']
169 167 sys.modules['__main__'] = ip.user_module
170 168 try:
171 169 res = dumps(ip.user_ns["w"])
172 170 finally:
173 171 sys.modules['__main__'] = _main
174 172 self.assertTrue(isinstance(res, bytes))
175 173
176 174 def test_global_ns(self):
177 175 "Code in functions must be able to access variables outside them."
178 176 ip = get_ipython()
179 177 ip.run_cell("a = 10")
180 178 ip.run_cell(("def f(x):\n"
181 179 " return x + a"))
182 180 ip.run_cell("b = f(12)")
183 181 self.assertEqual(ip.user_ns["b"], 22)
184 182
185 183 def test_bad_custom_tb(self):
186 184 """Check that InteractiveShell is protected from bad custom exception handlers"""
187 185 ip.set_custom_exc((IOError,), lambda etype,value,tb: 1/0)
188 186 self.assertEqual(ip.custom_exceptions, (IOError,))
189 187 with tt.AssertPrints("Custom TB Handler failed", channel='stderr'):
190 188 ip.run_cell(u'raise IOError("foo")')
191 189 self.assertEqual(ip.custom_exceptions, ())
192 190
193 191 def test_bad_custom_tb_return(self):
194 192 """Check that InteractiveShell is protected from bad return types in custom exception handlers"""
195 193 ip.set_custom_exc((NameError,),lambda etype,value,tb, tb_offset=None: 1)
196 194 self.assertEqual(ip.custom_exceptions, (NameError,))
197 195 with tt.AssertPrints("Custom TB Handler failed", channel='stderr'):
198 196 ip.run_cell(u'a=abracadabra')
199 197 self.assertEqual(ip.custom_exceptions, ())
200 198
201 199 def test_drop_by_id(self):
202 200 myvars = {"a":object(), "b":object(), "c": object()}
203 201 ip.push(myvars, interactive=False)
204 202 for name in myvars:
205 203 assert name in ip.user_ns, name
206 204 assert name in ip.user_ns_hidden, name
207 205 ip.user_ns['b'] = 12
208 206 ip.drop_by_id(myvars)
209 207 for name in ["a", "c"]:
210 208 assert name not in ip.user_ns, name
211 209 assert name not in ip.user_ns_hidden, name
212 210 assert ip.user_ns['b'] == 12
213 211 ip.reset()
214 212
215 213 def test_var_expand(self):
216 214 ip.user_ns['f'] = u'Ca\xf1o'
217 215 self.assertEqual(ip.var_expand(u'echo $f'), u'echo Ca\xf1o')
218 216 self.assertEqual(ip.var_expand(u'echo {f}'), u'echo Ca\xf1o')
219 217 self.assertEqual(ip.var_expand(u'echo {f[:-1]}'), u'echo Ca\xf1')
220 218 self.assertEqual(ip.var_expand(u'echo {1*2}'), u'echo 2')
221 219
222 220 ip.user_ns['f'] = b'Ca\xc3\xb1o'
223 221 # This should not raise any exception:
224 222 ip.var_expand(u'echo $f')
225 223
226 224 def test_var_expand_local(self):
227 225 """Test local variable expansion in !system and %magic calls"""
228 226 # !system
229 227 ip.run_cell('def test():\n'
230 228 ' lvar = "ttt"\n'
231 229 ' ret = !echo {lvar}\n'
232 230 ' return ret[0]\n')
233 231 res = ip.user_ns['test']()
234 232 nt.assert_in('ttt', res)
235 233
236 234 # %magic
237 235 ip.run_cell('def makemacro():\n'
238 236 ' macroname = "macro_var_expand_locals"\n'
239 237 ' %macro {macroname} codestr\n')
240 238 ip.user_ns['codestr'] = "str(12)"
241 239 ip.run_cell('makemacro()')
242 240 nt.assert_in('macro_var_expand_locals', ip.user_ns)
243 241
244 242 def test_var_expand_self(self):
245 243 """Test variable expansion with the name 'self', which was failing.
246 244
247 245 See https://github.com/ipython/ipython/issues/1878#issuecomment-7698218
248 246 """
249 247 ip.run_cell('class cTest:\n'
250 248 ' classvar="see me"\n'
251 249 ' def test(self):\n'
252 250 ' res = !echo Variable: {self.classvar}\n'
253 251 ' return res[0]\n')
254 252 nt.assert_in('see me', ip.user_ns['cTest']().test())
255 253
256 254 def test_bad_var_expand(self):
257 255 """var_expand on invalid formats shouldn't raise"""
258 256 # SyntaxError
259 257 self.assertEqual(ip.var_expand(u"{'a':5}"), u"{'a':5}")
260 258 # NameError
261 259 self.assertEqual(ip.var_expand(u"{asdf}"), u"{asdf}")
262 260 # ZeroDivisionError
263 261 self.assertEqual(ip.var_expand(u"{1/0}"), u"{1/0}")
264 262
265 263 def test_silent_postexec(self):
266 264 """run_cell(silent=True) doesn't invoke pre/post_run_cell callbacks"""
267 265 pre_explicit = mock.Mock()
268 266 pre_always = mock.Mock()
269 267 post_explicit = mock.Mock()
270 268 post_always = mock.Mock()
271 269
272 270 ip.events.register('pre_run_cell', pre_explicit)
273 271 ip.events.register('pre_execute', pre_always)
274 272 ip.events.register('post_run_cell', post_explicit)
275 273 ip.events.register('post_execute', post_always)
276 274
277 275 try:
278 276 ip.run_cell("1", silent=True)
279 277 assert pre_always.called
280 278 assert not pre_explicit.called
281 279 assert post_always.called
282 280 assert not post_explicit.called
283 281 # double-check that non-silent exec did what we expected
284 282 # silent to avoid
285 283 ip.run_cell("1")
286 284 assert pre_explicit.called
287 285 assert post_explicit.called
288 286 finally:
289 287 # remove post-exec
290 288 ip.events.unregister('pre_run_cell', pre_explicit)
291 289 ip.events.unregister('pre_execute', pre_always)
292 290 ip.events.unregister('post_run_cell', post_explicit)
293 291 ip.events.unregister('post_execute', post_always)
294 292
295 293 def test_silent_noadvance(self):
296 294 """run_cell(silent=True) doesn't advance execution_count"""
297 295 ec = ip.execution_count
298 296 # silent should force store_history=False
299 297 ip.run_cell("1", store_history=True, silent=True)
300 298
301 299 self.assertEqual(ec, ip.execution_count)
302 300 # double-check that non-silent exec did what we expected
303 301 # silent to avoid
304 302 ip.run_cell("1", store_history=True)
305 303 self.assertEqual(ec+1, ip.execution_count)
306 304
307 305 def test_silent_nodisplayhook(self):
308 306 """run_cell(silent=True) doesn't trigger displayhook"""
309 307 d = dict(called=False)
310 308
311 309 trap = ip.display_trap
312 310 save_hook = trap.hook
313 311
314 312 def failing_hook(*args, **kwargs):
315 313 d['called'] = True
316 314
317 315 try:
318 316 trap.hook = failing_hook
319 317 res = ip.run_cell("1", silent=True)
320 318 self.assertFalse(d['called'])
321 319 self.assertIsNone(res.result)
322 320 # double-check that non-silent exec did what we expected
323 321 # silent to avoid
324 322 ip.run_cell("1")
325 323 self.assertTrue(d['called'])
326 324 finally:
327 325 trap.hook = save_hook
328 326
329 327 def test_ofind_line_magic(self):
330 328 from IPython.core.magic import register_line_magic
331 329
332 330 @register_line_magic
333 331 def lmagic(line):
334 332 "A line magic"
335 333
336 334 # Get info on line magic
337 335 lfind = ip._ofind('lmagic')
338 336 info = dict(found=True, isalias=False, ismagic=True,
339 337 namespace = 'IPython internal', obj= lmagic.__wrapped__,
340 338 parent = None)
341 339 nt.assert_equal(lfind, info)
342 340
343 341 def test_ofind_cell_magic(self):
344 342 from IPython.core.magic import register_cell_magic
345 343
346 344 @register_cell_magic
347 345 def cmagic(line, cell):
348 346 "A cell magic"
349 347
350 348 # Get info on cell magic
351 349 find = ip._ofind('cmagic')
352 350 info = dict(found=True, isalias=False, ismagic=True,
353 351 namespace = 'IPython internal', obj= cmagic.__wrapped__,
354 352 parent = None)
355 353 nt.assert_equal(find, info)
356 354
357 355 def test_ofind_property_with_error(self):
358 356 class A(object):
359 357 @property
360 358 def foo(self):
361 359 raise NotImplementedError()
362 360 a = A()
363 361
364 362 found = ip._ofind('a.foo', [('locals', locals())])
365 363 info = dict(found=True, isalias=False, ismagic=False,
366 364 namespace='locals', obj=A.foo, parent=a)
367 365 nt.assert_equal(found, info)
368 366
369 367 def test_ofind_multiple_attribute_lookups(self):
370 368 class A(object):
371 369 @property
372 370 def foo(self):
373 371 raise NotImplementedError()
374 372
375 373 a = A()
376 374 a.a = A()
377 375 a.a.a = A()
378 376
379 377 found = ip._ofind('a.a.a.foo', [('locals', locals())])
380 378 info = dict(found=True, isalias=False, ismagic=False,
381 379 namespace='locals', obj=A.foo, parent=a.a.a)
382 380 nt.assert_equal(found, info)
383 381
384 382 def test_ofind_slotted_attributes(self):
385 383 class A(object):
386 384 __slots__ = ['foo']
387 385 def __init__(self):
388 386 self.foo = 'bar'
389 387
390 388 a = A()
391 389 found = ip._ofind('a.foo', [('locals', locals())])
392 390 info = dict(found=True, isalias=False, ismagic=False,
393 391 namespace='locals', obj=a.foo, parent=a)
394 392 nt.assert_equal(found, info)
395 393
396 394 found = ip._ofind('a.bar', [('locals', locals())])
397 395 info = dict(found=False, isalias=False, ismagic=False,
398 396 namespace=None, obj=None, parent=a)
399 397 nt.assert_equal(found, info)
400 398
401 399 def test_ofind_prefers_property_to_instance_level_attribute(self):
402 400 class A(object):
403 401 @property
404 402 def foo(self):
405 403 return 'bar'
406 404 a = A()
407 405 a.__dict__['foo'] = 'baz'
408 406 nt.assert_equal(a.foo, 'bar')
409 407 found = ip._ofind('a.foo', [('locals', locals())])
410 408 nt.assert_is(found['obj'], A.foo)
411 409
412 410 def test_custom_syntaxerror_exception(self):
413 411 called = []
414 412 def my_handler(shell, etype, value, tb, tb_offset=None):
415 413 called.append(etype)
416 414 shell.showtraceback((etype, value, tb), tb_offset=tb_offset)
417 415
418 416 ip.set_custom_exc((SyntaxError,), my_handler)
419 417 try:
420 418 ip.run_cell("1f")
421 419 # Check that this was called, and only once.
422 420 self.assertEqual(called, [SyntaxError])
423 421 finally:
424 422 # Reset the custom exception hook
425 423 ip.set_custom_exc((), None)
426 424
427 425 def test_custom_exception(self):
428 426 called = []
429 427 def my_handler(shell, etype, value, tb, tb_offset=None):
430 428 called.append(etype)
431 429 shell.showtraceback((etype, value, tb), tb_offset=tb_offset)
432 430
433 431 ip.set_custom_exc((ValueError,), my_handler)
434 432 try:
435 433 res = ip.run_cell("raise ValueError('test')")
436 434 # Check that this was called, and only once.
437 435 self.assertEqual(called, [ValueError])
438 436 # Check that the error is on the result object
439 437 self.assertIsInstance(res.error_in_exec, ValueError)
440 438 finally:
441 439 # Reset the custom exception hook
442 440 ip.set_custom_exc((), None)
443 441
444 442 def test_mktempfile(self):
445 443 filename = ip.mktempfile()
446 444 # Check that we can open the file again on Windows
447 445 with open(filename, 'w') as f:
448 446 f.write('abc')
449 447
450 448 filename = ip.mktempfile(data='blah')
451 449 with open(filename, 'r') as f:
452 450 self.assertEqual(f.read(), 'blah')
453 451
454 452 def test_new_main_mod(self):
455 453 # Smoketest to check that this accepts a unicode module name
456 454 name = u'jiefmw'
457 455 mod = ip.new_main_mod(u'%s.py' % name, name)
458 456 self.assertEqual(mod.__name__, name)
459 457
460 458 def test_get_exception_only(self):
461 459 try:
462 460 raise KeyboardInterrupt
463 461 except KeyboardInterrupt:
464 462 msg = ip.get_exception_only()
465 463 self.assertEqual(msg, 'KeyboardInterrupt\n')
466 464
467 465 try:
468 466 raise DerivedInterrupt("foo")
469 467 except KeyboardInterrupt:
470 468 msg = ip.get_exception_only()
471 469 self.assertEqual(msg, 'IPython.core.tests.test_interactiveshell.DerivedInterrupt: foo\n')
472 470
473 471 def test_inspect_text(self):
474 472 ip.run_cell('a = 5')
475 473 text = ip.object_inspect_text('a')
476 474 self.assertIsInstance(text, str)
477 475
478 476
479 477 class TestSafeExecfileNonAsciiPath(unittest.TestCase):
480 478
481 479 @onlyif_unicode_paths
482 480 def setUp(self):
483 481 self.BASETESTDIR = tempfile.mkdtemp()
484 482 self.TESTDIR = join(self.BASETESTDIR, u"Γ₯Àâ")
485 483 os.mkdir(self.TESTDIR)
486 484 with open(join(self.TESTDIR, u"Γ₯Àâtestscript.py"), "w") as sfile:
487 485 sfile.write("pass\n")
488 486 self.oldpath = os.getcwd()
489 487 os.chdir(self.TESTDIR)
490 488 self.fname = u"Γ₯Àâtestscript.py"
491 489
492 490 def tearDown(self):
493 491 os.chdir(self.oldpath)
494 492 shutil.rmtree(self.BASETESTDIR)
495 493
496 494 @onlyif_unicode_paths
497 495 def test_1(self):
498 496 """Test safe_execfile with non-ascii path
499 497 """
500 498 ip.safe_execfile(self.fname, {}, raise_exceptions=True)
501 499
502 500 class ExitCodeChecks(tt.TempFileMixin):
503 501 def test_exit_code_ok(self):
504 502 self.system('exit 0')
505 503 self.assertEqual(ip.user_ns['_exit_code'], 0)
506 504
507 505 def test_exit_code_error(self):
508 506 self.system('exit 1')
509 507 self.assertEqual(ip.user_ns['_exit_code'], 1)
510 508
511 509 @skipif(not hasattr(signal, 'SIGALRM'))
512 510 def test_exit_code_signal(self):
513 511 self.mktmp("import signal, time\n"
514 512 "signal.setitimer(signal.ITIMER_REAL, 0.1)\n"
515 513 "time.sleep(1)\n")
516 514 self.system("%s %s" % (sys.executable, self.fname))
517 515 self.assertEqual(ip.user_ns['_exit_code'], -signal.SIGALRM)
518 516
519 517 @onlyif_cmds_exist("csh")
520 518 def test_exit_code_signal_csh(self):
521 519 SHELL = os.environ.get('SHELL', None)
522 520 os.environ['SHELL'] = find_cmd("csh")
523 521 try:
524 522 self.test_exit_code_signal()
525 523 finally:
526 524 if SHELL is not None:
527 525 os.environ['SHELL'] = SHELL
528 526 else:
529 527 del os.environ['SHELL']
530 528
531 529 class TestSystemRaw(unittest.TestCase, ExitCodeChecks):
532 530 system = ip.system_raw
533 531
534 532 @onlyif_unicode_paths
535 533 def test_1(self):
536 534 """Test system_raw with non-ascii cmd
537 535 """
538 536 cmd = u'''python -c "'Γ₯Àâ'" '''
539 537 ip.system_raw(cmd)
540 538
541 539 @mock.patch('subprocess.call', side_effect=KeyboardInterrupt)
542 540 @mock.patch('os.system', side_effect=KeyboardInterrupt)
543 541 def test_control_c(self, *mocks):
544 542 try:
545 543 self.system("sleep 1 # wont happen")
546 544 except KeyboardInterrupt:
547 545 self.fail("system call should intercept "
548 546 "keyboard interrupt from subprocess.call")
549 547 self.assertEqual(ip.user_ns['_exit_code'], -signal.SIGINT)
550 548
551 549 # TODO: Exit codes are currently ignored on Windows.
552 550 class TestSystemPipedExitCode(unittest.TestCase, ExitCodeChecks):
553 551 system = ip.system_piped
554 552
555 553 @skip_win32
556 554 def test_exit_code_ok(self):
557 555 ExitCodeChecks.test_exit_code_ok(self)
558 556
559 557 @skip_win32
560 558 def test_exit_code_error(self):
561 559 ExitCodeChecks.test_exit_code_error(self)
562 560
563 561 @skip_win32
564 562 def test_exit_code_signal(self):
565 563 ExitCodeChecks.test_exit_code_signal(self)
566 564
567 565 class TestModules(unittest.TestCase, tt.TempFileMixin):
568 566 def test_extraneous_loads(self):
569 567 """Test we're not loading modules on startup that we shouldn't.
570 568 """
571 569 self.mktmp("import sys\n"
572 570 "print('numpy' in sys.modules)\n"
573 571 "print('ipyparallel' in sys.modules)\n"
574 572 "print('ipykernel' in sys.modules)\n"
575 573 )
576 574 out = "False\nFalse\nFalse\n"
577 575 tt.ipexec_validate(self.fname, out)
578 576
579 577 class Negator(ast.NodeTransformer):
580 578 """Negates all number literals in an AST."""
581 579 def visit_Num(self, node):
582 580 node.n = -node.n
583 581 return node
584 582
585 583 class TestAstTransform(unittest.TestCase):
586 584 def setUp(self):
587 585 self.negator = Negator()
588 586 ip.ast_transformers.append(self.negator)
589 587
590 588 def tearDown(self):
591 589 ip.ast_transformers.remove(self.negator)
592 590
593 591 def test_run_cell(self):
594 592 with tt.AssertPrints('-34'):
595 593 ip.run_cell('print (12 + 22)')
596 594
597 595 # A named reference to a number shouldn't be transformed.
598 596 ip.user_ns['n'] = 55
599 597 with tt.AssertNotPrints('-55'):
600 598 ip.run_cell('print (n)')
601 599
602 600 def test_timeit(self):
603 601 called = set()
604 602 def f(x):
605 603 called.add(x)
606 604 ip.push({'f':f})
607 605
608 606 with tt.AssertPrints("average of "):
609 607 ip.run_line_magic("timeit", "-n1 f(1)")
610 608 self.assertEqual(called, {-1})
611 609 called.clear()
612 610
613 611 with tt.AssertPrints("average of "):
614 612 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
615 613 self.assertEqual(called, {-2, -3})
616 614
617 615 def test_time(self):
618 616 called = []
619 617 def f(x):
620 618 called.append(x)
621 619 ip.push({'f':f})
622 620
623 621 # Test with an expression
624 622 with tt.AssertPrints("Wall time: "):
625 623 ip.run_line_magic("time", "f(5+9)")
626 624 self.assertEqual(called, [-14])
627 625 called[:] = []
628 626
629 627 # Test with a statement (different code path)
630 628 with tt.AssertPrints("Wall time: "):
631 629 ip.run_line_magic("time", "a = f(-3 + -2)")
632 630 self.assertEqual(called, [5])
633 631
634 632 def test_macro(self):
635 633 ip.push({'a':10})
636 634 # The AST transformation makes this do a+=-1
637 635 ip.define_macro("amacro", "a+=1\nprint(a)")
638 636
639 637 with tt.AssertPrints("9"):
640 638 ip.run_cell("amacro")
641 639 with tt.AssertPrints("8"):
642 640 ip.run_cell("amacro")
643 641
644 642 class IntegerWrapper(ast.NodeTransformer):
645 643 """Wraps all integers in a call to Integer()"""
646 644 def visit_Num(self, node):
647 645 if isinstance(node.n, int):
648 646 return ast.Call(func=ast.Name(id='Integer', ctx=ast.Load()),
649 647 args=[node], keywords=[])
650 648 return node
651 649
652 650 class TestAstTransform2(unittest.TestCase):
653 651 def setUp(self):
654 652 self.intwrapper = IntegerWrapper()
655 653 ip.ast_transformers.append(self.intwrapper)
656 654
657 655 self.calls = []
658 656 def Integer(*args):
659 657 self.calls.append(args)
660 658 return args
661 659 ip.push({"Integer": Integer})
662 660
663 661 def tearDown(self):
664 662 ip.ast_transformers.remove(self.intwrapper)
665 663 del ip.user_ns['Integer']
666 664
667 665 def test_run_cell(self):
668 666 ip.run_cell("n = 2")
669 667 self.assertEqual(self.calls, [(2,)])
670 668
671 669 # This shouldn't throw an error
672 670 ip.run_cell("o = 2.0")
673 671 self.assertEqual(ip.user_ns['o'], 2.0)
674 672
675 673 def test_timeit(self):
676 674 called = set()
677 675 def f(x):
678 676 called.add(x)
679 677 ip.push({'f':f})
680 678
681 679 with tt.AssertPrints("average of "):
682 680 ip.run_line_magic("timeit", "-n1 f(1)")
683 681 self.assertEqual(called, {(1,)})
684 682 called.clear()
685 683
686 684 with tt.AssertPrints("average of "):
687 685 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
688 686 self.assertEqual(called, {(2,), (3,)})
689 687
690 688 class ErrorTransformer(ast.NodeTransformer):
691 689 """Throws an error when it sees a number."""
692 690 def visit_Num(self, node):
693 691 raise ValueError("test")
694 692
695 693 class TestAstTransformError(unittest.TestCase):
696 694 def test_unregistering(self):
697 695 err_transformer = ErrorTransformer()
698 696 ip.ast_transformers.append(err_transformer)
699 697
700 698 with tt.AssertPrints("unregister", channel='stderr'):
701 699 ip.run_cell("1 + 2")
702 700
703 701 # This should have been removed.
704 702 nt.assert_not_in(err_transformer, ip.ast_transformers)
705 703
706 704
707 705 class StringRejector(ast.NodeTransformer):
708 706 """Throws an InputRejected when it sees a string literal.
709 707
710 708 Used to verify that NodeTransformers can signal that a piece of code should
711 709 not be executed by throwing an InputRejected.
712 710 """
713 711
714 712 def visit_Str(self, node):
715 713 raise InputRejected("test")
716 714
717 715
718 716 class TestAstTransformInputRejection(unittest.TestCase):
719 717
720 718 def setUp(self):
721 719 self.transformer = StringRejector()
722 720 ip.ast_transformers.append(self.transformer)
723 721
724 722 def tearDown(self):
725 723 ip.ast_transformers.remove(self.transformer)
726 724
727 725 def test_input_rejection(self):
728 726 """Check that NodeTransformers can reject input."""
729 727
730 728 expect_exception_tb = tt.AssertPrints("InputRejected: test")
731 729 expect_no_cell_output = tt.AssertNotPrints("'unsafe'", suppress=False)
732 730
733 731 # Run the same check twice to verify that the transformer is not
734 732 # disabled after raising.
735 733 with expect_exception_tb, expect_no_cell_output:
736 734 ip.run_cell("'unsafe'")
737 735
738 736 with expect_exception_tb, expect_no_cell_output:
739 737 res = ip.run_cell("'unsafe'")
740 738
741 739 self.assertIsInstance(res.error_before_exec, InputRejected)
742 740
743 741 def test__IPYTHON__():
744 742 # This shouldn't raise a NameError, that's all
745 743 __IPYTHON__
746 744
747 745
748 746 class DummyRepr(object):
749 747 def __repr__(self):
750 748 return "DummyRepr"
751 749
752 750 def _repr_html_(self):
753 751 return "<b>dummy</b>"
754 752
755 753 def _repr_javascript_(self):
756 754 return "console.log('hi');", {'key': 'value'}
757 755
758 756
759 757 def test_user_variables():
760 758 # enable all formatters
761 759 ip.display_formatter.active_types = ip.display_formatter.format_types
762 760
763 761 ip.user_ns['dummy'] = d = DummyRepr()
764 762 keys = {'dummy', 'doesnotexist'}
765 763 r = ip.user_expressions({ key:key for key in keys})
766 764
767 765 nt.assert_equal(keys, set(r.keys()))
768 766 dummy = r['dummy']
769 767 nt.assert_equal({'status', 'data', 'metadata'}, set(dummy.keys()))
770 768 nt.assert_equal(dummy['status'], 'ok')
771 769 data = dummy['data']
772 770 metadata = dummy['metadata']
773 771 nt.assert_equal(data.get('text/html'), d._repr_html_())
774 772 js, jsmd = d._repr_javascript_()
775 773 nt.assert_equal(data.get('application/javascript'), js)
776 774 nt.assert_equal(metadata.get('application/javascript'), jsmd)
777 775
778 776 dne = r['doesnotexist']
779 777 nt.assert_equal(dne['status'], 'error')
780 778 nt.assert_equal(dne['ename'], 'NameError')
781 779
782 780 # back to text only
783 781 ip.display_formatter.active_types = ['text/plain']
784 782
785 783 def test_user_expression():
786 784 # enable all formatters
787 785 ip.display_formatter.active_types = ip.display_formatter.format_types
788 786 query = {
789 787 'a' : '1 + 2',
790 788 'b' : '1/0',
791 789 }
792 790 r = ip.user_expressions(query)
793 791 import pprint
794 792 pprint.pprint(r)
795 793 nt.assert_equal(set(r.keys()), set(query.keys()))
796 794 a = r['a']
797 795 nt.assert_equal({'status', 'data', 'metadata'}, set(a.keys()))
798 796 nt.assert_equal(a['status'], 'ok')
799 797 data = a['data']
800 798 metadata = a['metadata']
801 799 nt.assert_equal(data.get('text/plain'), '3')
802 800
803 801 b = r['b']
804 802 nt.assert_equal(b['status'], 'error')
805 803 nt.assert_equal(b['ename'], 'ZeroDivisionError')
806 804
807 805 # back to text only
808 806 ip.display_formatter.active_types = ['text/plain']
809 807
810 808
811 809
812 810
813 811
814 812 class TestSyntaxErrorTransformer(unittest.TestCase):
815 813 """Check that SyntaxError raised by an input transformer is handled by run_cell()"""
816 814
817 815 class SyntaxErrorTransformer(InputTransformer):
818 816
819 817 def push(self, line):
820 818 pos = line.find('syntaxerror')
821 819 if pos >= 0:
822 820 e = SyntaxError('input contains "syntaxerror"')
823 821 e.text = line
824 822 e.offset = pos + 1
825 823 raise e
826 824 return line
827 825
828 826 def reset(self):
829 827 pass
830 828
831 829 def setUp(self):
832 830 self.transformer = TestSyntaxErrorTransformer.SyntaxErrorTransformer()
833 831 ip.input_splitter.python_line_transforms.append(self.transformer)
834 832 ip.input_transformer_manager.python_line_transforms.append(self.transformer)
835 833
836 834 def tearDown(self):
837 835 ip.input_splitter.python_line_transforms.remove(self.transformer)
838 836 ip.input_transformer_manager.python_line_transforms.remove(self.transformer)
839 837
840 838 def test_syntaxerror_input_transformer(self):
841 839 with tt.AssertPrints('1234'):
842 840 ip.run_cell('1234')
843 841 with tt.AssertPrints('SyntaxError: invalid syntax'):
844 842 ip.run_cell('1 2 3') # plain python syntax error
845 843 with tt.AssertPrints('SyntaxError: input contains "syntaxerror"'):
846 844 ip.run_cell('2345 # syntaxerror') # input transformer syntax error
847 845 with tt.AssertPrints('3456'):
848 846 ip.run_cell('3456')
849 847
850 848
851 849
852 850 def test_warning_suppression():
853 851 ip.run_cell("import warnings")
854 852 try:
855 853 with tt.AssertPrints("UserWarning: asdf", channel="stderr"):
856 854 ip.run_cell("warnings.warn('asdf')")
857 855 # Here's the real test -- if we run that again, we should get the
858 856 # warning again. Traditionally, each warning was only issued once per
859 857 # IPython session (approximately), even if the user typed in new and
860 858 # different code that should have also triggered the warning, leading
861 859 # to much confusion.
862 860 with tt.AssertPrints("UserWarning: asdf", channel="stderr"):
863 861 ip.run_cell("warnings.warn('asdf')")
864 862 finally:
865 863 ip.run_cell("del warnings")
866 864
867 865
868 866 def test_deprecation_warning():
869 867 ip.run_cell("""
870 868 import warnings
871 869 def wrn():
872 870 warnings.warn(
873 871 "I AM A WARNING",
874 872 DeprecationWarning
875 873 )
876 874 """)
877 875 try:
878 876 with tt.AssertPrints("I AM A WARNING", channel="stderr"):
879 877 ip.run_cell("wrn()")
880 878 finally:
881 879 ip.run_cell("del warnings")
882 880 ip.run_cell("del wrn")
883 881
884 882
885 883 class TestImportNoDeprecate(tt.TempFileMixin):
886 884
887 885 def setup(self):
888 886 """Make a valid python temp file."""
889 887 self.mktmp("""
890 888 import warnings
891 889 def wrn():
892 890 warnings.warn(
893 891 "I AM A WARNING",
894 892 DeprecationWarning
895 893 )
896 894 """)
897 895
898 896 def test_no_dep(self):
899 897 """
900 898 No deprecation warning should be raised from imported functions
901 899 """
902 900 ip.run_cell("from {} import wrn".format(self.fname))
903 901
904 902 with tt.AssertNotPrints("I AM A WARNING"):
905 903 ip.run_cell("wrn()")
906 904 ip.run_cell("del wrn")
@@ -1,204 +1,200 b''
1 1 import errno
2 2 import os
3 3 import shutil
4 4 import sys
5 5 import tempfile
6 6 import warnings
7
8 try: # Python 3
9 from unittest.mock import patch
10 except ImportError: # Python 2
11 from mock import patch
7 from unittest.mock import patch
12 8
13 9 import nose.tools as nt
14 10 from testpath import modified_env, assert_isdir, assert_isfile
15 11
16 12 from IPython import paths
17 13 from IPython.testing.decorators import skip_win32
18 14 from IPython.utils.tempdir import TemporaryDirectory
19 15
20 16 TMP_TEST_DIR = os.path.realpath(tempfile.mkdtemp())
21 17 HOME_TEST_DIR = os.path.join(TMP_TEST_DIR, "home_test_dir")
22 18 XDG_TEST_DIR = os.path.join(HOME_TEST_DIR, "xdg_test_dir")
23 19 XDG_CACHE_DIR = os.path.join(HOME_TEST_DIR, "xdg_cache_dir")
24 20 IP_TEST_DIR = os.path.join(HOME_TEST_DIR,'.ipython')
25 21
26 22 def setup():
27 23 """Setup testenvironment for the module:
28 24
29 25 - Adds dummy home dir tree
30 26 """
31 27 # Do not mask exceptions here. In particular, catching WindowsError is a
32 28 # problem because that exception is only defined on Windows...
33 29 os.makedirs(IP_TEST_DIR)
34 30 os.makedirs(os.path.join(XDG_TEST_DIR, 'ipython'))
35 31 os.makedirs(os.path.join(XDG_CACHE_DIR, 'ipython'))
36 32
37 33
38 34 def teardown():
39 35 """Teardown testenvironment for the module:
40 36
41 37 - Remove dummy home dir tree
42 38 """
43 39 # Note: we remove the parent test dir, which is the root of all test
44 40 # subdirs we may have created. Use shutil instead of os.removedirs, so
45 41 # that non-empty directories are all recursively removed.
46 42 shutil.rmtree(TMP_TEST_DIR)
47 43
48 44 def patch_get_home_dir(dirpath):
49 45 return patch.object(paths, 'get_home_dir', return_value=dirpath)
50 46
51 47
52 48 def test_get_ipython_dir_1():
53 49 """test_get_ipython_dir_1, Testcase to see if we can call get_ipython_dir without Exceptions."""
54 50 env_ipdir = os.path.join("someplace", ".ipython")
55 51 with patch.object(paths, '_writable_dir', return_value=True), \
56 52 modified_env({'IPYTHONDIR': env_ipdir}):
57 53 ipdir = paths.get_ipython_dir()
58 54
59 55 nt.assert_equal(ipdir, env_ipdir)
60 56
61 57 def test_get_ipython_dir_2():
62 58 """test_get_ipython_dir_2, Testcase to see if we can call get_ipython_dir without Exceptions."""
63 59 with patch_get_home_dir('someplace'), \
64 60 patch.object(paths, 'get_xdg_dir', return_value=None), \
65 61 patch.object(paths, '_writable_dir', return_value=True), \
66 62 patch('os.name', "posix"), \
67 63 modified_env({'IPYTHON_DIR': None,
68 64 'IPYTHONDIR': None,
69 65 'XDG_CONFIG_HOME': None
70 66 }):
71 67 ipdir = paths.get_ipython_dir()
72 68
73 69 nt.assert_equal(ipdir, os.path.join("someplace", ".ipython"))
74 70
75 71 def test_get_ipython_dir_3():
76 72 """test_get_ipython_dir_3, move XDG if defined, and .ipython doesn't exist."""
77 73 tmphome = TemporaryDirectory()
78 74 try:
79 75 with patch_get_home_dir(tmphome.name), \
80 76 patch('os.name', 'posix'), \
81 77 modified_env({
82 78 'IPYTHON_DIR': None,
83 79 'IPYTHONDIR': None,
84 80 'XDG_CONFIG_HOME': XDG_TEST_DIR,
85 81 }), warnings.catch_warnings(record=True) as w:
86 82 ipdir = paths.get_ipython_dir()
87 83
88 84 nt.assert_equal(ipdir, os.path.join(tmphome.name, ".ipython"))
89 85 if sys.platform != 'darwin':
90 86 nt.assert_equal(len(w), 1)
91 87 nt.assert_in('Moving', str(w[0]))
92 88 finally:
93 89 tmphome.cleanup()
94 90
95 91 def test_get_ipython_dir_4():
96 92 """test_get_ipython_dir_4, warn if XDG and home both exist."""
97 93 with patch_get_home_dir(HOME_TEST_DIR), \
98 94 patch('os.name', 'posix'):
99 95 try:
100 96 os.mkdir(os.path.join(XDG_TEST_DIR, 'ipython'))
101 97 except OSError as e:
102 98 if e.errno != errno.EEXIST:
103 99 raise
104 100
105 101
106 102 with modified_env({
107 103 'IPYTHON_DIR': None,
108 104 'IPYTHONDIR': None,
109 105 'XDG_CONFIG_HOME': XDG_TEST_DIR,
110 106 }), warnings.catch_warnings(record=True) as w:
111 107 ipdir = paths.get_ipython_dir()
112 108
113 109 nt.assert_equal(ipdir, os.path.join(HOME_TEST_DIR, ".ipython"))
114 110 if sys.platform != 'darwin':
115 111 nt.assert_equal(len(w), 1)
116 112 nt.assert_in('Ignoring', str(w[0]))
117 113
118 114 def test_get_ipython_dir_5():
119 115 """test_get_ipython_dir_5, use .ipython if exists and XDG defined, but doesn't exist."""
120 116 with patch_get_home_dir(HOME_TEST_DIR), \
121 117 patch('os.name', 'posix'):
122 118 try:
123 119 os.rmdir(os.path.join(XDG_TEST_DIR, 'ipython'))
124 120 except OSError as e:
125 121 if e.errno != errno.ENOENT:
126 122 raise
127 123
128 124 with modified_env({
129 125 'IPYTHON_DIR': None,
130 126 'IPYTHONDIR': None,
131 127 'XDG_CONFIG_HOME': XDG_TEST_DIR,
132 128 }):
133 129 ipdir = paths.get_ipython_dir()
134 130
135 131 nt.assert_equal(ipdir, IP_TEST_DIR)
136 132
137 133 def test_get_ipython_dir_6():
138 134 """test_get_ipython_dir_6, use home over XDG if defined and neither exist."""
139 135 xdg = os.path.join(HOME_TEST_DIR, 'somexdg')
140 136 os.mkdir(xdg)
141 137 shutil.rmtree(os.path.join(HOME_TEST_DIR, '.ipython'))
142 138 print(paths._writable_dir)
143 139 with patch_get_home_dir(HOME_TEST_DIR), \
144 140 patch.object(paths, 'get_xdg_dir', return_value=xdg), \
145 141 patch('os.name', 'posix'), \
146 142 modified_env({
147 143 'IPYTHON_DIR': None,
148 144 'IPYTHONDIR': None,
149 145 'XDG_CONFIG_HOME': None,
150 146 }), warnings.catch_warnings(record=True) as w:
151 147 ipdir = paths.get_ipython_dir()
152 148
153 149 nt.assert_equal(ipdir, os.path.join(HOME_TEST_DIR, '.ipython'))
154 150 nt.assert_equal(len(w), 0)
155 151
156 152 def test_get_ipython_dir_7():
157 153 """test_get_ipython_dir_7, test home directory expansion on IPYTHONDIR"""
158 154 home_dir = os.path.normpath(os.path.expanduser('~'))
159 155 with modified_env({'IPYTHONDIR': os.path.join('~', 'somewhere')}), \
160 156 patch.object(paths, '_writable_dir', return_value=True):
161 157 ipdir = paths.get_ipython_dir()
162 158 nt.assert_equal(ipdir, os.path.join(home_dir, 'somewhere'))
163 159
164 160 @skip_win32
165 161 def test_get_ipython_dir_8():
166 162 """test_get_ipython_dir_8, test / home directory"""
167 163 with patch.object(paths, '_writable_dir', lambda path: bool(path)), \
168 164 patch.object(paths, 'get_xdg_dir', return_value=None), \
169 165 modified_env({
170 166 'IPYTHON_DIR': None,
171 167 'IPYTHONDIR': None,
172 168 'HOME': '/',
173 169 }):
174 170 nt.assert_equal(paths.get_ipython_dir(), '/.ipython')
175 171
176 172
177 173 def test_get_ipython_cache_dir():
178 174 with modified_env({'HOME': HOME_TEST_DIR}):
179 175 if os.name == 'posix' and sys.platform != 'darwin':
180 176 # test default
181 177 os.makedirs(os.path.join(HOME_TEST_DIR, ".cache"))
182 178 with modified_env({'XDG_CACHE_HOME': None}):
183 179 ipdir = paths.get_ipython_cache_dir()
184 180 nt.assert_equal(os.path.join(HOME_TEST_DIR, ".cache", "ipython"),
185 181 ipdir)
186 182 assert_isdir(ipdir)
187 183
188 184 # test env override
189 185 with modified_env({"XDG_CACHE_HOME": XDG_CACHE_DIR}):
190 186 ipdir = paths.get_ipython_cache_dir()
191 187 assert_isdir(ipdir)
192 188 nt.assert_equal(ipdir, os.path.join(XDG_CACHE_DIR, "ipython"))
193 189 else:
194 190 nt.assert_equal(paths.get_ipython_cache_dir(),
195 191 paths.get_ipython_dir())
196 192
197 193 def test_get_ipython_package_dir():
198 194 ipdir = paths.get_ipython_package_dir()
199 195 assert_isdir(ipdir)
200 196
201 197
202 198 def test_get_ipython_module_path():
203 199 ipapp_path = paths.get_ipython_module_path('IPython.terminal.ipapp')
204 200 assert_isfile(ipapp_path)
@@ -1,514 +1,510 b''
1 1 # encoding: utf-8
2 2 """Tests for code execution (%run and related), which is particularly tricky.
3 3
4 4 Because of how %run manages namespaces, and the fact that we are trying here to
5 5 verify subtle object deletion and reference counting issues, the %run tests
6 6 will be kept in this separate file. This makes it easier to aggregate in one
7 7 place the tricks needed to handle it; most other magics are much easier to test
8 8 and we do so in a common test_magic file.
9 9 """
10 10
11 11 # Copyright (c) IPython Development Team.
12 12 # Distributed under the terms of the Modified BSD License.
13 13
14 14
15 15
16 16 import functools
17 17 import os
18 18 from os.path import join as pjoin
19 19 import random
20 20 import sys
21 21 import textwrap
22 22 import unittest
23
24 try:
25 from unittest.mock import patch
26 except ImportError:
27 from mock import patch
23 from unittest.mock import patch
28 24
29 25 import nose.tools as nt
30 26 from nose import SkipTest
31 27
32 28 from IPython.testing import decorators as dec
33 29 from IPython.testing import tools as tt
34 30 from IPython.utils import py3compat
35 31 from IPython.utils.io import capture_output
36 32 from IPython.utils.tempdir import TemporaryDirectory
37 33 from IPython.core import debugger
38 34
39 35
40 36 def doctest_refbug():
41 37 """Very nasty problem with references held by multiple runs of a script.
42 38 See: https://github.com/ipython/ipython/issues/141
43 39
44 40 In [1]: _ip.clear_main_mod_cache()
45 41 # random
46 42
47 43 In [2]: %run refbug
48 44
49 45 In [3]: call_f()
50 46 lowercased: hello
51 47
52 48 In [4]: %run refbug
53 49
54 50 In [5]: call_f()
55 51 lowercased: hello
56 52 lowercased: hello
57 53 """
58 54
59 55
60 56 def doctest_run_builtins():
61 57 r"""Check that %run doesn't damage __builtins__.
62 58
63 59 In [1]: import tempfile
64 60
65 61 In [2]: bid1 = id(__builtins__)
66 62
67 63 In [3]: fname = tempfile.mkstemp('.py')[1]
68 64
69 65 In [3]: f = open(fname,'w')
70 66
71 67 In [4]: dummy= f.write('pass\n')
72 68
73 69 In [5]: f.flush()
74 70
75 71 In [6]: t1 = type(__builtins__)
76 72
77 73 In [7]: %run $fname
78 74
79 75 In [7]: f.close()
80 76
81 77 In [8]: bid2 = id(__builtins__)
82 78
83 79 In [9]: t2 = type(__builtins__)
84 80
85 81 In [10]: t1 == t2
86 82 Out[10]: True
87 83
88 84 In [10]: bid1 == bid2
89 85 Out[10]: True
90 86
91 87 In [12]: try:
92 88 ....: os.unlink(fname)
93 89 ....: except:
94 90 ....: pass
95 91 ....:
96 92 """
97 93
98 94
99 95 def doctest_run_option_parser():
100 96 r"""Test option parser in %run.
101 97
102 98 In [1]: %run print_argv.py
103 99 []
104 100
105 101 In [2]: %run print_argv.py print*.py
106 102 ['print_argv.py']
107 103
108 104 In [3]: %run -G print_argv.py print*.py
109 105 ['print*.py']
110 106
111 107 """
112 108
113 109
114 110 @dec.skip_win32
115 111 def doctest_run_option_parser_for_posix():
116 112 r"""Test option parser in %run (Linux/OSX specific).
117 113
118 114 You need double quote to escape glob in POSIX systems:
119 115
120 116 In [1]: %run print_argv.py print\\*.py
121 117 ['print*.py']
122 118
123 119 You can't use quote to escape glob in POSIX systems:
124 120
125 121 In [2]: %run print_argv.py 'print*.py'
126 122 ['print_argv.py']
127 123
128 124 """
129 125
130 126
131 127 @dec.skip_if_not_win32
132 128 def doctest_run_option_parser_for_windows():
133 129 r"""Test option parser in %run (Windows specific).
134 130
135 131 In Windows, you can't escape ``*` `by backslash:
136 132
137 133 In [1]: %run print_argv.py print\\*.py
138 134 ['print\\*.py']
139 135
140 136 You can use quote to escape glob:
141 137
142 138 In [2]: %run print_argv.py 'print*.py'
143 139 ['print*.py']
144 140
145 141 """
146 142
147 143
148 144 @py3compat.doctest_refactor_print
149 145 def doctest_reset_del():
150 146 """Test that resetting doesn't cause errors in __del__ methods.
151 147
152 148 In [2]: class A(object):
153 149 ...: def __del__(self):
154 150 ...: print str("Hi")
155 151 ...:
156 152
157 153 In [3]: a = A()
158 154
159 155 In [4]: get_ipython().reset()
160 156 Hi
161 157
162 158 In [5]: 1+1
163 159 Out[5]: 2
164 160 """
165 161
166 162 # For some tests, it will be handy to organize them in a class with a common
167 163 # setup that makes a temp file
168 164
169 165 class TestMagicRunPass(tt.TempFileMixin):
170 166
171 167 def setup(self):
172 168 """Make a valid python temp file."""
173 169 self.mktmp('pass\n')
174 170
175 171 def run_tmpfile(self):
176 172 _ip = get_ipython()
177 173 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
178 174 # See below and ticket https://bugs.launchpad.net/bugs/366353
179 175 _ip.magic('run %s' % self.fname)
180 176
181 177 def run_tmpfile_p(self):
182 178 _ip = get_ipython()
183 179 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
184 180 # See below and ticket https://bugs.launchpad.net/bugs/366353
185 181 _ip.magic('run -p %s' % self.fname)
186 182
187 183 def test_builtins_id(self):
188 184 """Check that %run doesn't damage __builtins__ """
189 185 _ip = get_ipython()
190 186 # Test that the id of __builtins__ is not modified by %run
191 187 bid1 = id(_ip.user_ns['__builtins__'])
192 188 self.run_tmpfile()
193 189 bid2 = id(_ip.user_ns['__builtins__'])
194 190 nt.assert_equal(bid1, bid2)
195 191
196 192 def test_builtins_type(self):
197 193 """Check that the type of __builtins__ doesn't change with %run.
198 194
199 195 However, the above could pass if __builtins__ was already modified to
200 196 be a dict (it should be a module) by a previous use of %run. So we
201 197 also check explicitly that it really is a module:
202 198 """
203 199 _ip = get_ipython()
204 200 self.run_tmpfile()
205 201 nt.assert_equal(type(_ip.user_ns['__builtins__']),type(sys))
206 202
207 203 def test_run_profile( self ):
208 204 """Test that the option -p, which invokes the profiler, do not
209 205 crash by invoking execfile"""
210 206 self.run_tmpfile_p()
211 207
212 208 def test_run_debug_twice(self):
213 209 # https://github.com/ipython/ipython/issues/10028
214 210 _ip = get_ipython()
215 211 with tt.fake_input(['c']):
216 212 _ip.magic('run -d %s' % self.fname)
217 213 with tt.fake_input(['c']):
218 214 _ip.magic('run -d %s' % self.fname)
219 215
220 216
221 217 class TestMagicRunSimple(tt.TempFileMixin):
222 218
223 219 def test_simpledef(self):
224 220 """Test that simple class definitions work."""
225 221 src = ("class foo: pass\n"
226 222 "def f(): return foo()")
227 223 self.mktmp(src)
228 224 _ip.magic('run %s' % self.fname)
229 225 _ip.run_cell('t = isinstance(f(), foo)')
230 226 nt.assert_true(_ip.user_ns['t'])
231 227
232 228 def test_obj_del(self):
233 229 """Test that object's __del__ methods are called on exit."""
234 230 if sys.platform == 'win32':
235 231 try:
236 232 import win32api
237 233 except ImportError:
238 234 raise SkipTest("Test requires pywin32")
239 235 src = ("class A(object):\n"
240 236 " def __del__(self):\n"
241 237 " print 'object A deleted'\n"
242 238 "a = A()\n")
243 239 self.mktmp(py3compat.doctest_refactor_print(src))
244 240 if dec.module_not_available('sqlite3'):
245 241 err = 'WARNING: IPython History requires SQLite, your history will not be saved\n'
246 242 else:
247 243 err = None
248 244 tt.ipexec_validate(self.fname, 'object A deleted', err)
249 245
250 246 def test_aggressive_namespace_cleanup(self):
251 247 """Test that namespace cleanup is not too aggressive GH-238
252 248
253 249 Returning from another run magic deletes the namespace"""
254 250 # see ticket https://github.com/ipython/ipython/issues/238
255 251
256 252 with tt.TempFileMixin() as empty:
257 253 empty.mktmp('')
258 254 # On Windows, the filename will have \users in it, so we need to use the
259 255 # repr so that the \u becomes \\u.
260 256 src = ("ip = get_ipython()\n"
261 257 "for i in range(5):\n"
262 258 " try:\n"
263 259 " ip.magic(%r)\n"
264 260 " except NameError as e:\n"
265 261 " print(i)\n"
266 262 " break\n" % ('run ' + empty.fname))
267 263 self.mktmp(src)
268 264 _ip.magic('run %s' % self.fname)
269 265 _ip.run_cell('ip == get_ipython()')
270 266 nt.assert_equal(_ip.user_ns['i'], 4)
271 267
272 268 def test_run_second(self):
273 269 """Test that running a second file doesn't clobber the first, gh-3547
274 270 """
275 271 self.mktmp("avar = 1\n"
276 272 "def afunc():\n"
277 273 " return avar\n")
278 274
279 275 with tt.TempFileMixin() as empty:
280 276 empty.mktmp("")
281 277
282 278 _ip.magic('run %s' % self.fname)
283 279 _ip.magic('run %s' % empty.fname)
284 280 nt.assert_equal(_ip.user_ns['afunc'](), 1)
285 281
286 282 @dec.skip_win32
287 283 def test_tclass(self):
288 284 mydir = os.path.dirname(__file__)
289 285 tc = os.path.join(mydir, 'tclass')
290 286 src = ("%%run '%s' C-first\n"
291 287 "%%run '%s' C-second\n"
292 288 "%%run '%s' C-third\n") % (tc, tc, tc)
293 289 self.mktmp(src, '.ipy')
294 290 out = """\
295 291 ARGV 1-: ['C-first']
296 292 ARGV 1-: ['C-second']
297 293 tclass.py: deleting object: C-first
298 294 ARGV 1-: ['C-third']
299 295 tclass.py: deleting object: C-second
300 296 tclass.py: deleting object: C-third
301 297 """
302 298 if dec.module_not_available('sqlite3'):
303 299 err = 'WARNING: IPython History requires SQLite, your history will not be saved\n'
304 300 else:
305 301 err = None
306 302 tt.ipexec_validate(self.fname, out, err)
307 303
308 304 def test_run_i_after_reset(self):
309 305 """Check that %run -i still works after %reset (gh-693)"""
310 306 src = "yy = zz\n"
311 307 self.mktmp(src)
312 308 _ip.run_cell("zz = 23")
313 309 _ip.magic('run -i %s' % self.fname)
314 310 nt.assert_equal(_ip.user_ns['yy'], 23)
315 311 _ip.magic('reset -f')
316 312 _ip.run_cell("zz = 23")
317 313 _ip.magic('run -i %s' % self.fname)
318 314 nt.assert_equal(_ip.user_ns['yy'], 23)
319 315
320 316 def test_unicode(self):
321 317 """Check that files in odd encodings are accepted."""
322 318 mydir = os.path.dirname(__file__)
323 319 na = os.path.join(mydir, 'nonascii.py')
324 320 _ip.magic('run "%s"' % na)
325 321 nt.assert_equal(_ip.user_ns['u'], u'ΠŽΡ‚β„–Π€')
326 322
327 323 def test_run_py_file_attribute(self):
328 324 """Test handling of `__file__` attribute in `%run <file>.py`."""
329 325 src = "t = __file__\n"
330 326 self.mktmp(src)
331 327 _missing = object()
332 328 file1 = _ip.user_ns.get('__file__', _missing)
333 329 _ip.magic('run %s' % self.fname)
334 330 file2 = _ip.user_ns.get('__file__', _missing)
335 331
336 332 # Check that __file__ was equal to the filename in the script's
337 333 # namespace.
338 334 nt.assert_equal(_ip.user_ns['t'], self.fname)
339 335
340 336 # Check that __file__ was not leaked back into user_ns.
341 337 nt.assert_equal(file1, file2)
342 338
343 339 def test_run_ipy_file_attribute(self):
344 340 """Test handling of `__file__` attribute in `%run <file.ipy>`."""
345 341 src = "t = __file__\n"
346 342 self.mktmp(src, ext='.ipy')
347 343 _missing = object()
348 344 file1 = _ip.user_ns.get('__file__', _missing)
349 345 _ip.magic('run %s' % self.fname)
350 346 file2 = _ip.user_ns.get('__file__', _missing)
351 347
352 348 # Check that __file__ was equal to the filename in the script's
353 349 # namespace.
354 350 nt.assert_equal(_ip.user_ns['t'], self.fname)
355 351
356 352 # Check that __file__ was not leaked back into user_ns.
357 353 nt.assert_equal(file1, file2)
358 354
359 355 def test_run_formatting(self):
360 356 """ Test that %run -t -N<N> does not raise a TypeError for N > 1."""
361 357 src = "pass"
362 358 self.mktmp(src)
363 359 _ip.magic('run -t -N 1 %s' % self.fname)
364 360 _ip.magic('run -t -N 10 %s' % self.fname)
365 361
366 362 def test_ignore_sys_exit(self):
367 363 """Test the -e option to ignore sys.exit()"""
368 364 src = "import sys; sys.exit(1)"
369 365 self.mktmp(src)
370 366 with tt.AssertPrints('SystemExit'):
371 367 _ip.magic('run %s' % self.fname)
372 368
373 369 with tt.AssertNotPrints('SystemExit'):
374 370 _ip.magic('run -e %s' % self.fname)
375 371
376 372 def test_run_nb(self):
377 373 """Test %run notebook.ipynb"""
378 374 from nbformat import v4, writes
379 375 nb = v4.new_notebook(
380 376 cells=[
381 377 v4.new_markdown_cell("The Ultimate Question of Everything"),
382 378 v4.new_code_cell("answer=42")
383 379 ]
384 380 )
385 381 src = writes(nb, version=4)
386 382 self.mktmp(src, ext='.ipynb')
387 383
388 384 _ip.magic("run %s" % self.fname)
389 385
390 386 nt.assert_equal(_ip.user_ns['answer'], 42)
391 387
392 388
393 389
394 390 class TestMagicRunWithPackage(unittest.TestCase):
395 391
396 392 def writefile(self, name, content):
397 393 path = os.path.join(self.tempdir.name, name)
398 394 d = os.path.dirname(path)
399 395 if not os.path.isdir(d):
400 396 os.makedirs(d)
401 397 with open(path, 'w') as f:
402 398 f.write(textwrap.dedent(content))
403 399
404 400 def setUp(self):
405 401 self.package = package = 'tmp{0}'.format(repr(random.random())[2:])
406 402 """Temporary valid python package name."""
407 403
408 404 self.value = int(random.random() * 10000)
409 405
410 406 self.tempdir = TemporaryDirectory()
411 407 self.__orig_cwd = os.getcwd()
412 408 sys.path.insert(0, self.tempdir.name)
413 409
414 410 self.writefile(os.path.join(package, '__init__.py'), '')
415 411 self.writefile(os.path.join(package, 'sub.py'), """
416 412 x = {0!r}
417 413 """.format(self.value))
418 414 self.writefile(os.path.join(package, 'relative.py'), """
419 415 from .sub import x
420 416 """)
421 417 self.writefile(os.path.join(package, 'absolute.py'), """
422 418 from {0}.sub import x
423 419 """.format(package))
424 420
425 421 def tearDown(self):
426 422 os.chdir(self.__orig_cwd)
427 423 sys.path[:] = [p for p in sys.path if p != self.tempdir.name]
428 424 self.tempdir.cleanup()
429 425
430 426 def check_run_submodule(self, submodule, opts=''):
431 427 _ip.user_ns.pop('x', None)
432 428 _ip.magic('run {2} -m {0}.{1}'.format(self.package, submodule, opts))
433 429 self.assertEqual(_ip.user_ns['x'], self.value,
434 430 'Variable `x` is not loaded from module `{0}`.'
435 431 .format(submodule))
436 432
437 433 def test_run_submodule_with_absolute_import(self):
438 434 self.check_run_submodule('absolute')
439 435
440 436 def test_run_submodule_with_relative_import(self):
441 437 """Run submodule that has a relative import statement (#2727)."""
442 438 self.check_run_submodule('relative')
443 439
444 440 def test_prun_submodule_with_absolute_import(self):
445 441 self.check_run_submodule('absolute', '-p')
446 442
447 443 def test_prun_submodule_with_relative_import(self):
448 444 self.check_run_submodule('relative', '-p')
449 445
450 446 def with_fake_debugger(func):
451 447 @functools.wraps(func)
452 448 def wrapper(*args, **kwds):
453 449 with patch.object(debugger.Pdb, 'run', staticmethod(eval)):
454 450 return func(*args, **kwds)
455 451 return wrapper
456 452
457 453 @with_fake_debugger
458 454 def test_debug_run_submodule_with_absolute_import(self):
459 455 self.check_run_submodule('absolute', '-d')
460 456
461 457 @with_fake_debugger
462 458 def test_debug_run_submodule_with_relative_import(self):
463 459 self.check_run_submodule('relative', '-d')
464 460
465 461 def test_run__name__():
466 462 with TemporaryDirectory() as td:
467 463 path = pjoin(td, 'foo.py')
468 464 with open(path, 'w') as f:
469 465 f.write("q = __name__")
470 466
471 467 _ip.user_ns.pop('q', None)
472 468 _ip.magic('run {}'.format(path))
473 469 nt.assert_equal(_ip.user_ns.pop('q'), '__main__')
474 470
475 471 _ip.magic('run -n {}'.format(path))
476 472 nt.assert_equal(_ip.user_ns.pop('q'), 'foo')
477 473
478 474 def test_run_tb():
479 475 """Test traceback offset in %run"""
480 476 with TemporaryDirectory() as td:
481 477 path = pjoin(td, 'foo.py')
482 478 with open(path, 'w') as f:
483 479 f.write('\n'.join([
484 480 "def foo():",
485 481 " return bar()",
486 482 "def bar():",
487 483 " raise RuntimeError('hello!')",
488 484 "foo()",
489 485 ]))
490 486 with capture_output() as io:
491 487 _ip.magic('run {}'.format(path))
492 488 out = io.stdout
493 489 nt.assert_not_in("execfile", out)
494 490 nt.assert_in("RuntimeError", out)
495 491 nt.assert_equal(out.count("---->"), 3)
496 492
497 493 @dec.knownfailureif(sys.platform == 'win32', "writes to io.stdout aren't captured on Windows")
498 494 def test_script_tb():
499 495 """Test traceback offset in `ipython script.py`"""
500 496 with TemporaryDirectory() as td:
501 497 path = pjoin(td, 'foo.py')
502 498 with open(path, 'w') as f:
503 499 f.write('\n'.join([
504 500 "def foo():",
505 501 " return bar()",
506 502 "def bar():",
507 503 " raise RuntimeError('hello!')",
508 504 "foo()",
509 505 ]))
510 506 out, err = tt.ipexec(path)
511 507 nt.assert_not_in("execfile", out)
512 508 nt.assert_in("RuntimeError", out)
513 509 nt.assert_equal(out.count("---->"), 3)
514 510
@@ -1,355 +1,351 b''
1 1 # encoding: utf-8
2 2 """Tests for IPython.core.ultratb
3 3 """
4 4 import io
5 5 import sys
6 6 import os.path
7 7 from textwrap import dedent
8 8 import traceback
9 9 import unittest
10
11 try:
12 from unittest import mock
13 except ImportError:
14 import mock # Python 2
10 from unittest import mock
15 11
16 12 from ..ultratb import ColorTB, VerboseTB, find_recursion
17 13
18 14
19 15 from IPython.testing import tools as tt
20 16 from IPython.testing.decorators import onlyif_unicode_paths
21 17 from IPython.utils.syspathcontext import prepended_to_syspath
22 18 from IPython.utils.tempdir import TemporaryDirectory
23 19 from IPython.utils.py3compat import PY3
24 20
25 21 ip = get_ipython()
26 22
27 23 file_1 = """1
28 24 2
29 25 3
30 26 def f():
31 27 1/0
32 28 """
33 29
34 30 file_2 = """def f():
35 31 1/0
36 32 """
37 33
38 34 class ChangedPyFileTest(unittest.TestCase):
39 35 def test_changing_py_file(self):
40 36 """Traceback produced if the line where the error occurred is missing?
41 37
42 38 https://github.com/ipython/ipython/issues/1456
43 39 """
44 40 with TemporaryDirectory() as td:
45 41 fname = os.path.join(td, "foo.py")
46 42 with open(fname, "w") as f:
47 43 f.write(file_1)
48 44
49 45 with prepended_to_syspath(td):
50 46 ip.run_cell("import foo")
51 47
52 48 with tt.AssertPrints("ZeroDivisionError"):
53 49 ip.run_cell("foo.f()")
54 50
55 51 # Make the file shorter, so the line of the error is missing.
56 52 with open(fname, "w") as f:
57 53 f.write(file_2)
58 54
59 55 # For some reason, this was failing on the *second* call after
60 56 # changing the file, so we call f() twice.
61 57 with tt.AssertNotPrints("Internal Python error", channel='stderr'):
62 58 with tt.AssertPrints("ZeroDivisionError"):
63 59 ip.run_cell("foo.f()")
64 60 with tt.AssertPrints("ZeroDivisionError"):
65 61 ip.run_cell("foo.f()")
66 62
67 63 iso_8859_5_file = u'''# coding: iso-8859-5
68 64
69 65 def fail():
70 66 """Π΄Π±Π˜Π–"""
71 67 1/0 # Π΄Π±Π˜Π–
72 68 '''
73 69
74 70 class NonAsciiTest(unittest.TestCase):
75 71 @onlyif_unicode_paths
76 72 def test_nonascii_path(self):
77 73 # Non-ascii directory name as well.
78 74 with TemporaryDirectory(suffix=u'Γ©') as td:
79 75 fname = os.path.join(td, u"fooΓ©.py")
80 76 with open(fname, "w") as f:
81 77 f.write(file_1)
82 78
83 79 with prepended_to_syspath(td):
84 80 ip.run_cell("import foo")
85 81
86 82 with tt.AssertPrints("ZeroDivisionError"):
87 83 ip.run_cell("foo.f()")
88 84
89 85 def test_iso8859_5(self):
90 86 with TemporaryDirectory() as td:
91 87 fname = os.path.join(td, 'dfghjkl.py')
92 88
93 89 with io.open(fname, 'w', encoding='iso-8859-5') as f:
94 90 f.write(iso_8859_5_file)
95 91
96 92 with prepended_to_syspath(td):
97 93 ip.run_cell("from dfghjkl import fail")
98 94
99 95 with tt.AssertPrints("ZeroDivisionError"):
100 96 with tt.AssertPrints(u'Π΄Π±Π˜Π–', suppress=False):
101 97 ip.run_cell('fail()')
102 98
103 99 def test_nonascii_msg(self):
104 100 cell = u"raise Exception('Γ©')"
105 101 expected = u"Exception('Γ©')"
106 102 ip.run_cell("%xmode plain")
107 103 with tt.AssertPrints(expected):
108 104 ip.run_cell(cell)
109 105
110 106 ip.run_cell("%xmode verbose")
111 107 with tt.AssertPrints(expected):
112 108 ip.run_cell(cell)
113 109
114 110 ip.run_cell("%xmode context")
115 111 with tt.AssertPrints(expected):
116 112 ip.run_cell(cell)
117 113
118 114
119 115 class NestedGenExprTestCase(unittest.TestCase):
120 116 """
121 117 Regression test for the following issues:
122 118 https://github.com/ipython/ipython/issues/8293
123 119 https://github.com/ipython/ipython/issues/8205
124 120 """
125 121 def test_nested_genexpr(self):
126 122 code = dedent(
127 123 """\
128 124 class SpecificException(Exception):
129 125 pass
130 126
131 127 def foo(x):
132 128 raise SpecificException("Success!")
133 129
134 130 sum(sum(foo(x) for _ in [0]) for x in [0])
135 131 """
136 132 )
137 133 with tt.AssertPrints('SpecificException: Success!', suppress=False):
138 134 ip.run_cell(code)
139 135
140 136
141 137 indentationerror_file = """if True:
142 138 zoon()
143 139 """
144 140
145 141 class IndentationErrorTest(unittest.TestCase):
146 142 def test_indentationerror_shows_line(self):
147 143 # See issue gh-2398
148 144 with tt.AssertPrints("IndentationError"):
149 145 with tt.AssertPrints("zoon()", suppress=False):
150 146 ip.run_cell(indentationerror_file)
151 147
152 148 with TemporaryDirectory() as td:
153 149 fname = os.path.join(td, "foo.py")
154 150 with open(fname, "w") as f:
155 151 f.write(indentationerror_file)
156 152
157 153 with tt.AssertPrints("IndentationError"):
158 154 with tt.AssertPrints("zoon()", suppress=False):
159 155 ip.magic('run %s' % fname)
160 156
161 157 se_file_1 = """1
162 158 2
163 159 7/
164 160 """
165 161
166 162 se_file_2 = """7/
167 163 """
168 164
169 165 class SyntaxErrorTest(unittest.TestCase):
170 166 def test_syntaxerror_without_lineno(self):
171 167 with tt.AssertNotPrints("TypeError"):
172 168 with tt.AssertPrints("line unknown"):
173 169 ip.run_cell("raise SyntaxError()")
174 170
175 171 def test_changing_py_file(self):
176 172 with TemporaryDirectory() as td:
177 173 fname = os.path.join(td, "foo.py")
178 174 with open(fname, 'w') as f:
179 175 f.write(se_file_1)
180 176
181 177 with tt.AssertPrints(["7/", "SyntaxError"]):
182 178 ip.magic("run " + fname)
183 179
184 180 # Modify the file
185 181 with open(fname, 'w') as f:
186 182 f.write(se_file_2)
187 183
188 184 # The SyntaxError should point to the correct line
189 185 with tt.AssertPrints(["7/", "SyntaxError"]):
190 186 ip.magic("run " + fname)
191 187
192 188 def test_non_syntaxerror(self):
193 189 # SyntaxTB may be called with an error other than a SyntaxError
194 190 # See e.g. gh-4361
195 191 try:
196 192 raise ValueError('QWERTY')
197 193 except ValueError:
198 194 with tt.AssertPrints('QWERTY'):
199 195 ip.showsyntaxerror()
200 196
201 197
202 198 class Python3ChainedExceptionsTest(unittest.TestCase):
203 199 DIRECT_CAUSE_ERROR_CODE = """
204 200 try:
205 201 x = 1 + 2
206 202 print(not_defined_here)
207 203 except Exception as e:
208 204 x += 55
209 205 x - 1
210 206 y = {}
211 207 raise KeyError('uh') from e
212 208 """
213 209
214 210 EXCEPTION_DURING_HANDLING_CODE = """
215 211 try:
216 212 x = 1 + 2
217 213 print(not_defined_here)
218 214 except Exception as e:
219 215 x += 55
220 216 x - 1
221 217 y = {}
222 218 raise KeyError('uh')
223 219 """
224 220
225 221 SUPPRESS_CHAINING_CODE = """
226 222 try:
227 223 1/0
228 224 except Exception:
229 225 raise ValueError("Yikes") from None
230 226 """
231 227
232 228 def test_direct_cause_error(self):
233 229 if PY3:
234 230 with tt.AssertPrints(["KeyError", "NameError", "direct cause"]):
235 231 ip.run_cell(self.DIRECT_CAUSE_ERROR_CODE)
236 232
237 233 def test_exception_during_handling_error(self):
238 234 if PY3:
239 235 with tt.AssertPrints(["KeyError", "NameError", "During handling"]):
240 236 ip.run_cell(self.EXCEPTION_DURING_HANDLING_CODE)
241 237
242 238 def test_suppress_exception_chaining(self):
243 239 if PY3:
244 240 with tt.AssertNotPrints("ZeroDivisionError"), \
245 241 tt.AssertPrints("ValueError", suppress=False):
246 242 ip.run_cell(self.SUPPRESS_CHAINING_CODE)
247 243
248 244
249 245 class RecursionTest(unittest.TestCase):
250 246 DEFINITIONS = """
251 247 def non_recurs():
252 248 1/0
253 249
254 250 def r1():
255 251 r1()
256 252
257 253 def r3a():
258 254 r3b()
259 255
260 256 def r3b():
261 257 r3c()
262 258
263 259 def r3c():
264 260 r3a()
265 261
266 262 def r3o1():
267 263 r3a()
268 264
269 265 def r3o2():
270 266 r3o1()
271 267 """
272 268 def setUp(self):
273 269 ip.run_cell(self.DEFINITIONS)
274 270
275 271 def test_no_recursion(self):
276 272 with tt.AssertNotPrints("frames repeated"):
277 273 ip.run_cell("non_recurs()")
278 274
279 275 def test_recursion_one_frame(self):
280 276 with tt.AssertPrints("1 frames repeated"):
281 277 ip.run_cell("r1()")
282 278
283 279 def test_recursion_three_frames(self):
284 280 with tt.AssertPrints("3 frames repeated"):
285 281 ip.run_cell("r3o2()")
286 282
287 283 def test_find_recursion(self):
288 284 captured = []
289 285 def capture_exc(*args, **kwargs):
290 286 captured.append(sys.exc_info())
291 287 with mock.patch.object(ip, 'showtraceback', capture_exc):
292 288 ip.run_cell("r3o2()")
293 289
294 290 self.assertEqual(len(captured), 1)
295 291 etype, evalue, tb = captured[0]
296 292 self.assertIn("recursion", str(evalue))
297 293
298 294 records = ip.InteractiveTB.get_records(tb, 3, ip.InteractiveTB.tb_offset)
299 295 for r in records[:10]:
300 296 print(r[1:4])
301 297
302 298 # The outermost frames should be:
303 299 # 0: the 'cell' that was running when the exception came up
304 300 # 1: r3o2()
305 301 # 2: r3o1()
306 302 # 3: r3a()
307 303 # Then repeating r3b, r3c, r3a
308 304 last_unique, repeat_length = find_recursion(etype, evalue, records)
309 305 self.assertEqual(last_unique, 2)
310 306 self.assertEqual(repeat_length, 3)
311 307
312 308
313 309 #----------------------------------------------------------------------------
314 310
315 311 # module testing (minimal)
316 312 def test_handlers():
317 313 def spam(c, d_e):
318 314 (d, e) = d_e
319 315 x = c + d
320 316 y = c * d
321 317 foo(x, y)
322 318
323 319 def foo(a, b, bar=1):
324 320 eggs(a, b + bar)
325 321
326 322 def eggs(f, g, z=globals()):
327 323 h = f + g
328 324 i = f - g
329 325 return h / i
330 326
331 327 buff = io.StringIO()
332 328
333 329 buff.write('')
334 330 buff.write('*** Before ***')
335 331 try:
336 332 buff.write(spam(1, (2, 3)))
337 333 except:
338 334 traceback.print_exc(file=buff)
339 335
340 336 handler = ColorTB(ostream=buff)
341 337 buff.write('*** ColorTB ***')
342 338 try:
343 339 buff.write(spam(1, (2, 3)))
344 340 except:
345 341 handler(*sys.exc_info())
346 342 buff.write('')
347 343
348 344 handler = VerboseTB(ostream=buff)
349 345 buff.write('*** VerboseTB ***')
350 346 try:
351 347 buff.write(spam(1, (2, 3)))
352 348 except:
353 349 handler(*sys.exc_info())
354 350 buff.write('')
355 351
@@ -1,205 +1,201 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Tools for handling LaTeX."""
3 3
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 7 from io import BytesIO, open
8 8 import os
9 9 import tempfile
10 10 import shutil
11 11 import subprocess
12 from base64 import encodebytes
12 13
13 14 from IPython.utils.process import find_cmd, FindCmdError
14 15 from traitlets.config import get_config
15 16 from traitlets.config.configurable import SingletonConfigurable
16 17 from traitlets import List, Bool, Unicode
17 18 from IPython.utils.py3compat import cast_unicode, cast_unicode_py2 as u, PY3
18 19
19 try: # Py3
20 from base64 import encodebytes
21 except ImportError: # Py2
22 from base64 import encodestring as encodebytes
23
24 20
25 21 class LaTeXTool(SingletonConfigurable):
26 22 """An object to store configuration of the LaTeX tool."""
27 23 def _config_default(self):
28 24 return get_config()
29 25
30 26 backends = List(
31 27 Unicode(), ["matplotlib", "dvipng"],
32 28 help="Preferred backend to draw LaTeX math equations. "
33 29 "Backends in the list are checked one by one and the first "
34 30 "usable one is used. Note that `matplotlib` backend "
35 31 "is usable only for inline style equations. To draw "
36 32 "display style equations, `dvipng` backend must be specified. ",
37 33 # It is a List instead of Enum, to make configuration more
38 34 # flexible. For example, to use matplotlib mainly but dvipng
39 35 # for display style, the default ["matplotlib", "dvipng"] can
40 36 # be used. To NOT use dvipng so that other repr such as
41 37 # unicode pretty printing is used, you can use ["matplotlib"].
42 38 ).tag(config=True)
43 39
44 40 use_breqn = Bool(
45 41 True,
46 42 help="Use breqn.sty to automatically break long equations. "
47 43 "This configuration takes effect only for dvipng backend.",
48 44 ).tag(config=True)
49 45
50 46 packages = List(
51 47 ['amsmath', 'amsthm', 'amssymb', 'bm'],
52 48 help="A list of packages to use for dvipng backend. "
53 49 "'breqn' will be automatically appended when use_breqn=True.",
54 50 ).tag(config=True)
55 51
56 52 preamble = Unicode(
57 53 help="Additional preamble to use when generating LaTeX source "
58 54 "for dvipng backend.",
59 55 ).tag(config=True)
60 56
61 57
62 58 def latex_to_png(s, encode=False, backend=None, wrap=False):
63 59 """Render a LaTeX string to PNG.
64 60
65 61 Parameters
66 62 ----------
67 63 s : str
68 64 The raw string containing valid inline LaTeX.
69 65 encode : bool, optional
70 66 Should the PNG data base64 encoded to make it JSON'able.
71 67 backend : {matplotlib, dvipng}
72 68 Backend for producing PNG data.
73 69 wrap : bool
74 70 If true, Automatically wrap `s` as a LaTeX equation.
75 71
76 72 None is returned when the backend cannot be used.
77 73
78 74 """
79 75 s = cast_unicode(s)
80 76 allowed_backends = LaTeXTool.instance().backends
81 77 if backend is None:
82 78 backend = allowed_backends[0]
83 79 if backend not in allowed_backends:
84 80 return None
85 81 if backend == 'matplotlib':
86 82 f = latex_to_png_mpl
87 83 elif backend == 'dvipng':
88 84 f = latex_to_png_dvipng
89 85 else:
90 86 raise ValueError('No such backend {0}'.format(backend))
91 87 bin_data = f(s, wrap)
92 88 if encode and bin_data:
93 89 bin_data = encodebytes(bin_data)
94 90 return bin_data
95 91
96 92
97 93 def latex_to_png_mpl(s, wrap):
98 94 try:
99 95 from matplotlib import mathtext
100 96 from pyparsing import ParseFatalException
101 97 except ImportError:
102 98 return None
103 99
104 100 # mpl mathtext doesn't support display math, force inline
105 101 s = s.replace('$$', '$')
106 102 if wrap:
107 103 s = u'${0}$'.format(s)
108 104
109 105 try:
110 106 mt = mathtext.MathTextParser('bitmap')
111 107 f = BytesIO()
112 108 mt.to_png(f, s, fontsize=12)
113 109 return f.getvalue()
114 110 except (ValueError, RuntimeError, ParseFatalException):
115 111 return None
116 112
117 113
118 114 def latex_to_png_dvipng(s, wrap):
119 115 try:
120 116 find_cmd('latex')
121 117 find_cmd('dvipng')
122 118 except FindCmdError:
123 119 return None
124 120 try:
125 121 workdir = tempfile.mkdtemp()
126 122 tmpfile = os.path.join(workdir, "tmp.tex")
127 123 dvifile = os.path.join(workdir, "tmp.dvi")
128 124 outfile = os.path.join(workdir, "tmp.png")
129 125
130 126 with open(tmpfile, "w", encoding='utf8') as f:
131 127 f.writelines(genelatex(s, wrap))
132 128
133 129 with open(os.devnull, 'wb') as devnull:
134 130 subprocess.check_call(
135 131 ["latex", "-halt-on-error", "-interaction", "batchmode", tmpfile],
136 132 cwd=workdir, stdout=devnull, stderr=devnull)
137 133
138 134 subprocess.check_call(
139 135 ["dvipng", "-T", "tight", "-x", "1500", "-z", "9",
140 136 "-bg", "transparent", "-o", outfile, dvifile], cwd=workdir,
141 137 stdout=devnull, stderr=devnull)
142 138
143 139 with open(outfile, "rb") as f:
144 140 return f.read()
145 141 except subprocess.CalledProcessError:
146 142 return None
147 143 finally:
148 144 shutil.rmtree(workdir)
149 145
150 146
151 147 def kpsewhich(filename):
152 148 """Invoke kpsewhich command with an argument `filename`."""
153 149 try:
154 150 find_cmd("kpsewhich")
155 151 proc = subprocess.Popen(
156 152 ["kpsewhich", filename],
157 153 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
158 154 (stdout, stderr) = proc.communicate()
159 155 return stdout.strip().decode('utf8', 'replace')
160 156 except FindCmdError:
161 157 pass
162 158
163 159
164 160 def genelatex(body, wrap):
165 161 """Generate LaTeX document for dvipng backend."""
166 162 lt = LaTeXTool.instance()
167 163 breqn = wrap and lt.use_breqn and kpsewhich("breqn.sty")
168 164 yield u(r'\documentclass{article}')
169 165 packages = lt.packages
170 166 if breqn:
171 167 packages = packages + ['breqn']
172 168 for pack in packages:
173 169 yield u(r'\usepackage{{{0}}}'.format(pack))
174 170 yield u(r'\pagestyle{empty}')
175 171 if lt.preamble:
176 172 yield lt.preamble
177 173 yield u(r'\begin{document}')
178 174 if breqn:
179 175 yield u(r'\begin{dmath*}')
180 176 yield body
181 177 yield u(r'\end{dmath*}')
182 178 elif wrap:
183 179 yield u'$${0}$$'.format(body)
184 180 else:
185 181 yield body
186 182 yield u'\end{document}'
187 183
188 184
189 185 _data_uri_template_png = u"""<img src="data:image/png;base64,%s" alt=%s />"""
190 186
191 187 def latex_to_html(s, alt='image'):
192 188 """Render LaTeX to HTML with embedded PNG data using data URIs.
193 189
194 190 Parameters
195 191 ----------
196 192 s : str
197 193 The raw string containing valid inline LateX.
198 194 alt : str
199 195 The alt text to use for the HTML.
200 196 """
201 197 base64_data = latex_to_png(s, encode=True).decode('ascii')
202 198 if base64_data:
203 199 return _data_uri_template_png % (base64_data, alt)
204 200
205 201
@@ -1,139 +1,134 b''
1 1 # encoding: utf-8
2 2 """Tests for IPython.utils.path.py"""
3 3
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6
7 try:
8 from unittest.mock import patch
9 except ImportError:
10 from mock import patch
11
6 from unittest.mock import patch
12 7 import nose.tools as nt
13 8
14 9 from IPython.lib import latextools
15 10 from IPython.testing.decorators import onlyif_cmds_exist, skipif_not_matplotlib
16 11 from IPython.utils.process import FindCmdError
17 12
18 13
19 14 def test_latex_to_png_dvipng_fails_when_no_cmd():
20 15 """
21 16 `latex_to_png_dvipng` should return None when there is no required command
22 17 """
23 18 for command in ['latex', 'dvipng']:
24 19 yield (check_latex_to_png_dvipng_fails_when_no_cmd, command)
25 20
26 21
27 22 def check_latex_to_png_dvipng_fails_when_no_cmd(command):
28 23 def mock_find_cmd(arg):
29 24 if arg == command:
30 25 raise FindCmdError
31 26
32 27 with patch.object(latextools, "find_cmd", mock_find_cmd):
33 28 nt.assert_equal(latextools.latex_to_png_dvipng("whatever", True),
34 29 None)
35 30
36 31
37 32 @onlyif_cmds_exist('latex', 'dvipng')
38 33 def test_latex_to_png_dvipng_runs():
39 34 """
40 35 Test that latex_to_png_dvipng just runs without error.
41 36 """
42 37 def mock_kpsewhich(filename):
43 38 nt.assert_equal(filename, "breqn.sty")
44 39 return None
45 40
46 41 for (s, wrap) in [(u"$$x^2$$", False), (u"x^2", True)]:
47 42 yield (latextools.latex_to_png_dvipng, s, wrap)
48 43
49 44 with patch.object(latextools, "kpsewhich", mock_kpsewhich):
50 45 yield (latextools.latex_to_png_dvipng, s, wrap)
51 46
52 47 @skipif_not_matplotlib
53 48 def test_latex_to_png_mpl_runs():
54 49 """
55 50 Test that latex_to_png_mpl just runs without error.
56 51 """
57 52 def mock_kpsewhich(filename):
58 53 nt.assert_equal(filename, "breqn.sty")
59 54 return None
60 55
61 56 for (s, wrap) in [("$x^2$", False), ("x^2", True)]:
62 57 yield (latextools.latex_to_png_mpl, s, wrap)
63 58
64 59 with patch.object(latextools, "kpsewhich", mock_kpsewhich):
65 60 yield (latextools.latex_to_png_mpl, s, wrap)
66 61
67 62 @skipif_not_matplotlib
68 63 def test_latex_to_html():
69 64 img = latextools.latex_to_html("$x^2$")
70 65 nt.assert_in("data:image/png;base64,iVBOR", img)
71 66
72 67
73 68 def test_genelatex_no_wrap():
74 69 """
75 70 Test genelatex with wrap=False.
76 71 """
77 72 def mock_kpsewhich(filename):
78 73 assert False, ("kpsewhich should not be called "
79 74 "(called with {0})".format(filename))
80 75
81 76 with patch.object(latextools, "kpsewhich", mock_kpsewhich):
82 77 nt.assert_equal(
83 78 '\n'.join(latextools.genelatex("body text", False)),
84 79 r'''\documentclass{article}
85 80 \usepackage{amsmath}
86 81 \usepackage{amsthm}
87 82 \usepackage{amssymb}
88 83 \usepackage{bm}
89 84 \pagestyle{empty}
90 85 \begin{document}
91 86 body text
92 87 \end{document}''')
93 88
94 89
95 90 def test_genelatex_wrap_with_breqn():
96 91 """
97 92 Test genelatex with wrap=True for the case breqn.sty is installed.
98 93 """
99 94 def mock_kpsewhich(filename):
100 95 nt.assert_equal(filename, "breqn.sty")
101 96 return "path/to/breqn.sty"
102 97
103 98 with patch.object(latextools, "kpsewhich", mock_kpsewhich):
104 99 nt.assert_equal(
105 100 '\n'.join(latextools.genelatex("x^2", True)),
106 101 r'''\documentclass{article}
107 102 \usepackage{amsmath}
108 103 \usepackage{amsthm}
109 104 \usepackage{amssymb}
110 105 \usepackage{bm}
111 106 \usepackage{breqn}
112 107 \pagestyle{empty}
113 108 \begin{document}
114 109 \begin{dmath*}
115 110 x^2
116 111 \end{dmath*}
117 112 \end{document}''')
118 113
119 114
120 115 def test_genelatex_wrap_without_breqn():
121 116 """
122 117 Test genelatex with wrap=True for the case breqn.sty is not installed.
123 118 """
124 119 def mock_kpsewhich(filename):
125 120 nt.assert_equal(filename, "breqn.sty")
126 121 return None
127 122
128 123 with patch.object(latextools, "kpsewhich", mock_kpsewhich):
129 124 nt.assert_equal(
130 125 '\n'.join(latextools.genelatex("x^2", True)),
131 126 r'''\documentclass{article}
132 127 \usepackage{amsmath}
133 128 \usepackage{amsthm}
134 129 \usepackage{amssymb}
135 130 \usepackage{bm}
136 131 \pagestyle{empty}
137 132 \begin{document}
138 133 $$x^2$$
139 134 \end{document}''')
@@ -1,496 +1,489 b''
1 1 # encoding: utf-8
2 2 """Tests for IPython.utils.path.py"""
3 3
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 7 import errno
8 8 import os
9 9 import shutil
10 10 import sys
11 11 import tempfile
12 12 import warnings
13 13 from contextlib import contextmanager
14
15 try: # Python 3.3+
16 from unittest.mock import patch
17 except ImportError:
18 from mock import patch
19
14 from unittest.mock import patch
20 15 from os.path import join, abspath, split
21 16
22 from nose import SkipTest
17 from nose import SkipTest, with_setup
23 18 import nose.tools as nt
24 19
25 from nose import with_setup
26
27 20 import IPython
28 21 from IPython import paths
29 22 from IPython.testing import decorators as dec
30 23 from IPython.testing.decorators import (skip_if_not_win32, skip_win32,
31 24 onlyif_unicode_paths,)
32 25 from IPython.testing.tools import make_tempfile, AssertPrints
33 26 from IPython.utils import path
34 27 from IPython.utils import py3compat
35 28 from IPython.utils.tempdir import TemporaryDirectory
36 29
37 30 # Platform-dependent imports
38 31 try:
39 32 import winreg as wreg # Py 3
40 33 except ImportError:
41 34 try:
42 35 import _winreg as wreg # Py 2
43 36 except ImportError:
44 37 #Fake _winreg module on none windows platforms
45 38 import types
46 39 wr_name = "winreg" if py3compat.PY3 else "_winreg"
47 40 sys.modules[wr_name] = types.ModuleType(wr_name)
48 41 try:
49 42 import winreg as wreg
50 43 except ImportError:
51 44 import _winreg as wreg
52 45 #Add entries that needs to be stubbed by the testing code
53 46 (wreg.OpenKey, wreg.QueryValueEx,) = (None, None)
54 47
55 48 try:
56 49 reload
57 50 except NameError: # Python 3
58 51 from imp import reload
59 52
60 53 #-----------------------------------------------------------------------------
61 54 # Globals
62 55 #-----------------------------------------------------------------------------
63 56 env = os.environ
64 57 TMP_TEST_DIR = tempfile.mkdtemp()
65 58 HOME_TEST_DIR = join(TMP_TEST_DIR, "home_test_dir")
66 59 #
67 60 # Setup/teardown functions/decorators
68 61 #
69 62
70 63 def setup():
71 64 """Setup testenvironment for the module:
72 65
73 66 - Adds dummy home dir tree
74 67 """
75 68 # Do not mask exceptions here. In particular, catching WindowsError is a
76 69 # problem because that exception is only defined on Windows...
77 70 os.makedirs(os.path.join(HOME_TEST_DIR, 'ipython'))
78 71
79 72
80 73 def teardown():
81 74 """Teardown testenvironment for the module:
82 75
83 76 - Remove dummy home dir tree
84 77 """
85 78 # Note: we remove the parent test dir, which is the root of all test
86 79 # subdirs we may have created. Use shutil instead of os.removedirs, so
87 80 # that non-empty directories are all recursively removed.
88 81 shutil.rmtree(TMP_TEST_DIR)
89 82
90 83
91 84 def setup_environment():
92 85 """Setup testenvironment for some functions that are tested
93 86 in this module. In particular this functions stores attributes
94 87 and other things that we need to stub in some test functions.
95 88 This needs to be done on a function level and not module level because
96 89 each testfunction needs a pristine environment.
97 90 """
98 91 global oldstuff, platformstuff
99 92 oldstuff = (env.copy(), os.name, sys.platform, path.get_home_dir, IPython.__file__, os.getcwd())
100 93
101 94 def teardown_environment():
102 95 """Restore things that were remembered by the setup_environment function
103 96 """
104 97 (oldenv, os.name, sys.platform, path.get_home_dir, IPython.__file__, old_wd) = oldstuff
105 98 os.chdir(old_wd)
106 99 reload(path)
107 100
108 101 for key in list(env):
109 102 if key not in oldenv:
110 103 del env[key]
111 104 env.update(oldenv)
112 105 if hasattr(sys, 'frozen'):
113 106 del sys.frozen
114 107
115 108 # Build decorator that uses the setup_environment/setup_environment
116 109 with_environment = with_setup(setup_environment, teardown_environment)
117 110
118 111 @skip_if_not_win32
119 112 @with_environment
120 113 def test_get_home_dir_1():
121 114 """Testcase for py2exe logic, un-compressed lib
122 115 """
123 116 unfrozen = path.get_home_dir()
124 117 sys.frozen = True
125 118
126 119 #fake filename for IPython.__init__
127 120 IPython.__file__ = abspath(join(HOME_TEST_DIR, "Lib/IPython/__init__.py"))
128 121
129 122 home_dir = path.get_home_dir()
130 123 nt.assert_equal(home_dir, unfrozen)
131 124
132 125
133 126 @skip_if_not_win32
134 127 @with_environment
135 128 def test_get_home_dir_2():
136 129 """Testcase for py2exe logic, compressed lib
137 130 """
138 131 unfrozen = path.get_home_dir()
139 132 sys.frozen = True
140 133 #fake filename for IPython.__init__
141 134 IPython.__file__ = abspath(join(HOME_TEST_DIR, "Library.zip/IPython/__init__.py")).lower()
142 135
143 136 home_dir = path.get_home_dir(True)
144 137 nt.assert_equal(home_dir, unfrozen)
145 138
146 139
147 140 @with_environment
148 141 def test_get_home_dir_3():
149 142 """get_home_dir() uses $HOME if set"""
150 143 env["HOME"] = HOME_TEST_DIR
151 144 home_dir = path.get_home_dir(True)
152 145 # get_home_dir expands symlinks
153 146 nt.assert_equal(home_dir, os.path.realpath(env["HOME"]))
154 147
155 148
156 149 @with_environment
157 150 def test_get_home_dir_4():
158 151 """get_home_dir() still works if $HOME is not set"""
159 152
160 153 if 'HOME' in env: del env['HOME']
161 154 # this should still succeed, but we don't care what the answer is
162 155 home = path.get_home_dir(False)
163 156
164 157 @with_environment
165 158 def test_get_home_dir_5():
166 159 """raise HomeDirError if $HOME is specified, but not a writable dir"""
167 160 env['HOME'] = abspath(HOME_TEST_DIR+'garbage')
168 161 # set os.name = posix, to prevent My Documents fallback on Windows
169 162 os.name = 'posix'
170 163 nt.assert_raises(path.HomeDirError, path.get_home_dir, True)
171 164
172 165 # Should we stub wreg fully so we can run the test on all platforms?
173 166 @skip_if_not_win32
174 167 @with_environment
175 168 def test_get_home_dir_8():
176 169 """Using registry hack for 'My Documents', os=='nt'
177 170
178 171 HOMESHARE, HOMEDRIVE, HOMEPATH, USERPROFILE and others are missing.
179 172 """
180 173 os.name = 'nt'
181 174 # Remove from stub environment all keys that may be set
182 175 for key in ['HOME', 'HOMESHARE', 'HOMEDRIVE', 'HOMEPATH', 'USERPROFILE']:
183 176 env.pop(key, None)
184 177
185 178 class key:
186 179 def Close(self):
187 180 pass
188 181
189 182 with patch.object(wreg, 'OpenKey', return_value=key()), \
190 183 patch.object(wreg, 'QueryValueEx', return_value=[abspath(HOME_TEST_DIR)]):
191 184 home_dir = path.get_home_dir()
192 185 nt.assert_equal(home_dir, abspath(HOME_TEST_DIR))
193 186
194 187 @with_environment
195 188 def test_get_xdg_dir_0():
196 189 """test_get_xdg_dir_0, check xdg_dir"""
197 190 reload(path)
198 191 path._writable_dir = lambda path: True
199 192 path.get_home_dir = lambda : 'somewhere'
200 193 os.name = "posix"
201 194 sys.platform = "linux2"
202 195 env.pop('IPYTHON_DIR', None)
203 196 env.pop('IPYTHONDIR', None)
204 197 env.pop('XDG_CONFIG_HOME', None)
205 198
206 199 nt.assert_equal(path.get_xdg_dir(), os.path.join('somewhere', '.config'))
207 200
208 201
209 202 @with_environment
210 203 def test_get_xdg_dir_1():
211 204 """test_get_xdg_dir_1, check nonexistant xdg_dir"""
212 205 reload(path)
213 206 path.get_home_dir = lambda : HOME_TEST_DIR
214 207 os.name = "posix"
215 208 sys.platform = "linux2"
216 209 env.pop('IPYTHON_DIR', None)
217 210 env.pop('IPYTHONDIR', None)
218 211 env.pop('XDG_CONFIG_HOME', None)
219 212 nt.assert_equal(path.get_xdg_dir(), None)
220 213
221 214 @with_environment
222 215 def test_get_xdg_dir_2():
223 216 """test_get_xdg_dir_2, check xdg_dir default to ~/.config"""
224 217 reload(path)
225 218 path.get_home_dir = lambda : HOME_TEST_DIR
226 219 os.name = "posix"
227 220 sys.platform = "linux2"
228 221 env.pop('IPYTHON_DIR', None)
229 222 env.pop('IPYTHONDIR', None)
230 223 env.pop('XDG_CONFIG_HOME', None)
231 224 cfgdir=os.path.join(path.get_home_dir(), '.config')
232 225 if not os.path.exists(cfgdir):
233 226 os.makedirs(cfgdir)
234 227
235 228 nt.assert_equal(path.get_xdg_dir(), cfgdir)
236 229
237 230 @with_environment
238 231 def test_get_xdg_dir_3():
239 232 """test_get_xdg_dir_3, check xdg_dir not used on OS X"""
240 233 reload(path)
241 234 path.get_home_dir = lambda : HOME_TEST_DIR
242 235 os.name = "posix"
243 236 sys.platform = "darwin"
244 237 env.pop('IPYTHON_DIR', None)
245 238 env.pop('IPYTHONDIR', None)
246 239 env.pop('XDG_CONFIG_HOME', None)
247 240 cfgdir=os.path.join(path.get_home_dir(), '.config')
248 241 if not os.path.exists(cfgdir):
249 242 os.makedirs(cfgdir)
250 243
251 244 nt.assert_equal(path.get_xdg_dir(), None)
252 245
253 246 def test_filefind():
254 247 """Various tests for filefind"""
255 248 f = tempfile.NamedTemporaryFile()
256 249 # print 'fname:',f.name
257 250 alt_dirs = paths.get_ipython_dir()
258 251 t = path.filefind(f.name, alt_dirs)
259 252 # print 'found:',t
260 253
261 254
262 255 @dec.skip_if_not_win32
263 256 def test_get_long_path_name_win32():
264 257 with TemporaryDirectory() as tmpdir:
265 258
266 259 # Make a long path. Expands the path of tmpdir prematurely as it may already have a long
267 260 # path component, so ensure we include the long form of it
268 261 long_path = os.path.join(path.get_long_path_name(tmpdir), u'this is my long path name')
269 262 os.makedirs(long_path)
270 263
271 264 # Test to see if the short path evaluates correctly.
272 265 short_path = os.path.join(tmpdir, u'THISIS~1')
273 266 evaluated_path = path.get_long_path_name(short_path)
274 267 nt.assert_equal(evaluated_path.lower(), long_path.lower())
275 268
276 269
277 270 @dec.skip_win32
278 271 def test_get_long_path_name():
279 272 p = path.get_long_path_name('/usr/local')
280 273 nt.assert_equal(p,'/usr/local')
281 274
282 275 @dec.skip_win32 # can't create not-user-writable dir on win
283 276 @with_environment
284 277 def test_not_writable_ipdir():
285 278 tmpdir = tempfile.mkdtemp()
286 279 os.name = "posix"
287 280 env.pop('IPYTHON_DIR', None)
288 281 env.pop('IPYTHONDIR', None)
289 282 env.pop('XDG_CONFIG_HOME', None)
290 283 env['HOME'] = tmpdir
291 284 ipdir = os.path.join(tmpdir, '.ipython')
292 285 os.mkdir(ipdir, 0o555)
293 286 try:
294 287 open(os.path.join(ipdir, "_foo_"), 'w').close()
295 288 except IOError:
296 289 pass
297 290 else:
298 291 # I can still write to an unwritable dir,
299 292 # assume I'm root and skip the test
300 293 raise SkipTest("I can't create directories that I can't write to")
301 294 with AssertPrints('is not a writable location', channel='stderr'):
302 295 ipdir = paths.get_ipython_dir()
303 296 env.pop('IPYTHON_DIR', None)
304 297
305 298 @with_environment
306 299 def test_get_py_filename():
307 300 os.chdir(TMP_TEST_DIR)
308 301 with make_tempfile('foo.py'):
309 302 nt.assert_equal(path.get_py_filename('foo.py'), 'foo.py')
310 303 nt.assert_equal(path.get_py_filename('foo'), 'foo.py')
311 304 with make_tempfile('foo'):
312 305 nt.assert_equal(path.get_py_filename('foo'), 'foo')
313 306 nt.assert_raises(IOError, path.get_py_filename, 'foo.py')
314 307 nt.assert_raises(IOError, path.get_py_filename, 'foo')
315 308 nt.assert_raises(IOError, path.get_py_filename, 'foo.py')
316 309 true_fn = 'foo with spaces.py'
317 310 with make_tempfile(true_fn):
318 311 nt.assert_equal(path.get_py_filename('foo with spaces'), true_fn)
319 312 nt.assert_equal(path.get_py_filename('foo with spaces.py'), true_fn)
320 313 nt.assert_raises(IOError, path.get_py_filename, '"foo with spaces.py"')
321 314 nt.assert_raises(IOError, path.get_py_filename, "'foo with spaces.py'")
322 315
323 316 @onlyif_unicode_paths
324 317 def test_unicode_in_filename():
325 318 """When a file doesn't exist, the exception raised should be safe to call
326 319 str() on - i.e. in Python 2 it must only have ASCII characters.
327 320
328 321 https://github.com/ipython/ipython/issues/875
329 322 """
330 323 try:
331 324 # these calls should not throw unicode encode exceptions
332 325 path.get_py_filename(u'fooéè.py', force_win32=False)
333 326 except IOError as ex:
334 327 str(ex)
335 328
336 329
337 330 class TestShellGlob(object):
338 331
339 332 @classmethod
340 333 def setUpClass(cls):
341 334 cls.filenames_start_with_a = ['a0', 'a1', 'a2']
342 335 cls.filenames_end_with_b = ['0b', '1b', '2b']
343 336 cls.filenames = cls.filenames_start_with_a + cls.filenames_end_with_b
344 337 cls.tempdir = TemporaryDirectory()
345 338 td = cls.tempdir.name
346 339
347 340 with cls.in_tempdir():
348 341 # Create empty files
349 342 for fname in cls.filenames:
350 343 open(os.path.join(td, fname), 'w').close()
351 344
352 345 @classmethod
353 346 def tearDownClass(cls):
354 347 cls.tempdir.cleanup()
355 348
356 349 @classmethod
357 350 @contextmanager
358 351 def in_tempdir(cls):
359 352 save = os.getcwd()
360 353 try:
361 354 os.chdir(cls.tempdir.name)
362 355 yield
363 356 finally:
364 357 os.chdir(save)
365 358
366 359 def check_match(self, patterns, matches):
367 360 with self.in_tempdir():
368 361 # glob returns unordered list. that's why sorted is required.
369 362 nt.assert_equal(sorted(path.shellglob(patterns)),
370 363 sorted(matches))
371 364
372 365 def common_cases(self):
373 366 return [
374 367 (['*'], self.filenames),
375 368 (['a*'], self.filenames_start_with_a),
376 369 (['*c'], ['*c']),
377 370 (['*', 'a*', '*b', '*c'], self.filenames
378 371 + self.filenames_start_with_a
379 372 + self.filenames_end_with_b
380 373 + ['*c']),
381 374 (['a[012]'], self.filenames_start_with_a),
382 375 ]
383 376
384 377 @skip_win32
385 378 def test_match_posix(self):
386 379 for (patterns, matches) in self.common_cases() + [
387 380 ([r'\*'], ['*']),
388 381 ([r'a\*', 'a*'], ['a*'] + self.filenames_start_with_a),
389 382 ([r'a\[012]'], ['a[012]']),
390 383 ]:
391 384 yield (self.check_match, patterns, matches)
392 385
393 386 @skip_if_not_win32
394 387 def test_match_windows(self):
395 388 for (patterns, matches) in self.common_cases() + [
396 389 # In windows, backslash is interpreted as path
397 390 # separator. Therefore, you can't escape glob
398 391 # using it.
399 392 ([r'a\*', 'a*'], [r'a\*'] + self.filenames_start_with_a),
400 393 ([r'a\[012]'], [r'a\[012]']),
401 394 ]:
402 395 yield (self.check_match, patterns, matches)
403 396
404 397
405 398 def test_unescape_glob():
406 399 nt.assert_equal(path.unescape_glob(r'\*\[\!\]\?'), '*[!]?')
407 400 nt.assert_equal(path.unescape_glob(r'\\*'), r'\*')
408 401 nt.assert_equal(path.unescape_glob(r'\\\*'), r'\*')
409 402 nt.assert_equal(path.unescape_glob(r'\\a'), r'\a')
410 403 nt.assert_equal(path.unescape_glob(r'\a'), r'\a')
411 404
412 405
413 406 def test_ensure_dir_exists():
414 407 with TemporaryDirectory() as td:
415 408 d = os.path.join(td, u'βˆ‚ir')
416 409 path.ensure_dir_exists(d) # create it
417 410 assert os.path.isdir(d)
418 411 path.ensure_dir_exists(d) # no-op
419 412 f = os.path.join(td, u'Ζ’ile')
420 413 open(f, 'w').close() # touch
421 414 with nt.assert_raises(IOError):
422 415 path.ensure_dir_exists(f)
423 416
424 417 class TestLinkOrCopy(object):
425 418 def setUp(self):
426 419 self.tempdir = TemporaryDirectory()
427 420 self.src = self.dst("src")
428 421 with open(self.src, "w") as f:
429 422 f.write("Hello, world!")
430 423
431 424 def tearDown(self):
432 425 self.tempdir.cleanup()
433 426
434 427 def dst(self, *args):
435 428 return os.path.join(self.tempdir.name, *args)
436 429
437 430 def assert_inode_not_equal(self, a, b):
438 431 nt.assert_not_equal(os.stat(a).st_ino, os.stat(b).st_ino,
439 432 "%r and %r do reference the same indoes" %(a, b))
440 433
441 434 def assert_inode_equal(self, a, b):
442 435 nt.assert_equal(os.stat(a).st_ino, os.stat(b).st_ino,
443 436 "%r and %r do not reference the same indoes" %(a, b))
444 437
445 438 def assert_content_equal(self, a, b):
446 439 with open(a) as a_f:
447 440 with open(b) as b_f:
448 441 nt.assert_equal(a_f.read(), b_f.read())
449 442
450 443 @skip_win32
451 444 def test_link_successful(self):
452 445 dst = self.dst("target")
453 446 path.link_or_copy(self.src, dst)
454 447 self.assert_inode_equal(self.src, dst)
455 448
456 449 @skip_win32
457 450 def test_link_into_dir(self):
458 451 dst = self.dst("some_dir")
459 452 os.mkdir(dst)
460 453 path.link_or_copy(self.src, dst)
461 454 expected_dst = self.dst("some_dir", os.path.basename(self.src))
462 455 self.assert_inode_equal(self.src, expected_dst)
463 456
464 457 @skip_win32
465 458 def test_target_exists(self):
466 459 dst = self.dst("target")
467 460 open(dst, "w").close()
468 461 path.link_or_copy(self.src, dst)
469 462 self.assert_inode_equal(self.src, dst)
470 463
471 464 @skip_win32
472 465 def test_no_link(self):
473 466 real_link = os.link
474 467 try:
475 468 del os.link
476 469 dst = self.dst("target")
477 470 path.link_or_copy(self.src, dst)
478 471 self.assert_content_equal(self.src, dst)
479 472 self.assert_inode_not_equal(self.src, dst)
480 473 finally:
481 474 os.link = real_link
482 475
483 476 @skip_if_not_win32
484 477 def test_windows(self):
485 478 dst = self.dst("target")
486 479 path.link_or_copy(self.src, dst)
487 480 self.assert_content_equal(self.src, dst)
488 481
489 482 def test_link_twice(self):
490 483 # Linking the same file twice shouldn't leave duplicates around.
491 484 # See https://github.com/ipython/ipython/issues/6450
492 485 dst = self.dst('target')
493 486 path.link_or_copy(self.src, dst)
494 487 path.link_or_copy(self.src, dst)
495 488 self.assert_inode_equal(self.src, dst)
496 489 nt.assert_equal(sorted(os.listdir(self.tempdir.name)), ['src', 'target'])
General Comments 0
You need to be logged in to leave comments. Login now