##// END OF EJS Templates
TST: Put %xmode back after testing new Minimal mode.
Dan Allan -
Show More
@@ -1,403 +1,406 b''
1 1 # encoding: utf-8
2 2 """Tests for IPython.core.ultratb
3 3 """
4 4 import io
5 5 import logging
6 6 import sys
7 7 import os.path
8 8 from textwrap import dedent
9 9 import traceback
10 10 import unittest
11 11 from unittest import mock
12 12
13 13 from ..ultratb import ColorTB, VerboseTB, find_recursion
14 14
15 15
16 16 from IPython.testing import tools as tt
17 17 from IPython.testing.decorators import onlyif_unicode_paths
18 18 from IPython.utils.syspathcontext import prepended_to_syspath
19 19 from IPython.utils.tempdir import TemporaryDirectory
20 20
21 21 ip = get_ipython()
22 22
23 23 file_1 = """1
24 24 2
25 25 3
26 26 def f():
27 27 1/0
28 28 """
29 29
30 30 file_2 = """def f():
31 31 1/0
32 32 """
33 33
34 34 class ChangedPyFileTest(unittest.TestCase):
35 35 def test_changing_py_file(self):
36 36 """Traceback produced if the line where the error occurred is missing?
37 37
38 38 https://github.com/ipython/ipython/issues/1456
39 39 """
40 40 with TemporaryDirectory() as td:
41 41 fname = os.path.join(td, "foo.py")
42 42 with open(fname, "w") as f:
43 43 f.write(file_1)
44 44
45 45 with prepended_to_syspath(td):
46 46 ip.run_cell("import foo")
47 47
48 48 with tt.AssertPrints("ZeroDivisionError"):
49 49 ip.run_cell("foo.f()")
50 50
51 51 # Make the file shorter, so the line of the error is missing.
52 52 with open(fname, "w") as f:
53 53 f.write(file_2)
54 54
55 55 # For some reason, this was failing on the *second* call after
56 56 # changing the file, so we call f() twice.
57 57 with tt.AssertNotPrints("Internal Python error", channel='stderr'):
58 58 with tt.AssertPrints("ZeroDivisionError"):
59 59 ip.run_cell("foo.f()")
60 60 with tt.AssertPrints("ZeroDivisionError"):
61 61 ip.run_cell("foo.f()")
62 62
63 63 iso_8859_5_file = u'''# coding: iso-8859-5
64 64
65 65 def fail():
66 66 """Π΄Π±Π˜Π–"""
67 67 1/0 # Π΄Π±Π˜Π–
68 68 '''
69 69
70 70 class NonAsciiTest(unittest.TestCase):
71 71 @onlyif_unicode_paths
72 72 def test_nonascii_path(self):
73 73 # Non-ascii directory name as well.
74 74 with TemporaryDirectory(suffix=u'Γ©') as td:
75 75 fname = os.path.join(td, u"fooΓ©.py")
76 76 with open(fname, "w") as f:
77 77 f.write(file_1)
78 78
79 79 with prepended_to_syspath(td):
80 80 ip.run_cell("import foo")
81 81
82 82 with tt.AssertPrints("ZeroDivisionError"):
83 83 ip.run_cell("foo.f()")
84 84
85 85 def test_iso8859_5(self):
86 86 with TemporaryDirectory() as td:
87 87 fname = os.path.join(td, 'dfghjkl.py')
88 88
89 89 with io.open(fname, 'w', encoding='iso-8859-5') as f:
90 90 f.write(iso_8859_5_file)
91 91
92 92 with prepended_to_syspath(td):
93 93 ip.run_cell("from dfghjkl import fail")
94 94
95 95 with tt.AssertPrints("ZeroDivisionError"):
96 96 with tt.AssertPrints(u'Π΄Π±Π˜Π–', suppress=False):
97 97 ip.run_cell('fail()')
98 98
99 99 def test_nonascii_msg(self):
100 100 cell = u"raise Exception('Γ©')"
101 101 expected = u"Exception('Γ©')"
102 102 ip.run_cell("%xmode plain")
103 103 with tt.AssertPrints(expected):
104 104 ip.run_cell(cell)
105 105
106 106 ip.run_cell("%xmode verbose")
107 107 with tt.AssertPrints(expected):
108 108 ip.run_cell(cell)
109 109
110 110 ip.run_cell("%xmode context")
111 111 with tt.AssertPrints(expected):
112 112 ip.run_cell(cell)
113 113
114 114 ip.run_cell("%xmode minimal")
115 115 with tt.AssertPrints(u"Exception: Γ©"):
116 116 ip.run_cell(cell)
117 117
118 # Put this back into Context mode for later tests.
119 ip.run_cell("%xmode context")
120
118 121 class NestedGenExprTestCase(unittest.TestCase):
119 122 """
120 123 Regression test for the following issues:
121 124 https://github.com/ipython/ipython/issues/8293
122 125 https://github.com/ipython/ipython/issues/8205
123 126 """
124 127 def test_nested_genexpr(self):
125 128 code = dedent(
126 129 """\
127 130 class SpecificException(Exception):
128 131 pass
129 132
130 133 def foo(x):
131 134 raise SpecificException("Success!")
132 135
133 136 sum(sum(foo(x) for _ in [0]) for x in [0])
134 137 """
135 138 )
136 139 with tt.AssertPrints('SpecificException: Success!', suppress=False):
137 140 ip.run_cell(code)
138 141
139 142
140 143 indentationerror_file = """if True:
141 144 zoon()
142 145 """
143 146
144 147 class IndentationErrorTest(unittest.TestCase):
145 148 def test_indentationerror_shows_line(self):
146 149 # See issue gh-2398
147 150 with tt.AssertPrints("IndentationError"):
148 151 with tt.AssertPrints("zoon()", suppress=False):
149 152 ip.run_cell(indentationerror_file)
150 153
151 154 with TemporaryDirectory() as td:
152 155 fname = os.path.join(td, "foo.py")
153 156 with open(fname, "w") as f:
154 157 f.write(indentationerror_file)
155 158
156 159 with tt.AssertPrints("IndentationError"):
157 160 with tt.AssertPrints("zoon()", suppress=False):
158 161 ip.magic('run %s' % fname)
159 162
160 163 se_file_1 = """1
161 164 2
162 165 7/
163 166 """
164 167
165 168 se_file_2 = """7/
166 169 """
167 170
168 171 class SyntaxErrorTest(unittest.TestCase):
169 172 def test_syntaxerror_without_lineno(self):
170 173 with tt.AssertNotPrints("TypeError"):
171 174 with tt.AssertPrints("line unknown"):
172 175 ip.run_cell("raise SyntaxError()")
173 176
174 177 def test_syntaxerror_no_stacktrace_at_compile_time(self):
175 178 syntax_error_at_compile_time = """
176 179 def foo():
177 180 ..
178 181 """
179 182 with tt.AssertPrints("SyntaxError"):
180 183 ip.run_cell(syntax_error_at_compile_time)
181 184
182 185 with tt.AssertNotPrints("foo()"):
183 186 ip.run_cell(syntax_error_at_compile_time)
184 187
185 188 def test_syntaxerror_stacktrace_when_running_compiled_code(self):
186 189 syntax_error_at_runtime = """
187 190 def foo():
188 191 eval("..")
189 192
190 193 def bar():
191 194 foo()
192 195
193 196 bar()
194 197 """
195 198 with tt.AssertPrints("SyntaxError"):
196 199 ip.run_cell(syntax_error_at_runtime)
197 200 # Assert syntax error during runtime generate stacktrace
198 201 with tt.AssertPrints(["foo()", "bar()"]):
199 202 ip.run_cell(syntax_error_at_runtime)
200 203
201 204 def test_changing_py_file(self):
202 205 with TemporaryDirectory() as td:
203 206 fname = os.path.join(td, "foo.py")
204 207 with open(fname, 'w') as f:
205 208 f.write(se_file_1)
206 209
207 210 with tt.AssertPrints(["7/", "SyntaxError"]):
208 211 ip.magic("run " + fname)
209 212
210 213 # Modify the file
211 214 with open(fname, 'w') as f:
212 215 f.write(se_file_2)
213 216
214 217 # The SyntaxError should point to the correct line
215 218 with tt.AssertPrints(["7/", "SyntaxError"]):
216 219 ip.magic("run " + fname)
217 220
218 221 def test_non_syntaxerror(self):
219 222 # SyntaxTB may be called with an error other than a SyntaxError
220 223 # See e.g. gh-4361
221 224 try:
222 225 raise ValueError('QWERTY')
223 226 except ValueError:
224 227 with tt.AssertPrints('QWERTY'):
225 228 ip.showsyntaxerror()
226 229
227 230
228 231 class Python3ChainedExceptionsTest(unittest.TestCase):
229 232 DIRECT_CAUSE_ERROR_CODE = """
230 233 try:
231 234 x = 1 + 2
232 235 print(not_defined_here)
233 236 except Exception as e:
234 237 x += 55
235 238 x - 1
236 239 y = {}
237 240 raise KeyError('uh') from e
238 241 """
239 242
240 243 EXCEPTION_DURING_HANDLING_CODE = """
241 244 try:
242 245 x = 1 + 2
243 246 print(not_defined_here)
244 247 except Exception as e:
245 248 x += 55
246 249 x - 1
247 250 y = {}
248 251 raise KeyError('uh')
249 252 """
250 253
251 254 SUPPRESS_CHAINING_CODE = """
252 255 try:
253 256 1/0
254 257 except Exception:
255 258 raise ValueError("Yikes") from None
256 259 """
257 260
258 261 def test_direct_cause_error(self):
259 262 with tt.AssertPrints(["KeyError", "NameError", "direct cause"]):
260 263 ip.run_cell(self.DIRECT_CAUSE_ERROR_CODE)
261 264
262 265 def test_exception_during_handling_error(self):
263 266 with tt.AssertPrints(["KeyError", "NameError", "During handling"]):
264 267 ip.run_cell(self.EXCEPTION_DURING_HANDLING_CODE)
265 268
266 269 def test_suppress_exception_chaining(self):
267 270 with tt.AssertNotPrints("ZeroDivisionError"), \
268 271 tt.AssertPrints("ValueError", suppress=False):
269 272 ip.run_cell(self.SUPPRESS_CHAINING_CODE)
270 273
271 274
272 275 class RecursionTest(unittest.TestCase):
273 276 DEFINITIONS = """
274 277 def non_recurs():
275 278 1/0
276 279
277 280 def r1():
278 281 r1()
279 282
280 283 def r3a():
281 284 r3b()
282 285
283 286 def r3b():
284 287 r3c()
285 288
286 289 def r3c():
287 290 r3a()
288 291
289 292 def r3o1():
290 293 r3a()
291 294
292 295 def r3o2():
293 296 r3o1()
294 297 """
295 298 def setUp(self):
296 299 ip.run_cell(self.DEFINITIONS)
297 300
298 301 def test_no_recursion(self):
299 302 with tt.AssertNotPrints("frames repeated"):
300 303 ip.run_cell("non_recurs()")
301 304
302 305 def test_recursion_one_frame(self):
303 306 with tt.AssertPrints("1 frames repeated"):
304 307 ip.run_cell("r1()")
305 308
306 309 def test_recursion_three_frames(self):
307 310 with tt.AssertPrints("3 frames repeated"):
308 311 ip.run_cell("r3o2()")
309 312
310 313 def test_find_recursion(self):
311 314 captured = []
312 315 def capture_exc(*args, **kwargs):
313 316 captured.append(sys.exc_info())
314 317 with mock.patch.object(ip, 'showtraceback', capture_exc):
315 318 ip.run_cell("r3o2()")
316 319
317 320 self.assertEqual(len(captured), 1)
318 321 etype, evalue, tb = captured[0]
319 322 self.assertIn("recursion", str(evalue))
320 323
321 324 records = ip.InteractiveTB.get_records(tb, 3, ip.InteractiveTB.tb_offset)
322 325 for r in records[:10]:
323 326 print(r[1:4])
324 327
325 328 # The outermost frames should be:
326 329 # 0: the 'cell' that was running when the exception came up
327 330 # 1: r3o2()
328 331 # 2: r3o1()
329 332 # 3: r3a()
330 333 # Then repeating r3b, r3c, r3a
331 334 last_unique, repeat_length = find_recursion(etype, evalue, records)
332 335 self.assertEqual(last_unique, 2)
333 336 self.assertEqual(repeat_length, 3)
334 337
335 338
336 339 #----------------------------------------------------------------------------
337 340
338 341 # module testing (minimal)
339 342 def test_handlers():
340 343 def spam(c, d_e):
341 344 (d, e) = d_e
342 345 x = c + d
343 346 y = c * d
344 347 foo(x, y)
345 348
346 349 def foo(a, b, bar=1):
347 350 eggs(a, b + bar)
348 351
349 352 def eggs(f, g, z=globals()):
350 353 h = f + g
351 354 i = f - g
352 355 return h / i
353 356
354 357 buff = io.StringIO()
355 358
356 359 buff.write('')
357 360 buff.write('*** Before ***')
358 361 try:
359 362 buff.write(spam(1, (2, 3)))
360 363 except:
361 364 traceback.print_exc(file=buff)
362 365
363 366 handler = ColorTB(ostream=buff)
364 367 buff.write('*** ColorTB ***')
365 368 try:
366 369 buff.write(spam(1, (2, 3)))
367 370 except:
368 371 handler(*sys.exc_info())
369 372 buff.write('')
370 373
371 374 handler = VerboseTB(ostream=buff)
372 375 buff.write('*** VerboseTB ***')
373 376 try:
374 377 buff.write(spam(1, (2, 3)))
375 378 except:
376 379 handler(*sys.exc_info())
377 380 buff.write('')
378 381
379 382
380 383 class TokenizeFailureTest(unittest.TestCase):
381 384 """Tests related to https://github.com/ipython/ipython/issues/6864."""
382 385
383 386 def testLogging(self):
384 387 message = "An unexpected error occurred while tokenizing input"
385 388 cell = 'raise ValueError("""a\nb""")'
386 389
387 390 stream = io.StringIO()
388 391 handler = logging.StreamHandler(stream)
389 392 logger = logging.getLogger()
390 393 loglevel = logger.level
391 394 logger.addHandler(handler)
392 395 self.addCleanup(lambda: logger.removeHandler(handler))
393 396 self.addCleanup(lambda: logger.setLevel(loglevel))
394 397
395 398 logger.setLevel(logging.INFO)
396 399 with tt.AssertNotPrints(message):
397 400 ip.run_cell(cell)
398 401 self.assertNotIn(message, stream.getvalue())
399 402
400 403 logger.setLevel(logging.DEBUG)
401 404 with tt.AssertNotPrints(message):
402 405 ip.run_cell(cell)
403 406 self.assertIn(message, stream.getvalue())
General Comments 0
You need to be logged in to leave comments. Login now