##// END OF EJS Templates
Merge pull request #11886 from alexmojaki/master...
Matthias Bussonnier -
r25477:7db73df5 merge
parent child Browse files
Show More
@@ -1,246 +1,231 b''
1 1 """Tests for the key interactiveshell module, where the main ipython class is defined.
2 2 """
3 3 #-----------------------------------------------------------------------------
4 4 # Module imports
5 5 #-----------------------------------------------------------------------------
6 6
7 7 # third party
8 8 import nose.tools as nt
9 9
10 10 # our own packages
11 11
12 12 #-----------------------------------------------------------------------------
13 13 # Test functions
14 14 #-----------------------------------------------------------------------------
15 15
16 16 def test_reset():
17 17 """reset must clear most namespaces."""
18 18
19 19 # Check that reset runs without error
20 20 ip.reset()
21 21
22 22 # Once we've reset it (to clear of any junk that might have been there from
23 23 # other tests, we can count how many variables are in the user's namespace
24 24 nvars_user_ns = len(ip.user_ns)
25 25 nvars_hidden = len(ip.user_ns_hidden)
26 26
27 27 # Now add a few variables to user_ns, and check that reset clears them
28 28 ip.user_ns['x'] = 1
29 29 ip.user_ns['y'] = 1
30 30 ip.reset()
31 31
32 32 # Finally, check that all namespaces have only as many variables as we
33 33 # expect to find in them:
34 34 nt.assert_equal(len(ip.user_ns), nvars_user_ns)
35 35 nt.assert_equal(len(ip.user_ns_hidden), nvars_hidden)
36 36
37 37
38 38 # Tests for reporting of exceptions in various modes, handling of SystemExit,
39 39 # and %tb functionality. This is really a mix of testing ultraTB and interactiveshell.
40 40
41 41 def doctest_tb_plain():
42 42 """
43 43 In [18]: xmode plain
44 44 Exception reporting mode: Plain
45 45
46 46 In [19]: run simpleerr.py
47 47 Traceback (most recent call last):
48 48 ...line 32, in <module>
49 49 bar(mode)
50 50 ...line 16, in bar
51 51 div0()
52 52 ...line 8, in div0
53 53 x/y
54 54 ZeroDivisionError: ...
55 55 """
56 56
57 57
58 58 def doctest_tb_context():
59 59 """
60 60 In [3]: xmode context
61 61 Exception reporting mode: Context
62 62
63 63 In [4]: run simpleerr.py
64 64 ---------------------------------------------------------------------------
65 65 ZeroDivisionError Traceback (most recent call last)
66 66 <BLANKLINE>
67 67 ... in <module>
68 29 except IndexError:
68 69 30 mode = 'div'
69 31
70 70 ---> 32 bar(mode)
71 71 <BLANKLINE>
72 72 ... in bar(mode)
73 73 14 "bar"
74 74 15 if mode=='div':
75 75 ---> 16 div0()
76 76 17 elif mode=='exit':
77 77 18 try:
78 78 <BLANKLINE>
79 79 ... in div0()
80 80 6 x = 1
81 81 7 y = 0
82 82 ----> 8 x/y
83 9
84 10 def sysexit(stat, mode):
85 83 <BLANKLINE>
86 84 ZeroDivisionError: ...
87 85 """
88 86
89 87
90 88 def doctest_tb_verbose():
91 89 """
92 90 In [5]: xmode verbose
93 91 Exception reporting mode: Verbose
94 92
95 93 In [6]: run simpleerr.py
96 94 ---------------------------------------------------------------------------
97 95 ZeroDivisionError Traceback (most recent call last)
98 96 <BLANKLINE>
99 97 ... in <module>
98 29 except IndexError:
100 99 30 mode = 'div'
101 31
102 100 ---> 32 bar(mode)
103 global bar = <function bar at ...>
104 global mode = 'div'
101 mode = 'div'
105 102 <BLANKLINE>
106 103 ... in bar(mode='div')
107 104 14 "bar"
108 105 15 if mode=='div':
109 106 ---> 16 div0()
110 global div0 = <function div0 at ...>
111 107 17 elif mode=='exit':
112 108 18 try:
113 109 <BLANKLINE>
114 110 ... in div0()
115 111 6 x = 1
116 112 7 y = 0
117 113 ----> 8 x/y
118 114 x = 1
119 115 y = 0
120 9
121 10 def sysexit(stat, mode):
122 116 <BLANKLINE>
123 117 ZeroDivisionError: ...
124 118 """
125 119
126 120 def doctest_tb_sysexit():
127 121 """
128 122 In [17]: %xmode plain
129 123 Exception reporting mode: Plain
130 124
131 125 In [18]: %run simpleerr.py exit
132 126 An exception has occurred, use %tb to see the full traceback.
133 127 SystemExit: (1, 'Mode = exit')
134 128
135 129 In [19]: %run simpleerr.py exit 2
136 130 An exception has occurred, use %tb to see the full traceback.
137 131 SystemExit: (2, 'Mode = exit')
138 132
139 133 In [20]: %tb
140 134 Traceback (most recent call last):
141 135 File ... in <module>
142 136 bar(mode)
143 137 File ... line 22, in bar
144 138 sysexit(stat, mode)
145 139 File ... line 11, in sysexit
146 140 raise SystemExit(stat, 'Mode = %s' % mode)
147 141 SystemExit: (2, 'Mode = exit')
148 142
149 143 In [21]: %xmode context
150 144 Exception reporting mode: Context
151 145
152 146 In [22]: %tb
153 147 ---------------------------------------------------------------------------
154 148 SystemExit Traceback (most recent call last)
155 149 <BLANKLINE>
156 150 ...<module>
151 29 except IndexError:
157 152 30 mode = 'div'
158 31
159 153 ---> 32 bar(mode)
160 154 <BLANKLINE>
161 155 ...bar(mode)
162 156 20 except:
163 157 21 stat = 1
164 158 ---> 22 sysexit(stat, mode)
165 159 23 else:
166 160 24 raise ValueError('Unknown mode')
167 161 <BLANKLINE>
168 162 ...sysexit(stat, mode)
169 9
170 163 10 def sysexit(stat, mode):
171 164 ---> 11 raise SystemExit(stat, 'Mode = %s' % mode)
172 12
173 13 def bar(mode):
174 165 <BLANKLINE>
175 166 SystemExit: (2, 'Mode = exit')
176 167
177 168 In [23]: %xmode verbose
178 169 Exception reporting mode: Verbose
179 170
180 171 In [24]: %tb
181 172 ---------------------------------------------------------------------------
182 173 SystemExit Traceback (most recent call last)
183 174 <BLANKLINE>
184 175 ... in <module>
176 29 except IndexError:
185 177 30 mode = 'div'
186 31
187 178 ---> 32 bar(mode)
188 global bar = <function bar at ...>
189 global mode = 'exit'
179 mode = 'exit'
190 180 <BLANKLINE>
191 181 ... in bar(mode='exit')
192 182 20 except:
193 183 21 stat = 1
194 184 ---> 22 sysexit(stat, mode)
195 global sysexit = <function sysexit at ...>
196 stat = 2
197 185 mode = 'exit'
186 stat = 2
198 187 23 else:
199 188 24 raise ValueError('Unknown mode')
200 189 <BLANKLINE>
201 190 ... in sysexit(stat=2, mode='exit')
202 9
203 191 10 def sysexit(stat, mode):
204 192 ---> 11 raise SystemExit(stat, 'Mode = %s' % mode)
205 global SystemExit = undefined
206 193 stat = 2
207 194 mode = 'exit'
208 12
209 13 def bar(mode):
210 195 <BLANKLINE>
211 196 SystemExit: (2, 'Mode = exit')
212 197 """
213 198
214 199
215 200 def test_run_cell():
216 201 import textwrap
217 202 ip.run_cell('a = 10\na+=1')
218 203 ip.run_cell('assert a == 11\nassert 1')
219 204
220 205 nt.assert_equal(ip.user_ns['a'], 11)
221 206 complex = textwrap.dedent("""
222 207 if 1:
223 208 print "hello"
224 209 if 1:
225 210 print "world"
226 211
227 212 if 2:
228 213 print "foo"
229 214
230 215 if 3:
231 216 print "bar"
232 217
233 218 if 4:
234 219 print "bar"
235 220
236 221 """)
237 222 # Simply verifies that this kind of input is run
238 223 ip.run_cell(complex)
239 224
240 225
241 226 def test_db():
242 227 """Test the internal database used for variable persistence."""
243 228 ip.db['__unittest_'] = 12
244 229 nt.assert_equal(ip.db['__unittest_'], 12)
245 230 del ip.db['__unittest_']
246 231 assert '__unittest_' not in ip.db
@@ -1,466 +1,408 b''
1 1 # encoding: utf-8
2 2 """Tests for IPython.core.ultratb
3 3 """
4 4 import io
5 5 import logging
6 import re
6 7 import sys
7 8 import os.path
8 9 from textwrap import dedent
9 10 import traceback
10 11 import unittest
11 from unittest import mock
12 12
13 import IPython.core.ultratb as ultratb
14 from IPython.core.ultratb import ColorTB, VerboseTB, find_recursion
13 from IPython.core.ultratb import ColorTB, VerboseTB
15 14
16 15
17 16 from IPython.testing import tools as tt
18 17 from IPython.testing.decorators import onlyif_unicode_paths
19 18 from IPython.utils.syspathcontext import prepended_to_syspath
20 19 from IPython.utils.tempdir import TemporaryDirectory
21 20
22 21 file_1 = """1
23 22 2
24 23 3
25 24 def f():
26 25 1/0
27 26 """
28 27
29 28 file_2 = """def f():
30 29 1/0
31 30 """
32 31
33 32
34 33 def recursionlimit(frames):
35 34 """
36 35 decorator to set the recursion limit temporarily
37 36 """
38 37
39 38 def inner(test_function):
40 39 def wrapper(*args, **kwargs):
41 _orig_rec_limit = ultratb._FRAME_RECURSION_LIMIT
42 ultratb._FRAME_RECURSION_LIMIT = 50
43
44 40 rl = sys.getrecursionlimit()
45 41 sys.setrecursionlimit(frames)
46 42 try:
47 43 return test_function(*args, **kwargs)
48 44 finally:
49 45 sys.setrecursionlimit(rl)
50 ultratb._FRAME_RECURSION_LIMIT = _orig_rec_limit
51 46
52 47 return wrapper
53 48
54 49 return inner
55 50
56 51
57 52 class ChangedPyFileTest(unittest.TestCase):
58 53 def test_changing_py_file(self):
59 54 """Traceback produced if the line where the error occurred is missing?
60 55
61 56 https://github.com/ipython/ipython/issues/1456
62 57 """
63 58 with TemporaryDirectory() as td:
64 59 fname = os.path.join(td, "foo.py")
65 60 with open(fname, "w") as f:
66 61 f.write(file_1)
67 62
68 63 with prepended_to_syspath(td):
69 64 ip.run_cell("import foo")
70 65
71 66 with tt.AssertPrints("ZeroDivisionError"):
72 67 ip.run_cell("foo.f()")
73 68
74 69 # Make the file shorter, so the line of the error is missing.
75 70 with open(fname, "w") as f:
76 71 f.write(file_2)
77 72
78 73 # For some reason, this was failing on the *second* call after
79 74 # changing the file, so we call f() twice.
80 75 with tt.AssertNotPrints("Internal Python error", channel='stderr'):
81 76 with tt.AssertPrints("ZeroDivisionError"):
82 77 ip.run_cell("foo.f()")
83 78 with tt.AssertPrints("ZeroDivisionError"):
84 79 ip.run_cell("foo.f()")
85 80
86 81 iso_8859_5_file = u'''# coding: iso-8859-5
87 82
88 83 def fail():
89 84 """Π΄Π±Π˜Π–"""
90 85 1/0 # Π΄Π±Π˜Π–
91 86 '''
92 87
93 88 class NonAsciiTest(unittest.TestCase):
94 89 @onlyif_unicode_paths
95 90 def test_nonascii_path(self):
96 91 # Non-ascii directory name as well.
97 92 with TemporaryDirectory(suffix=u'Γ©') as td:
98 93 fname = os.path.join(td, u"fooΓ©.py")
99 94 with open(fname, "w") as f:
100 95 f.write(file_1)
101 96
102 97 with prepended_to_syspath(td):
103 98 ip.run_cell("import foo")
104 99
105 100 with tt.AssertPrints("ZeroDivisionError"):
106 101 ip.run_cell("foo.f()")
107 102
108 103 def test_iso8859_5(self):
109 104 with TemporaryDirectory() as td:
110 105 fname = os.path.join(td, 'dfghjkl.py')
111 106
112 107 with io.open(fname, 'w', encoding='iso-8859-5') as f:
113 108 f.write(iso_8859_5_file)
114 109
115 110 with prepended_to_syspath(td):
116 111 ip.run_cell("from dfghjkl import fail")
117 112
118 113 with tt.AssertPrints("ZeroDivisionError"):
119 114 with tt.AssertPrints(u'Π΄Π±Π˜Π–', suppress=False):
120 115 ip.run_cell('fail()')
121 116
122 117 def test_nonascii_msg(self):
123 118 cell = u"raise Exception('Γ©')"
124 119 expected = u"Exception('Γ©')"
125 120 ip.run_cell("%xmode plain")
126 121 with tt.AssertPrints(expected):
127 122 ip.run_cell(cell)
128 123
129 124 ip.run_cell("%xmode verbose")
130 125 with tt.AssertPrints(expected):
131 126 ip.run_cell(cell)
132 127
133 128 ip.run_cell("%xmode context")
134 129 with tt.AssertPrints(expected):
135 130 ip.run_cell(cell)
136 131
137 132 ip.run_cell("%xmode minimal")
138 133 with tt.AssertPrints(u"Exception: Γ©"):
139 134 ip.run_cell(cell)
140 135
141 136 # Put this back into Context mode for later tests.
142 137 ip.run_cell("%xmode context")
143 138
144 139 class NestedGenExprTestCase(unittest.TestCase):
145 140 """
146 141 Regression test for the following issues:
147 142 https://github.com/ipython/ipython/issues/8293
148 143 https://github.com/ipython/ipython/issues/8205
149 144 """
150 145 def test_nested_genexpr(self):
151 146 code = dedent(
152 147 """\
153 148 class SpecificException(Exception):
154 149 pass
155 150
156 151 def foo(x):
157 152 raise SpecificException("Success!")
158 153
159 154 sum(sum(foo(x) for _ in [0]) for x in [0])
160 155 """
161 156 )
162 157 with tt.AssertPrints('SpecificException: Success!', suppress=False):
163 158 ip.run_cell(code)
164 159
165 160
166 161 indentationerror_file = """if True:
167 162 zoon()
168 163 """
169 164
170 165 class IndentationErrorTest(unittest.TestCase):
171 166 def test_indentationerror_shows_line(self):
172 167 # See issue gh-2398
173 168 with tt.AssertPrints("IndentationError"):
174 169 with tt.AssertPrints("zoon()", suppress=False):
175 170 ip.run_cell(indentationerror_file)
176 171
177 172 with TemporaryDirectory() as td:
178 173 fname = os.path.join(td, "foo.py")
179 174 with open(fname, "w") as f:
180 175 f.write(indentationerror_file)
181 176
182 177 with tt.AssertPrints("IndentationError"):
183 178 with tt.AssertPrints("zoon()", suppress=False):
184 179 ip.magic('run %s' % fname)
185 180
186 181 se_file_1 = """1
187 182 2
188 183 7/
189 184 """
190 185
191 186 se_file_2 = """7/
192 187 """
193 188
194 189 class SyntaxErrorTest(unittest.TestCase):
195 190 def test_syntaxerror_without_lineno(self):
196 191 with tt.AssertNotPrints("TypeError"):
197 192 with tt.AssertPrints("line unknown"):
198 193 ip.run_cell("raise SyntaxError()")
199 194
200 195 def test_syntaxerror_no_stacktrace_at_compile_time(self):
201 196 syntax_error_at_compile_time = """
202 197 def foo():
203 198 ..
204 199 """
205 200 with tt.AssertPrints("SyntaxError"):
206 201 ip.run_cell(syntax_error_at_compile_time)
207 202
208 203 with tt.AssertNotPrints("foo()"):
209 204 ip.run_cell(syntax_error_at_compile_time)
210 205
211 206 def test_syntaxerror_stacktrace_when_running_compiled_code(self):
212 207 syntax_error_at_runtime = """
213 208 def foo():
214 209 eval("..")
215 210
216 211 def bar():
217 212 foo()
218 213
219 214 bar()
220 215 """
221 216 with tt.AssertPrints("SyntaxError"):
222 217 ip.run_cell(syntax_error_at_runtime)
223 218 # Assert syntax error during runtime generate stacktrace
224 219 with tt.AssertPrints(["foo()", "bar()"]):
225 220 ip.run_cell(syntax_error_at_runtime)
226 221 del ip.user_ns['bar']
227 222 del ip.user_ns['foo']
228 223
229 224 def test_changing_py_file(self):
230 225 with TemporaryDirectory() as td:
231 226 fname = os.path.join(td, "foo.py")
232 227 with open(fname, 'w') as f:
233 228 f.write(se_file_1)
234 229
235 230 with tt.AssertPrints(["7/", "SyntaxError"]):
236 231 ip.magic("run " + fname)
237 232
238 233 # Modify the file
239 234 with open(fname, 'w') as f:
240 235 f.write(se_file_2)
241 236
242 237 # The SyntaxError should point to the correct line
243 238 with tt.AssertPrints(["7/", "SyntaxError"]):
244 239 ip.magic("run " + fname)
245 240
246 241 def test_non_syntaxerror(self):
247 242 # SyntaxTB may be called with an error other than a SyntaxError
248 243 # See e.g. gh-4361
249 244 try:
250 245 raise ValueError('QWERTY')
251 246 except ValueError:
252 247 with tt.AssertPrints('QWERTY'):
253 248 ip.showsyntaxerror()
254 249
255 250
256 251 class MemoryErrorTest(unittest.TestCase):
257 252 def test_memoryerror(self):
258 253 memoryerror_code = "(" * 200 + ")" * 200
259 254 with tt.AssertPrints("MemoryError"):
260 255 ip.run_cell(memoryerror_code)
261 256
262 257
263 258 class Python3ChainedExceptionsTest(unittest.TestCase):
264 259 DIRECT_CAUSE_ERROR_CODE = """
265 260 try:
266 261 x = 1 + 2
267 262 print(not_defined_here)
268 263 except Exception as e:
269 264 x += 55
270 265 x - 1
271 266 y = {}
272 267 raise KeyError('uh') from e
273 268 """
274 269
275 270 EXCEPTION_DURING_HANDLING_CODE = """
276 271 try:
277 272 x = 1 + 2
278 273 print(not_defined_here)
279 274 except Exception as e:
280 275 x += 55
281 276 x - 1
282 277 y = {}
283 278 raise KeyError('uh')
284 279 """
285 280
286 281 SUPPRESS_CHAINING_CODE = """
287 282 try:
288 283 1/0
289 284 except Exception:
290 285 raise ValueError("Yikes") from None
291 286 """
292 287
293 288 def test_direct_cause_error(self):
294 289 with tt.AssertPrints(["KeyError", "NameError", "direct cause"]):
295 290 ip.run_cell(self.DIRECT_CAUSE_ERROR_CODE)
296 291
297 292 def test_exception_during_handling_error(self):
298 293 with tt.AssertPrints(["KeyError", "NameError", "During handling"]):
299 294 ip.run_cell(self.EXCEPTION_DURING_HANDLING_CODE)
300 295
301 296 def test_suppress_exception_chaining(self):
302 297 with tt.AssertNotPrints("ZeroDivisionError"), \
303 298 tt.AssertPrints("ValueError", suppress=False):
304 299 ip.run_cell(self.SUPPRESS_CHAINING_CODE)
305 300
306 301 def test_plain_direct_cause_error(self):
307 302 with tt.AssertPrints(["KeyError", "NameError", "direct cause"]):
308 303 ip.run_cell("%xmode Plain")
309 304 ip.run_cell(self.DIRECT_CAUSE_ERROR_CODE)
310 305 ip.run_cell("%xmode Verbose")
311 306
312 307 def test_plain_exception_during_handling_error(self):
313 308 with tt.AssertPrints(["KeyError", "NameError", "During handling"]):
314 309 ip.run_cell("%xmode Plain")
315 310 ip.run_cell(self.EXCEPTION_DURING_HANDLING_CODE)
316 311 ip.run_cell("%xmode Verbose")
317 312
318 313 def test_plain_suppress_exception_chaining(self):
319 314 with tt.AssertNotPrints("ZeroDivisionError"), \
320 315 tt.AssertPrints("ValueError", suppress=False):
321 316 ip.run_cell("%xmode Plain")
322 317 ip.run_cell(self.SUPPRESS_CHAINING_CODE)
323 318 ip.run_cell("%xmode Verbose")
324 319
325 320
326 321 class RecursionTest(unittest.TestCase):
327 322 DEFINITIONS = """
328 323 def non_recurs():
329 324 1/0
330 325
331 326 def r1():
332 327 r1()
333 328
334 329 def r3a():
335 330 r3b()
336 331
337 332 def r3b():
338 333 r3c()
339 334
340 335 def r3c():
341 336 r3a()
342 337
343 338 def r3o1():
344 339 r3a()
345 340
346 341 def r3o2():
347 342 r3o1()
348 343 """
349 344 def setUp(self):
350 345 ip.run_cell(self.DEFINITIONS)
351 346
352 347 def test_no_recursion(self):
353 with tt.AssertNotPrints("frames repeated"):
348 with tt.AssertNotPrints("skipping similar frames"):
354 349 ip.run_cell("non_recurs()")
355 350
356 351 @recursionlimit(150)
357 352 def test_recursion_one_frame(self):
358 with tt.AssertPrints("1 frames repeated"):
353 with tt.AssertPrints(re.compile(
354 r"\[\.\.\. skipping similar frames: r1 at line 5 \(\d{2} times\)\]")
355 ):
359 356 ip.run_cell("r1()")
360 357
361 358 @recursionlimit(150)
362 359 def test_recursion_three_frames(self):
363 with tt.AssertPrints("3 frames repeated"):
364 ip.run_cell("r3o2()")
365
366 @recursionlimit(150)
367 def test_find_recursion(self):
368 captured = []
369 def capture_exc(*args, **kwargs):
370 captured.append(sys.exc_info())
371 with mock.patch.object(ip, 'showtraceback', capture_exc):
360 with tt.AssertPrints("[... skipping similar frames: "), \
361 tt.AssertPrints(re.compile(r"r3a at line 8 \(\d{2} times\)"), suppress=False), \
362 tt.AssertPrints(re.compile(r"r3b at line 11 \(\d{2} times\)"), suppress=False), \
363 tt.AssertPrints(re.compile(r"r3c at line 14 \(\d{2} times\)"), suppress=False):
372 364 ip.run_cell("r3o2()")
373 365
374 self.assertEqual(len(captured), 1)
375 etype, evalue, tb = captured[0]
376 self.assertIn("recursion", str(evalue))
377
378 records = ip.InteractiveTB.get_records(tb, 3, ip.InteractiveTB.tb_offset)
379 for r in records[:10]:
380 print(r[1:4])
381
382 # The outermost frames should be:
383 # 0: the 'cell' that was running when the exception came up
384 # 1: r3o2()
385 # 2: r3o1()
386 # 3: r3a()
387 # Then repeating r3b, r3c, r3a
388 last_unique, repeat_length = find_recursion(etype, evalue, records)
389 self.assertEqual(last_unique, 2)
390 self.assertEqual(repeat_length, 3)
391
392 366
393 367 #----------------------------------------------------------------------------
394 368
395 369 # module testing (minimal)
396 370 def test_handlers():
397 371 def spam(c, d_e):
398 372 (d, e) = d_e
399 373 x = c + d
400 374 y = c * d
401 375 foo(x, y)
402 376
403 377 def foo(a, b, bar=1):
404 378 eggs(a, b + bar)
405 379
406 380 def eggs(f, g, z=globals()):
407 381 h = f + g
408 382 i = f - g
409 383 return h / i
410 384
411 385 buff = io.StringIO()
412 386
413 387 buff.write('')
414 388 buff.write('*** Before ***')
415 389 try:
416 390 buff.write(spam(1, (2, 3)))
417 391 except:
418 392 traceback.print_exc(file=buff)
419 393
420 394 handler = ColorTB(ostream=buff)
421 395 buff.write('*** ColorTB ***')
422 396 try:
423 397 buff.write(spam(1, (2, 3)))
424 398 except:
425 399 handler(*sys.exc_info())
426 400 buff.write('')
427 401
428 402 handler = VerboseTB(ostream=buff)
429 403 buff.write('*** VerboseTB ***')
430 404 try:
431 405 buff.write(spam(1, (2, 3)))
432 406 except:
433 407 handler(*sys.exc_info())
434 408 buff.write('')
435
436 from IPython.testing.decorators import skipif
437
438 class TokenizeFailureTest(unittest.TestCase):
439 """Tests related to https://github.com/ipython/ipython/issues/6864."""
440
441 # that appear to test that we are handling an exception that can be thrown
442 # by the tokenizer due to a bug that seem to have been fixed in 3.8, though
443 # I'm unsure if other sequences can make it raise this error. Let's just
444 # skip in 3.8 for now
445 @skipif(sys.version_info > (3,8))
446 def testLogging(self):
447 message = "An unexpected error occurred while tokenizing input"
448 cell = 'raise ValueError("""a\nb""")'
449
450 stream = io.StringIO()
451 handler = logging.StreamHandler(stream)
452 logger = logging.getLogger()
453 loglevel = logger.level
454 logger.addHandler(handler)
455 self.addCleanup(lambda: logger.removeHandler(handler))
456 self.addCleanup(lambda: logger.setLevel(loglevel))
457
458 logger.setLevel(logging.INFO)
459 with tt.AssertNotPrints(message):
460 ip.run_cell(cell)
461 self.assertNotIn(message, stream.getvalue())
462
463 logger.setLevel(logging.DEBUG)
464 with tt.AssertNotPrints(message):
465 ip.run_cell(cell)
466 self.assertIn(message, stream.getvalue())
This diff has been collapsed as it changes many lines, (523 lines changed) Show them Hide them
@@ -1,1503 +1,1060 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 Verbose and colourful traceback formatting.
4 4
5 5 **ColorTB**
6 6
7 7 I've always found it a bit hard to visually parse tracebacks in Python. The
8 8 ColorTB class is a solution to that problem. It colors the different parts of a
9 9 traceback in a manner similar to what you would expect from a syntax-highlighting
10 10 text editor.
11 11
12 12 Installation instructions for ColorTB::
13 13
14 14 import sys,ultratb
15 15 sys.excepthook = ultratb.ColorTB()
16 16
17 17 **VerboseTB**
18 18
19 19 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
20 20 of useful info when a traceback occurs. Ping originally had it spit out HTML
21 21 and intended it for CGI programmers, but why should they have all the fun? I
22 22 altered it to spit out colored text to the terminal. It's a bit overwhelming,
23 23 but kind of neat, and maybe useful for long-running programs that you believe
24 24 are bug-free. If a crash *does* occur in that type of program you want details.
25 25 Give it a shot--you'll love it or you'll hate it.
26 26
27 27 .. note::
28 28
29 29 The Verbose mode prints the variables currently visible where the exception
30 30 happened (shortening their strings if too long). This can potentially be
31 31 very slow, if you happen to have a huge data structure whose string
32 32 representation is complex to compute. Your computer may appear to freeze for
33 33 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
34 34 with Ctrl-C (maybe hitting it more than once).
35 35
36 36 If you encounter this kind of situation often, you may want to use the
37 37 Verbose_novars mode instead of the regular Verbose, which avoids formatting
38 38 variables (but otherwise includes the information and context given by
39 39 Verbose).
40 40
41 41 .. note::
42 42
43 43 The verbose mode print all variables in the stack, which means it can
44 44 potentially leak sensitive information like access keys, or unencrypted
45 45 password.
46 46
47 47 Installation instructions for VerboseTB::
48 48
49 49 import sys,ultratb
50 50 sys.excepthook = ultratb.VerboseTB()
51 51
52 52 Note: Much of the code in this module was lifted verbatim from the standard
53 53 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
54 54
55 55 Color schemes
56 56 -------------
57 57
58 58 The colors are defined in the class TBTools through the use of the
59 59 ColorSchemeTable class. Currently the following exist:
60 60
61 61 - NoColor: allows all of this module to be used in any terminal (the color
62 62 escapes are just dummy blank strings).
63 63
64 64 - Linux: is meant to look good in a terminal like the Linux console (black
65 65 or very dark background).
66 66
67 67 - LightBG: similar to Linux but swaps dark/light colors to be more readable
68 68 in light background terminals.
69 69
70 70 - Neutral: a neutral color scheme that should be readable on both light and
71 71 dark background
72 72
73 73 You can implement other color schemes easily, the syntax is fairly
74 74 self-explanatory. Please send back new schemes you develop to the author for
75 75 possible inclusion in future releases.
76 76
77 77 Inheritance diagram:
78 78
79 79 .. inheritance-diagram:: IPython.core.ultratb
80 80 :parts: 3
81 81 """
82 82
83 83 #*****************************************************************************
84 84 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
85 85 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
86 86 #
87 87 # Distributed under the terms of the BSD License. The full license is in
88 88 # the file COPYING, distributed as part of this software.
89 89 #*****************************************************************************
90 90
91 91
92 import dis
93 92 import inspect
94 import keyword
95 93 import linecache
96 import os
97 94 import pydoc
98 import re
99 95 import sys
100 96 import time
101 import tokenize
102 97 import traceback
103 98
104 from tokenize import generate_tokens
105
106 # For purposes of monkeypatching inspect to fix a bug in it.
107 from inspect import getsourcefile, getfile, getmodule, \
108 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
99 import stack_data
109 100
110 101 # IPython's own modules
111 102 from IPython import get_ipython
112 103 from IPython.core import debugger
113 104 from IPython.core.display_trap import DisplayTrap
114 105 from IPython.core.excolors import exception_colors
115 106 from IPython.utils import PyColorize
116 107 from IPython.utils import path as util_path
117 108 from IPython.utils import py3compat
118 from IPython.utils.data import uniq_stable
119 109 from IPython.utils.terminal import get_terminal_size
120 110
121 from logging import info, error, debug
122
123 from importlib.util import source_from_cache
124
125 111 import IPython.utils.colorable as colorable
126 112
127 113 # Globals
128 114 # amount of space to put line numbers before verbose tracebacks
129 115 INDENT_SIZE = 8
130 116
131 117 # Default color scheme. This is used, for example, by the traceback
132 118 # formatter. When running in an actual IPython instance, the user's rc.colors
133 119 # value is used, but having a module global makes this functionality available
134 120 # to users of ultratb who are NOT running inside ipython.
135 121 DEFAULT_SCHEME = 'NoColor'
136 122
137
138 # Number of frame above which we are likely to have a recursion and will
139 # **attempt** to detect it. Made modifiable mostly to speedup test suite
140 # as detecting recursion is one of our slowest test
141 _FRAME_RECURSION_LIMIT = 500
142
143 123 # ---------------------------------------------------------------------------
144 124 # Code begins
145 125
146 # Utility functions
147 def inspect_error():
148 """Print a message about internal inspect errors.
149
150 These are unfortunately quite common."""
151
152 error('Internal Python error in the inspect module.\n'
153 'Below is the traceback from this internal error.\n')
154
155
156 # This function is a monkeypatch we apply to the Python inspect module. We have
157 # now found when it's needed (see discussion on issue gh-1456), and we have a
158 # test case (IPython.core.tests.test_ultratb.ChangedPyFileTest) that fails if
159 # the monkeypatch is not applied. TK, Aug 2012.
160 def findsource(object):
161 """Return the entire source file and starting line number for an object.
162
163 The argument may be a module, class, method, function, traceback, frame,
164 or code object. The source code is returned as a list of all the lines
165 in the file and the line number indexes a line in that list. An IOError
166 is raised if the source code cannot be retrieved.
167
168 FIXED version with which we monkeypatch the stdlib to work around a bug."""
169
170 file = getsourcefile(object) or getfile(object)
171 # If the object is a frame, then trying to get the globals dict from its
172 # module won't work. Instead, the frame object itself has the globals
173 # dictionary.
174 globals_dict = None
175 if inspect.isframe(object):
176 # XXX: can this ever be false?
177 globals_dict = object.f_globals
178 else:
179 module = getmodule(object, file)
180 if module:
181 globals_dict = module.__dict__
182 lines = linecache.getlines(file, globals_dict)
183 if not lines:
184 raise IOError('could not get source code')
185
186 if ismodule(object):
187 return lines, 0
188
189 if isclass(object):
190 name = object.__name__
191 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
192 # make some effort to find the best matching class definition:
193 # use the one with the least indentation, which is the one
194 # that's most probably not inside a function definition.
195 candidates = []
196 for i, line in enumerate(lines):
197 match = pat.match(line)
198 if match:
199 # if it's at toplevel, it's already the best one
200 if line[0] == 'c':
201 return lines, i
202 # else add whitespace to candidate list
203 candidates.append((match.group(1), i))
204 if candidates:
205 # this will sort by whitespace, and by line number,
206 # less whitespace first
207 candidates.sort()
208 return lines, candidates[0][1]
209 else:
210 raise IOError('could not find class definition')
211
212 if ismethod(object):
213 object = object.__func__
214 if isfunction(object):
215 object = object.__code__
216 if istraceback(object):
217 object = object.tb_frame
218 if isframe(object):
219 object = object.f_code
220 if iscode(object):
221 if not hasattr(object, 'co_firstlineno'):
222 raise IOError('could not find function definition')
223 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
224 pmatch = pat.match
225 # fperez - fix: sometimes, co_firstlineno can give a number larger than
226 # the length of lines, which causes an error. Safeguard against that.
227 lnum = min(object.co_firstlineno, len(lines)) - 1
228 while lnum > 0:
229 if pmatch(lines[lnum]):
230 break
231 lnum -= 1
232
233 return lines, lnum
234 raise IOError('could not find code object')
235
236
237 # This is a patched version of inspect.getargs that applies the (unmerged)
238 # patch for http://bugs.python.org/issue14611 by Stefano Taschini. This fixes
239 # https://github.com/ipython/ipython/issues/8205 and
240 # https://github.com/ipython/ipython/issues/8293
241 def getargs(co):
242 """Get information about the arguments accepted by a code object.
243
244 Three things are returned: (args, varargs, varkw), where 'args' is
245 a list of argument names (possibly containing nested lists), and
246 'varargs' and 'varkw' are the names of the * and ** arguments or None."""
247 if not iscode(co):
248 raise TypeError('{!r} is not a code object'.format(co))
249
250 nargs = co.co_argcount
251 names = co.co_varnames
252 args = list(names[:nargs])
253 step = 0
254
255 # The following acrobatics are for anonymous (tuple) arguments.
256 for i in range(nargs):
257 if args[i][:1] in ('', '.'):
258 stack, remain, count = [], [], []
259 while step < len(co.co_code):
260 op = ord(co.co_code[step])
261 step = step + 1
262 if op >= dis.HAVE_ARGUMENT:
263 opname = dis.opname[op]
264 value = ord(co.co_code[step]) + ord(co.co_code[step+1])*256
265 step = step + 2
266 if opname in ('UNPACK_TUPLE', 'UNPACK_SEQUENCE'):
267 remain.append(value)
268 count.append(value)
269 elif opname in ('STORE_FAST', 'STORE_DEREF'):
270 if op in dis.haslocal:
271 stack.append(co.co_varnames[value])
272 elif op in dis.hasfree:
273 stack.append((co.co_cellvars + co.co_freevars)[value])
274 # Special case for sublists of length 1: def foo((bar))
275 # doesn't generate the UNPACK_TUPLE bytecode, so if
276 # `remain` is empty here, we have such a sublist.
277 if not remain:
278 stack[0] = [stack[0]]
279 break
280 else:
281 remain[-1] = remain[-1] - 1
282 while remain[-1] == 0:
283 remain.pop()
284 size = count.pop()
285 stack[-size:] = [stack[-size:]]
286 if not remain:
287 break
288 remain[-1] = remain[-1] - 1
289 if not remain:
290 break
291 args[i] = stack[0]
292
293 varargs = None
294 if co.co_flags & inspect.CO_VARARGS:
295 varargs = co.co_varnames[nargs]
296 nargs = nargs + 1
297 varkw = None
298 if co.co_flags & inspect.CO_VARKEYWORDS:
299 varkw = co.co_varnames[nargs]
300 return inspect.Arguments(args, varargs, varkw)
301
302
303 # Monkeypatch inspect to apply our bugfix.
304 def with_patch_inspect(f):
305 """
306 Deprecated since IPython 6.0
307 decorator for monkeypatching inspect.findsource
308 """
309
310 def wrapped(*args, **kwargs):
311 save_findsource = inspect.findsource
312 save_getargs = inspect.getargs
313 inspect.findsource = findsource
314 inspect.getargs = getargs
315 try:
316 return f(*args, **kwargs)
317 finally:
318 inspect.findsource = save_findsource
319 inspect.getargs = save_getargs
320
321 return wrapped
322
323
324 def fix_frame_records_filenames(records):
325 """Try to fix the filenames in each record from inspect.getinnerframes().
326
327 Particularly, modules loaded from within zip files have useless filenames
328 attached to their code object, and inspect.getinnerframes() just uses it.
329 """
330 fixed_records = []
331 for frame, filename, line_no, func_name, lines, index in records:
332 # Look inside the frame's globals dictionary for __file__,
333 # which should be better. However, keep Cython filenames since
334 # we prefer the source filenames over the compiled .so file.
335 if not filename.endswith(('.pyx', '.pxd', '.pxi')):
336 better_fn = frame.f_globals.get('__file__', None)
337 if isinstance(better_fn, str):
338 # Check the type just in case someone did something weird with
339 # __file__. It might also be None if the error occurred during
340 # import.
341 filename = better_fn
342 fixed_records.append((frame, filename, line_no, func_name, lines, index))
343 return fixed_records
344
345
346 @with_patch_inspect
347 def _fixed_getinnerframes(etb, context=1, tb_offset=0):
348 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
349
350 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
351 # If the error is at the console, don't build any context, since it would
352 # otherwise produce 5 blank lines printed out (there is no file at the
353 # console)
354 rec_check = records[tb_offset:]
355 try:
356 rname = rec_check[0][1]
357 if rname == '<ipython console>' or rname.endswith('<string>'):
358 return rec_check
359 except IndexError:
360 pass
361
362 aux = traceback.extract_tb(etb)
363 assert len(records) == len(aux)
364 for i, (file, lnum, _, _) in enumerate(aux):
365 maybeStart = lnum - 1 - context // 2
366 start = max(maybeStart, 0)
367 end = start + context
368 lines = linecache.getlines(file)[start:end]
369 buf = list(records[i])
370 buf[LNUM_POS] = lnum
371 buf[INDEX_POS] = lnum - 1 - start
372 buf[LINES_POS] = lines
373 records[i] = tuple(buf)
374 return records[tb_offset:]
375
376 126 # Helper function -- largely belongs to VerboseTB, but we need the same
377 127 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
378 128 # can be recognized properly by ipython.el's py-traceback-line-re
379 129 # (SyntaxErrors have to be treated specially because they have no traceback)
380 130
381 131
382 def _format_traceback_lines(lnum, index, lines, Colors, lvals, _line_format):
132 def _format_traceback_lines(lines, Colors, lvals, _line_format):
383 133 """
384 134 Format tracebacks lines with pointing arrow, leading numbers...
385 135
386 136 Parameters
387 137 ==========
388 138
389 lnum: int
390 index: int
391 lines: list[string]
139 lines: list[Line]
392 140 Colors:
393 141 ColorScheme used.
394 lvals: bytes
142 lvals: str
395 143 Values of local variables, already colored, to inject just after the error line.
396 144 _line_format: f (str) -> (str, bool)
397 145 return (colorized version of str, failure to do so)
398 146 """
399 147 numbers_width = INDENT_SIZE - 1
400 148 res = []
401 149
402 for i,line in enumerate(lines, lnum-index):
403 line = py3compat.cast_unicode(line)
150 for stack_line in lines:
151 if stack_line is stack_data.LINE_GAP:
152 res.append('%s (...)%s\n' % (Colors.linenoEm, Colors.Normal))
153 continue
154
155 line = stack_line.text.rstrip('\n') + '\n'
404 156
405 157 new_line, err = _line_format(line, 'str')
406 158 if not err:
407 159 line = new_line
408 160
409 if i == lnum:
161 lineno = stack_line.lineno
162 if stack_line.is_current:
410 163 # This is the line with the error
411 pad = numbers_width - len(str(i))
412 num = '%s%s' % (debugger.make_arrow(pad), str(lnum))
164 pad = numbers_width - len(str(lineno))
165 num = '%s%s' % (debugger.make_arrow(pad), str(lineno))
413 166 line = '%s%s%s %s%s' % (Colors.linenoEm, num,
414 167 Colors.line, line, Colors.Normal)
415 168 else:
416 num = '%*s' % (numbers_width, i)
169 num = '%*s' % (numbers_width, lineno)
417 170 line = '%s%s%s %s' % (Colors.lineno, num,
418 171 Colors.Normal, line)
419 172
420 173 res.append(line)
421 if lvals and i == lnum:
174 if lvals and stack_line.is_current:
422 175 res.append(lvals + '\n')
423 176 return res
424 177
425 def is_recursion_error(etype, value, records):
426 try:
427 # RecursionError is new in Python 3.5
428 recursion_error_type = RecursionError
429 except NameError:
430 recursion_error_type = RuntimeError
431
432 # The default recursion limit is 1000, but some of that will be taken up
433 # by stack frames in IPython itself. >500 frames probably indicates
434 # a recursion error.
435 return (etype is recursion_error_type) \
436 and "recursion" in str(value).lower() \
437 and len(records) > _FRAME_RECURSION_LIMIT
438
439 def find_recursion(etype, value, records):
440 """Identify the repeating stack frames from a RecursionError traceback
441
442 'records' is a list as returned by VerboseTB.get_records()
443
444 Returns (last_unique, repeat_length)
445 """
446 # This involves a bit of guesswork - we want to show enough of the traceback
447 # to indicate where the recursion is occurring. We guess that the innermost
448 # quarter of the traceback (250 frames by default) is repeats, and find the
449 # first frame (from in to out) that looks different.
450 if not is_recursion_error(etype, value, records):
451 return len(records), 0
452
453 # Select filename, lineno, func_name to track frames with
454 records = [r[1:4] for r in records]
455 inner_frames = records[-(len(records)//4):]
456 frames_repeated = set(inner_frames)
457
458 last_seen_at = {}
459 longest_repeat = 0
460 i = len(records)
461 for frame in reversed(records):
462 i -= 1
463 if frame not in frames_repeated:
464 last_unique = i
465 break
466
467 if frame in last_seen_at:
468 distance = last_seen_at[frame] - i
469 longest_repeat = max(longest_repeat, distance)
470
471 last_seen_at[frame] = i
472 else:
473 last_unique = 0 # The whole traceback was recursion
474
475 return last_unique, longest_repeat
476 178
477 179 #---------------------------------------------------------------------------
478 180 # Module classes
479 181 class TBTools(colorable.Colorable):
480 182 """Basic tools used by all traceback printer classes."""
481 183
482 184 # Number of frames to skip when reporting tracebacks
483 185 tb_offset = 0
484 186
485 187 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=None, config=None):
486 188 # Whether to call the interactive pdb debugger after printing
487 189 # tracebacks or not
488 190 super(TBTools, self).__init__(parent=parent, config=config)
489 191 self.call_pdb = call_pdb
490 192
491 193 # Output stream to write to. Note that we store the original value in
492 194 # a private attribute and then make the public ostream a property, so
493 195 # that we can delay accessing sys.stdout until runtime. The way
494 196 # things are written now, the sys.stdout object is dynamically managed
495 197 # so a reference to it should NEVER be stored statically. This
496 198 # property approach confines this detail to a single location, and all
497 199 # subclasses can simply access self.ostream for writing.
498 200 self._ostream = ostream
499 201
500 202 # Create color table
501 203 self.color_scheme_table = exception_colors()
502 204
503 205 self.set_colors(color_scheme)
504 206 self.old_scheme = color_scheme # save initial value for toggles
505 207
506 208 if call_pdb:
507 209 self.pdb = debugger.Pdb()
508 210 else:
509 211 self.pdb = None
510 212
511 213 def _get_ostream(self):
512 214 """Output stream that exceptions are written to.
513 215
514 216 Valid values are:
515 217
516 218 - None: the default, which means that IPython will dynamically resolve
517 219 to sys.stdout. This ensures compatibility with most tools, including
518 220 Windows (where plain stdout doesn't recognize ANSI escapes).
519 221
520 222 - Any object with 'write' and 'flush' attributes.
521 223 """
522 224 return sys.stdout if self._ostream is None else self._ostream
523 225
524 226 def _set_ostream(self, val):
525 227 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
526 228 self._ostream = val
527 229
528 230 ostream = property(_get_ostream, _set_ostream)
529 231
530 232 def get_parts_of_chained_exception(self, evalue):
531 233 def get_chained_exception(exception_value):
532 234 cause = getattr(exception_value, '__cause__', None)
533 235 if cause:
534 236 return cause
535 237 if getattr(exception_value, '__suppress_context__', False):
536 238 return None
537 239 return getattr(exception_value, '__context__', None)
538 240
539 241 chained_evalue = get_chained_exception(evalue)
540 242
541 243 if chained_evalue:
542 244 return chained_evalue.__class__, chained_evalue, chained_evalue.__traceback__
543 245
544 246 def prepare_chained_exception_message(self, cause):
545 247 direct_cause = "\nThe above exception was the direct cause of the following exception:\n"
546 248 exception_during_handling = "\nDuring handling of the above exception, another exception occurred:\n"
547 249
548 250 if cause:
549 251 message = [[direct_cause]]
550 252 else:
551 253 message = [[exception_during_handling]]
552 254 return message
553 255
554 256 def set_colors(self, *args, **kw):
555 257 """Shorthand access to the color table scheme selector method."""
556 258
557 259 # Set own color table
558 260 self.color_scheme_table.set_active_scheme(*args, **kw)
559 261 # for convenience, set Colors to the active scheme
560 262 self.Colors = self.color_scheme_table.active_colors
561 263 # Also set colors of debugger
562 264 if hasattr(self, 'pdb') and self.pdb is not None:
563 265 self.pdb.set_colors(*args, **kw)
564 266
565 267 def color_toggle(self):
566 268 """Toggle between the currently active color scheme and NoColor."""
567 269
568 270 if self.color_scheme_table.active_scheme_name == 'NoColor':
569 271 self.color_scheme_table.set_active_scheme(self.old_scheme)
570 272 self.Colors = self.color_scheme_table.active_colors
571 273 else:
572 274 self.old_scheme = self.color_scheme_table.active_scheme_name
573 275 self.color_scheme_table.set_active_scheme('NoColor')
574 276 self.Colors = self.color_scheme_table.active_colors
575 277
576 278 def stb2text(self, stb):
577 279 """Convert a structured traceback (a list) to a string."""
578 280 return '\n'.join(stb)
579 281
580 282 def text(self, etype, value, tb, tb_offset=None, context=5):
581 283 """Return formatted traceback.
582 284
583 285 Subclasses may override this if they add extra arguments.
584 286 """
585 287 tb_list = self.structured_traceback(etype, value, tb,
586 288 tb_offset, context)
587 289 return self.stb2text(tb_list)
588 290
589 291 def structured_traceback(self, etype, evalue, tb, tb_offset=None,
590 292 context=5, mode=None):
591 293 """Return a list of traceback frames.
592 294
593 295 Must be implemented by each class.
594 296 """
595 297 raise NotImplementedError()
596 298
597 299
598 300 #---------------------------------------------------------------------------
599 301 class ListTB(TBTools):
600 302 """Print traceback information from a traceback list, with optional color.
601 303
602 304 Calling requires 3 arguments: (etype, evalue, elist)
603 305 as would be obtained by::
604 306
605 307 etype, evalue, tb = sys.exc_info()
606 308 if tb:
607 309 elist = traceback.extract_tb(tb)
608 310 else:
609 311 elist = None
610 312
611 313 It can thus be used by programs which need to process the traceback before
612 314 printing (such as console replacements based on the code module from the
613 315 standard library).
614 316
615 317 Because they are meant to be called without a full traceback (only a
616 318 list), instances of this class can't call the interactive pdb debugger."""
617 319
618 320 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=None, config=None):
619 321 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
620 322 ostream=ostream, parent=parent,config=config)
621 323
622 324 def __call__(self, etype, value, elist):
623 325 self.ostream.flush()
624 326 self.ostream.write(self.text(etype, value, elist))
625 327 self.ostream.write('\n')
626 328
627 329 def _extract_tb(self, tb):
628 330 if tb:
629 331 return traceback.extract_tb(tb)
630 332 else:
631 333 return None
632 334
633 335 def structured_traceback(self, etype, evalue, etb=None, tb_offset=None,
634 336 context=5):
635 337 """Return a color formatted string with the traceback info.
636 338
637 339 Parameters
638 340 ----------
639 341 etype : exception type
640 342 Type of the exception raised.
641 343
642 344 evalue : object
643 345 Data stored in the exception
644 346
645 347 etb : object
646 348 If list: List of frames, see class docstring for details.
647 349 If Traceback: Traceback of the exception.
648 350
649 351 tb_offset : int, optional
650 352 Number of frames in the traceback to skip. If not given, the
651 353 instance evalue is used (set in constructor).
652 354
653 355 context : int, optional
654 356 Number of lines of context information to print.
655 357
656 358 Returns
657 359 -------
658 360 String with formatted exception.
659 361 """
660 362 # This is a workaround to get chained_exc_ids in recursive calls
661 363 # etb should not be a tuple if structured_traceback is not recursive
662 364 if isinstance(etb, tuple):
663 365 etb, chained_exc_ids = etb
664 366 else:
665 367 chained_exc_ids = set()
666 368
667 369 if isinstance(etb, list):
668 370 elist = etb
669 371 elif etb is not None:
670 372 elist = self._extract_tb(etb)
671 373 else:
672 374 elist = []
673 375 tb_offset = self.tb_offset if tb_offset is None else tb_offset
674 376 Colors = self.Colors
675 377 out_list = []
676 378 if elist:
677 379
678 380 if tb_offset and len(elist) > tb_offset:
679 381 elist = elist[tb_offset:]
680 382
681 383 out_list.append('Traceback %s(most recent call last)%s:' %
682 384 (Colors.normalEm, Colors.Normal) + '\n')
683 385 out_list.extend(self._format_list(elist))
684 386 # The exception info should be a single entry in the list.
685 387 lines = ''.join(self._format_exception_only(etype, evalue))
686 388 out_list.append(lines)
687 389
688 390 exception = self.get_parts_of_chained_exception(evalue)
689 391
690 392 if exception and not id(exception[1]) in chained_exc_ids:
691 393 chained_exception_message = self.prepare_chained_exception_message(
692 394 evalue.__cause__)[0]
693 395 etype, evalue, etb = exception
694 396 # Trace exception to avoid infinite 'cause' loop
695 397 chained_exc_ids.add(id(exception[1]))
696 398 chained_exceptions_tb_offset = 0
697 399 out_list = (
698 400 self.structured_traceback(
699 401 etype, evalue, (etb, chained_exc_ids),
700 402 chained_exceptions_tb_offset, context)
701 403 + chained_exception_message
702 404 + out_list)
703 405
704 406 return out_list
705 407
706 408 def _format_list(self, extracted_list):
707 409 """Format a list of traceback entry tuples for printing.
708 410
709 411 Given a list of tuples as returned by extract_tb() or
710 412 extract_stack(), return a list of strings ready for printing.
711 413 Each string in the resulting list corresponds to the item with the
712 414 same index in the argument list. Each string ends in a newline;
713 415 the strings may contain internal newlines as well, for those items
714 416 whose source text line is not None.
715 417
716 418 Lifted almost verbatim from traceback.py
717 419 """
718 420
719 421 Colors = self.Colors
720 422 list = []
721 423 for filename, lineno, name, line in extracted_list[:-1]:
722 424 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
723 425 (Colors.filename, filename, Colors.Normal,
724 426 Colors.lineno, lineno, Colors.Normal,
725 427 Colors.name, name, Colors.Normal)
726 428 if line:
727 429 item += ' %s\n' % line.strip()
728 430 list.append(item)
729 431 # Emphasize the last entry
730 432 filename, lineno, name, line = extracted_list[-1]
731 433 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
732 434 (Colors.normalEm,
733 435 Colors.filenameEm, filename, Colors.normalEm,
734 436 Colors.linenoEm, lineno, Colors.normalEm,
735 437 Colors.nameEm, name, Colors.normalEm,
736 438 Colors.Normal)
737 439 if line:
738 440 item += '%s %s%s\n' % (Colors.line, line.strip(),
739 441 Colors.Normal)
740 442 list.append(item)
741 443 return list
742 444
743 445 def _format_exception_only(self, etype, value):
744 446 """Format the exception part of a traceback.
745 447
746 448 The arguments are the exception type and value such as given by
747 449 sys.exc_info()[:2]. The return value is a list of strings, each ending
748 450 in a newline. Normally, the list contains a single string; however,
749 451 for SyntaxError exceptions, it contains several lines that (when
750 452 printed) display detailed information about where the syntax error
751 453 occurred. The message indicating which exception occurred is the
752 454 always last string in the list.
753 455
754 456 Also lifted nearly verbatim from traceback.py
755 457 """
756 458 have_filedata = False
757 459 Colors = self.Colors
758 460 list = []
759 461 stype = py3compat.cast_unicode(Colors.excName + etype.__name__ + Colors.Normal)
760 462 if value is None:
761 463 # Not sure if this can still happen in Python 2.6 and above
762 464 list.append(stype + '\n')
763 465 else:
764 466 if issubclass(etype, SyntaxError):
765 467 have_filedata = True
766 468 if not value.filename: value.filename = "<string>"
767 469 if value.lineno:
768 470 lineno = value.lineno
769 471 textline = linecache.getline(value.filename, value.lineno)
770 472 else:
771 473 lineno = 'unknown'
772 474 textline = ''
773 475 list.append('%s File %s"%s"%s, line %s%s%s\n' % \
774 476 (Colors.normalEm,
775 477 Colors.filenameEm, py3compat.cast_unicode(value.filename), Colors.normalEm,
776 478 Colors.linenoEm, lineno, Colors.Normal ))
777 479 if textline == '':
778 480 textline = py3compat.cast_unicode(value.text, "utf-8")
779 481
780 482 if textline is not None:
781 483 i = 0
782 484 while i < len(textline) and textline[i].isspace():
783 485 i += 1
784 486 list.append('%s %s%s\n' % (Colors.line,
785 487 textline.strip(),
786 488 Colors.Normal))
787 489 if value.offset is not None:
788 490 s = ' '
789 491 for c in textline[i:value.offset - 1]:
790 492 if c.isspace():
791 493 s += c
792 494 else:
793 495 s += ' '
794 496 list.append('%s%s^%s\n' % (Colors.caret, s,
795 497 Colors.Normal))
796 498
797 499 try:
798 500 s = value.msg
799 501 except Exception:
800 502 s = self._some_str(value)
801 503 if s:
802 504 list.append('%s%s:%s %s\n' % (stype, Colors.excName,
803 505 Colors.Normal, s))
804 506 else:
805 507 list.append('%s\n' % stype)
806 508
807 509 # sync with user hooks
808 510 if have_filedata:
809 511 ipinst = get_ipython()
810 512 if ipinst is not None:
811 513 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
812 514
813 515 return list
814 516
815 517 def get_exception_only(self, etype, value):
816 518 """Only print the exception type and message, without a traceback.
817 519
818 520 Parameters
819 521 ----------
820 522 etype : exception type
821 523 value : exception value
822 524 """
823 525 return ListTB.structured_traceback(self, etype, value)
824 526
825 527 def show_exception_only(self, etype, evalue):
826 528 """Only print the exception type and message, without a traceback.
827 529
828 530 Parameters
829 531 ----------
830 532 etype : exception type
831 533 value : exception value
832 534 """
833 535 # This method needs to use __call__ from *this* class, not the one from
834 536 # a subclass whose signature or behavior may be different
835 537 ostream = self.ostream
836 538 ostream.flush()
837 539 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
838 540 ostream.flush()
839 541
840 542 def _some_str(self, value):
841 543 # Lifted from traceback.py
842 544 try:
843 545 return py3compat.cast_unicode(str(value))
844 546 except:
845 547 return u'<unprintable %s object>' % type(value).__name__
846 548
847 549
848 550 #----------------------------------------------------------------------------
849 551 class VerboseTB(TBTools):
850 552 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
851 553 of HTML. Requires inspect and pydoc. Crazy, man.
852 554
853 555 Modified version which optionally strips the topmost entries from the
854 556 traceback, to be used with alternate interpreters (because their own code
855 557 would appear in the traceback)."""
856 558
857 559 def __init__(self, color_scheme='Linux', call_pdb=False, ostream=None,
858 560 tb_offset=0, long_header=False, include_vars=True,
859 561 check_cache=None, debugger_cls = None,
860 562 parent=None, config=None):
861 563 """Specify traceback offset, headers and color scheme.
862 564
863 565 Define how many frames to drop from the tracebacks. Calling it with
864 566 tb_offset=1 allows use of this handler in interpreters which will have
865 567 their own code at the top of the traceback (VerboseTB will first
866 568 remove that frame before printing the traceback info)."""
867 569 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
868 570 ostream=ostream, parent=parent, config=config)
869 571 self.tb_offset = tb_offset
870 572 self.long_header = long_header
871 573 self.include_vars = include_vars
872 574 # By default we use linecache.checkcache, but the user can provide a
873 575 # different check_cache implementation. This is used by the IPython
874 576 # kernel to provide tracebacks for interactive code that is cached,
875 577 # by a compiler instance that flushes the linecache but preserves its
876 578 # own code cache.
877 579 if check_cache is None:
878 580 check_cache = linecache.checkcache
879 581 self.check_cache = check_cache
880 582
881 583 self.debugger_cls = debugger_cls or debugger.Pdb
882 584
883 def format_records(self, records, last_unique, recursion_repeat):
884 """Format the stack frames of the traceback"""
885 frames = []
886 for r in records[:last_unique+recursion_repeat+1]:
887 #print '*** record:',file,lnum,func,lines,index # dbg
888 frames.append(self.format_record(*r))
889
890 if recursion_repeat:
891 frames.append('... last %d frames repeated, from the frame below ...\n' % recursion_repeat)
892 frames.append(self.format_record(*records[last_unique+recursion_repeat+1]))
893
894 return frames
895
896 def format_record(self, frame, file, lnum, func, lines, index):
585 def format_record(self, frame_info):
897 586 """Format a single stack frame"""
898 587 Colors = self.Colors # just a shorthand + quicker name lookup
899 588 ColorsNormal = Colors.Normal # used a lot
589
590 if isinstance(frame_info, stack_data.RepeatedFrames):
591 return ' %s[... skipping similar frames: %s]%s\n' % (
592 Colors.excName, frame_info.description, ColorsNormal)
593
900 594 col_scheme = self.color_scheme_table.active_scheme_name
901 595 indent = ' ' * INDENT_SIZE
902 596 em_normal = '%s\n%s%s' % (Colors.valEm, indent, ColorsNormal)
903 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
904 597 tpl_link = '%s%%s%s' % (Colors.filenameEm, ColorsNormal)
905 598 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
906 599 ColorsNormal)
907 600 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
908 601 (Colors.vName, Colors.valEm, ColorsNormal)
909 602 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
910 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
911 Colors.vName, ColorsNormal)
912 603 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
913 604
914 if not file:
915 file = '?'
916 elif file.startswith(str("<")) and file.endswith(str(">")):
917 # Not a real filename, no problem...
918 pass
919 elif not os.path.isabs(file):
920 # Try to make the filename absolute by trying all
921 # sys.path entries (which is also what linecache does)
922 for dirname in sys.path:
923 try:
924 fullname = os.path.join(dirname, file)
925 if os.path.isfile(fullname):
926 file = os.path.abspath(fullname)
927 break
928 except Exception:
929 # Just in case that sys.path contains very
930 # strange entries...
931 pass
932
605 file = frame_info.filename
933 606 file = py3compat.cast_unicode(file, util_path.fs_encoding)
934 607 link = tpl_link % util_path.compress_user(file)
935 args, varargs, varkw, locals_ = inspect.getargvalues(frame)
608 args, varargs, varkw, locals_ = inspect.getargvalues(frame_info.frame)
936 609
937 if func == '?':
938 call = ''
939 elif func == '<module>':
610 func = frame_info.executing.code_qualname()
611 if func == '<module>':
940 612 call = tpl_call % (func, '')
941 613 else:
942 614 # Decide whether to include variable details or not
943 615 var_repr = eqrepr if self.include_vars else nullrepr
944 616 try:
945 617 call = tpl_call % (func, inspect.formatargvalues(args,
946 618 varargs, varkw,
947 619 locals_, formatvalue=var_repr))
948 620 except KeyError:
949 621 # This happens in situations like errors inside generator
950 622 # expressions, where local variables are listed in the
951 623 # line, but can't be extracted from the frame. I'm not
952 624 # 100% sure this isn't actually a bug in inspect itself,
953 625 # but since there's no info for us to compute with, the
954 626 # best we can do is report the failure and move on. Here
955 627 # we must *not* call any traceback construction again,
956 628 # because that would mess up use of %debug later on. So we
957 629 # simply report the failure and move on. The only
958 630 # limitation will be that this frame won't have locals
959 631 # listed in the call signature. Quite subtle problem...
960 632 # I can't think of a good way to validate this in a unit
961 633 # test, but running a script consisting of:
962 634 # dict( (k,v.strip()) for (k,v) in range(10) )
963 635 # will illustrate the error, if this exception catch is
964 636 # disabled.
965 637 call = tpl_call_fail % func
966 638
967 # Don't attempt to tokenize binary files.
968 if file.endswith(('.so', '.pyd', '.dll')):
969 return '%s %s\n' % (link, call)
970
971 elif file.endswith(('.pyc', '.pyo')):
972 # Look up the corresponding source file.
973 try:
974 file = source_from_cache(file)
975 except ValueError:
976 # Failed to get the source file for some reason
977 # E.g. https://github.com/ipython/ipython/issues/9486
978 return '%s %s\n' % (link, call)
979
980 def linereader(file=file, lnum=[lnum], getline=linecache.getline):
981 line = getline(file, lnum[0])
982 lnum[0] += 1
983 return line
984
985 # Build the list of names on this line of code where the exception
986 # occurred.
987 try:
988 names = []
989 name_cont = False
990
991 for token_type, token, start, end, line in generate_tokens(linereader):
992 # build composite names
993 if token_type == tokenize.NAME and token not in keyword.kwlist:
994 if name_cont:
995 # Continuation of a dotted name
996 try:
997 names[-1].append(token)
998 except IndexError:
999 names.append([token])
1000 name_cont = False
1001 else:
1002 # Regular new names. We append everything, the caller
1003 # will be responsible for pruning the list later. It's
1004 # very tricky to try to prune as we go, b/c composite
1005 # names can fool us. The pruning at the end is easy
1006 # to do (or the caller can print a list with repeated
1007 # names if so desired.
1008 names.append([token])
1009 elif token == '.':
1010 name_cont = True
1011 elif token_type == tokenize.NEWLINE:
1012 break
1013
1014 except (IndexError, UnicodeDecodeError, SyntaxError):
1015 # signals exit of tokenizer
1016 # SyntaxError can occur if the file is not actually Python
1017 # - see gh-6300
1018 pass
1019 except tokenize.TokenError as msg:
1020 # Tokenizing may fail for various reasons, many of which are
1021 # harmless. (A good example is when the line in question is the
1022 # close of a triple-quoted string, cf gh-6864). We don't want to
1023 # show this to users, but want make it available for debugging
1024 # purposes.
1025 _m = ("An unexpected error occurred while tokenizing input\n"
1026 "The following traceback may be corrupted or invalid\n"
1027 "The error message is: %s\n" % msg)
1028 debug(_m)
1029
1030 # Join composite names (e.g. "dict.fromkeys")
1031 names = ['.'.join(n) for n in names]
1032 # prune names list of duplicates, but keep the right order
1033 unique_names = uniq_stable(names)
1034
1035 # Start loop over vars
1036 639 lvals = ''
1037 640 lvals_list = []
1038 641 if self.include_vars:
1039 for name_full in unique_names:
1040 name_base = name_full.split('.', 1)[0]
1041 if name_base in frame.f_code.co_varnames:
1042 if name_base in locals_:
1043 try:
1044 value = repr(eval(name_full, locals_))
1045 except:
1046 value = undefined
1047 else:
1048 value = undefined
1049 name = tpl_local_var % name_full
1050 else:
1051 if name_base in frame.f_globals:
1052 try:
1053 value = repr(eval(name_full, frame.f_globals))
1054 except:
1055 value = undefined
1056 else:
1057 value = undefined
1058 name = tpl_global_var % name_full
1059 lvals_list.append(tpl_name_val % (name, value))
642 for var in frame_info.variables_in_executing_piece:
643 lvals_list.append(tpl_name_val % (var.name, repr(var.value)))
1060 644 if lvals_list:
1061 645 lvals = '%s%s' % (indent, em_normal.join(lvals_list))
1062 646
1063 level = '%s %s\n' % (link, call)
647 result = '%s %s\n' % (link, call)
1064 648
1065 if index is None:
1066 return level
1067 else:
1068 _line_format = PyColorize.Parser(style=col_scheme, parent=self).format2
1069 return '%s%s' % (level, ''.join(
1070 _format_traceback_lines(lnum, index, lines, Colors, lvals,
1071 _line_format)))
649 _line_format = PyColorize.Parser(style=col_scheme, parent=self).format2
650 result += ''.join(_format_traceback_lines(frame_info.lines, Colors, lvals, _line_format))
651 return result
1072 652
1073 653 def prepare_header(self, etype, long_version=False):
1074 654 colors = self.Colors # just a shorthand + quicker name lookup
1075 655 colorsnormal = colors.Normal # used a lot
1076 656 exc = '%s%s%s' % (colors.excName, etype, colorsnormal)
1077 657 width = min(75, get_terminal_size()[0])
1078 658 if long_version:
1079 659 # Header with the exception type, python version, and date
1080 660 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
1081 661 date = time.ctime(time.time())
1082 662
1083 663 head = '%s%s%s\n%s%s%s\n%s' % (colors.topline, '-' * width, colorsnormal,
1084 664 exc, ' ' * (width - len(str(etype)) - len(pyver)),
1085 665 pyver, date.rjust(width) )
1086 666 head += "\nA problem occurred executing Python code. Here is the sequence of function" \
1087 667 "\ncalls leading up to the error, with the most recent (innermost) call last."
1088 668 else:
1089 669 # Simplified header
1090 670 head = '%s%s' % (exc, 'Traceback (most recent call last)'. \
1091 671 rjust(width - len(str(etype))) )
1092 672
1093 673 return head
1094 674
1095 675 def format_exception(self, etype, evalue):
1096 676 colors = self.Colors # just a shorthand + quicker name lookup
1097 677 colorsnormal = colors.Normal # used a lot
1098 678 # Get (safely) a string form of the exception info
1099 679 try:
1100 680 etype_str, evalue_str = map(str, (etype, evalue))
1101 681 except:
1102 682 # User exception is improperly defined.
1103 683 etype, evalue = str, sys.exc_info()[:2]
1104 684 etype_str, evalue_str = map(str, (etype, evalue))
1105 685 # ... and format it
1106 686 return ['%s%s%s: %s' % (colors.excName, etype_str,
1107 687 colorsnormal, py3compat.cast_unicode(evalue_str))]
1108 688
1109 689 def format_exception_as_a_whole(self, etype, evalue, etb, number_of_lines_of_context, tb_offset):
1110 690 """Formats the header, traceback and exception message for a single exception.
1111 691
1112 692 This may be called multiple times by Python 3 exception chaining
1113 693 (PEP 3134).
1114 694 """
1115 695 # some locals
1116 696 orig_etype = etype
1117 697 try:
1118 698 etype = etype.__name__
1119 699 except AttributeError:
1120 700 pass
1121 701
1122 702 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1123 703 head = self.prepare_header(etype, self.long_header)
1124 704 records = self.get_records(etb, number_of_lines_of_context, tb_offset)
1125 705
1126 if records is None:
1127 return ""
1128
1129 last_unique, recursion_repeat = find_recursion(orig_etype, evalue, records)
1130
1131 frames = self.format_records(records, last_unique, recursion_repeat)
706 frames = list(map(self.format_record, records))
1132 707
1133 708 formatted_exception = self.format_exception(etype, evalue)
1134 709 if records:
1135 filepath, lnum = records[-1][1:3]
1136 filepath = os.path.abspath(filepath)
710 frame_info = records[-1]
1137 711 ipinst = get_ipython()
1138 712 if ipinst is not None:
1139 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
713 ipinst.hooks.synchronize_with_editor(frame_info.filename, frame_info.lineno, 0)
1140 714
1141 715 return [[head] + frames + [''.join(formatted_exception[0])]]
1142 716
1143 717 def get_records(self, etb, number_of_lines_of_context, tb_offset):
1144 try:
1145 # Try the default getinnerframes and Alex's: Alex's fixes some
1146 # problems, but it generates empty tracebacks for console errors
1147 # (5 blanks lines) where none should be returned.
1148 return _fixed_getinnerframes(etb, number_of_lines_of_context, tb_offset)
1149 except UnicodeDecodeError:
1150 # This can occur if a file's encoding magic comment is wrong.
1151 # I can't see a way to recover without duplicating a bunch of code
1152 # from the stdlib traceback module. --TK
1153 error('\nUnicodeDecodeError while processing traceback.\n')
1154 return None
1155 except:
1156 # FIXME: I've been getting many crash reports from python 2.3
1157 # users, traceable to inspect.py. If I can find a small test-case
1158 # to reproduce this, I should either write a better workaround or
1159 # file a bug report against inspect (if that's the real problem).
1160 # So far, I haven't been able to find an isolated example to
1161 # reproduce the problem.
1162 inspect_error()
1163 traceback.print_exc(file=self.ostream)
1164 info('\nUnfortunately, your original traceback can not be constructed.\n')
1165 return None
718 context = number_of_lines_of_context - 1
719 after = context // 2
720 before = context - after
721 options = stack_data.Options(before=before, after=after)
722 return list(stack_data.FrameInfo.stack_data(etb, options=options))[tb_offset:]
1166 723
1167 724 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
1168 725 number_of_lines_of_context=5):
1169 726 """Return a nice text document describing the traceback."""
1170 727
1171 728 formatted_exception = self.format_exception_as_a_whole(etype, evalue, etb, number_of_lines_of_context,
1172 729 tb_offset)
1173 730
1174 731 colors = self.Colors # just a shorthand + quicker name lookup
1175 732 colorsnormal = colors.Normal # used a lot
1176 733 head = '%s%s%s' % (colors.topline, '-' * min(75, get_terminal_size()[0]), colorsnormal)
1177 734 structured_traceback_parts = [head]
1178 735 chained_exceptions_tb_offset = 0
1179 736 lines_of_context = 3
1180 737 formatted_exceptions = formatted_exception
1181 738 exception = self.get_parts_of_chained_exception(evalue)
1182 739 if exception:
1183 740 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
1184 741 etype, evalue, etb = exception
1185 742 else:
1186 743 evalue = None
1187 744 chained_exc_ids = set()
1188 745 while evalue:
1189 746 formatted_exceptions += self.format_exception_as_a_whole(etype, evalue, etb, lines_of_context,
1190 747 chained_exceptions_tb_offset)
1191 748 exception = self.get_parts_of_chained_exception(evalue)
1192 749
1193 750 if exception and not id(exception[1]) in chained_exc_ids:
1194 751 chained_exc_ids.add(id(exception[1])) # trace exception to avoid infinite 'cause' loop
1195 752 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
1196 753 etype, evalue, etb = exception
1197 754 else:
1198 755 evalue = None
1199 756
1200 757 # we want to see exceptions in a reversed order:
1201 758 # the first exception should be on top
1202 759 for formatted_exception in reversed(formatted_exceptions):
1203 760 structured_traceback_parts += formatted_exception
1204 761
1205 762 return structured_traceback_parts
1206 763
1207 764 def debugger(self, force=False):
1208 765 """Call up the pdb debugger if desired, always clean up the tb
1209 766 reference.
1210 767
1211 768 Keywords:
1212 769
1213 770 - force(False): by default, this routine checks the instance call_pdb
1214 771 flag and does not actually invoke the debugger if the flag is false.
1215 772 The 'force' option forces the debugger to activate even if the flag
1216 773 is false.
1217 774
1218 775 If the call_pdb flag is set, the pdb interactive debugger is
1219 776 invoked. In all cases, the self.tb reference to the current traceback
1220 777 is deleted to prevent lingering references which hamper memory
1221 778 management.
1222 779
1223 780 Note that each call to pdb() does an 'import readline', so if your app
1224 781 requires a special setup for the readline completers, you'll have to
1225 782 fix that by hand after invoking the exception handler."""
1226 783
1227 784 if force or self.call_pdb:
1228 785 if self.pdb is None:
1229 786 self.pdb = self.debugger_cls()
1230 787 # the system displayhook may have changed, restore the original
1231 788 # for pdb
1232 789 display_trap = DisplayTrap(hook=sys.__displayhook__)
1233 790 with display_trap:
1234 791 self.pdb.reset()
1235 792 # Find the right frame so we don't pop up inside ipython itself
1236 793 if hasattr(self, 'tb') and self.tb is not None:
1237 794 etb = self.tb
1238 795 else:
1239 796 etb = self.tb = sys.last_traceback
1240 797 while self.tb is not None and self.tb.tb_next is not None:
1241 798 self.tb = self.tb.tb_next
1242 799 if etb and etb.tb_next:
1243 800 etb = etb.tb_next
1244 801 self.pdb.botframe = etb.tb_frame
1245 802 self.pdb.interaction(None, etb)
1246 803
1247 804 if hasattr(self, 'tb'):
1248 805 del self.tb
1249 806
1250 807 def handler(self, info=None):
1251 808 (etype, evalue, etb) = info or sys.exc_info()
1252 809 self.tb = etb
1253 810 ostream = self.ostream
1254 811 ostream.flush()
1255 812 ostream.write(self.text(etype, evalue, etb))
1256 813 ostream.write('\n')
1257 814 ostream.flush()
1258 815
1259 816 # Changed so an instance can just be called as VerboseTB_inst() and print
1260 817 # out the right info on its own.
1261 818 def __call__(self, etype=None, evalue=None, etb=None):
1262 819 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
1263 820 if etb is None:
1264 821 self.handler()
1265 822 else:
1266 823 self.handler((etype, evalue, etb))
1267 824 try:
1268 825 self.debugger()
1269 826 except KeyboardInterrupt:
1270 827 print("\nKeyboardInterrupt")
1271 828
1272 829
1273 830 #----------------------------------------------------------------------------
1274 831 class FormattedTB(VerboseTB, ListTB):
1275 832 """Subclass ListTB but allow calling with a traceback.
1276 833
1277 834 It can thus be used as a sys.excepthook for Python > 2.1.
1278 835
1279 836 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
1280 837
1281 838 Allows a tb_offset to be specified. This is useful for situations where
1282 839 one needs to remove a number of topmost frames from the traceback (such as
1283 840 occurs with python programs that themselves execute other python code,
1284 841 like Python shells). """
1285 842
1286 843 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1287 844 ostream=None,
1288 845 tb_offset=0, long_header=False, include_vars=False,
1289 846 check_cache=None, debugger_cls=None,
1290 847 parent=None, config=None):
1291 848
1292 849 # NEVER change the order of this list. Put new modes at the end:
1293 850 self.valid_modes = ['Plain', 'Context', 'Verbose', 'Minimal']
1294 851 self.verbose_modes = self.valid_modes[1:3]
1295 852
1296 853 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
1297 854 ostream=ostream, tb_offset=tb_offset,
1298 855 long_header=long_header, include_vars=include_vars,
1299 856 check_cache=check_cache, debugger_cls=debugger_cls,
1300 857 parent=parent, config=config)
1301 858
1302 859 # Different types of tracebacks are joined with different separators to
1303 860 # form a single string. They are taken from this dict
1304 861 self._join_chars = dict(Plain='', Context='\n', Verbose='\n',
1305 862 Minimal='')
1306 863 # set_mode also sets the tb_join_char attribute
1307 864 self.set_mode(mode)
1308 865
1309 866 def structured_traceback(self, etype, value, tb, tb_offset=None, number_of_lines_of_context=5):
1310 867 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1311 868 mode = self.mode
1312 869 if mode in self.verbose_modes:
1313 870 # Verbose modes need a full traceback
1314 871 return VerboseTB.structured_traceback(
1315 872 self, etype, value, tb, tb_offset, number_of_lines_of_context
1316 873 )
1317 874 elif mode == 'Minimal':
1318 875 return ListTB.get_exception_only(self, etype, value)
1319 876 else:
1320 877 # We must check the source cache because otherwise we can print
1321 878 # out-of-date source code.
1322 879 self.check_cache()
1323 880 # Now we can extract and format the exception
1324 881 return ListTB.structured_traceback(
1325 882 self, etype, value, tb, tb_offset, number_of_lines_of_context
1326 883 )
1327 884
1328 885 def stb2text(self, stb):
1329 886 """Convert a structured traceback (a list) to a string."""
1330 887 return self.tb_join_char.join(stb)
1331 888
1332 889
1333 890 def set_mode(self, mode=None):
1334 891 """Switch to the desired mode.
1335 892
1336 893 If mode is not specified, cycles through the available modes."""
1337 894
1338 895 if not mode:
1339 896 new_idx = (self.valid_modes.index(self.mode) + 1 ) % \
1340 897 len(self.valid_modes)
1341 898 self.mode = self.valid_modes[new_idx]
1342 899 elif mode not in self.valid_modes:
1343 900 raise ValueError('Unrecognized mode in FormattedTB: <' + mode + '>\n'
1344 901 'Valid modes: ' + str(self.valid_modes))
1345 902 else:
1346 903 self.mode = mode
1347 904 # include variable details only in 'Verbose' mode
1348 905 self.include_vars = (self.mode == self.valid_modes[2])
1349 906 # Set the join character for generating text tracebacks
1350 907 self.tb_join_char = self._join_chars[self.mode]
1351 908
1352 909 # some convenient shortcuts
1353 910 def plain(self):
1354 911 self.set_mode(self.valid_modes[0])
1355 912
1356 913 def context(self):
1357 914 self.set_mode(self.valid_modes[1])
1358 915
1359 916 def verbose(self):
1360 917 self.set_mode(self.valid_modes[2])
1361 918
1362 919 def minimal(self):
1363 920 self.set_mode(self.valid_modes[3])
1364 921
1365 922
1366 923 #----------------------------------------------------------------------------
1367 924 class AutoFormattedTB(FormattedTB):
1368 925 """A traceback printer which can be called on the fly.
1369 926
1370 927 It will find out about exceptions by itself.
1371 928
1372 929 A brief example::
1373 930
1374 931 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1375 932 try:
1376 933 ...
1377 934 except:
1378 935 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1379 936 """
1380 937
1381 938 def __call__(self, etype=None, evalue=None, etb=None,
1382 939 out=None, tb_offset=None):
1383 940 """Print out a formatted exception traceback.
1384 941
1385 942 Optional arguments:
1386 943 - out: an open file-like object to direct output to.
1387 944
1388 945 - tb_offset: the number of frames to skip over in the stack, on a
1389 946 per-call basis (this overrides temporarily the instance's tb_offset
1390 947 given at initialization time. """
1391 948
1392 949 if out is None:
1393 950 out = self.ostream
1394 951 out.flush()
1395 952 out.write(self.text(etype, evalue, etb, tb_offset))
1396 953 out.write('\n')
1397 954 out.flush()
1398 955 # FIXME: we should remove the auto pdb behavior from here and leave
1399 956 # that to the clients.
1400 957 try:
1401 958 self.debugger()
1402 959 except KeyboardInterrupt:
1403 960 print("\nKeyboardInterrupt")
1404 961
1405 962 def structured_traceback(self, etype=None, value=None, tb=None,
1406 963 tb_offset=None, number_of_lines_of_context=5):
1407 964 if etype is None:
1408 965 etype, value, tb = sys.exc_info()
1409 966 if isinstance(tb, tuple):
1410 967 # tb is a tuple if this is a chained exception.
1411 968 self.tb = tb[0]
1412 969 else:
1413 970 self.tb = tb
1414 971 return FormattedTB.structured_traceback(
1415 972 self, etype, value, tb, tb_offset, number_of_lines_of_context)
1416 973
1417 974
1418 975 #---------------------------------------------------------------------------
1419 976
1420 977 # A simple class to preserve Nathan's original functionality.
1421 978 class ColorTB(FormattedTB):
1422 979 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1423 980
1424 981 def __init__(self, color_scheme='Linux', call_pdb=0, **kwargs):
1425 982 FormattedTB.__init__(self, color_scheme=color_scheme,
1426 983 call_pdb=call_pdb, **kwargs)
1427 984
1428 985
1429 986 class SyntaxTB(ListTB):
1430 987 """Extension which holds some state: the last exception value"""
1431 988
1432 989 def __init__(self, color_scheme='NoColor', parent=None, config=None):
1433 990 ListTB.__init__(self, color_scheme, parent=parent, config=config)
1434 991 self.last_syntax_error = None
1435 992
1436 993 def __call__(self, etype, value, elist):
1437 994 self.last_syntax_error = value
1438 995
1439 996 ListTB.__call__(self, etype, value, elist)
1440 997
1441 998 def structured_traceback(self, etype, value, elist, tb_offset=None,
1442 999 context=5):
1443 1000 # If the source file has been edited, the line in the syntax error can
1444 1001 # be wrong (retrieved from an outdated cache). This replaces it with
1445 1002 # the current value.
1446 1003 if isinstance(value, SyntaxError) \
1447 1004 and isinstance(value.filename, str) \
1448 1005 and isinstance(value.lineno, int):
1449 1006 linecache.checkcache(value.filename)
1450 1007 newtext = linecache.getline(value.filename, value.lineno)
1451 1008 if newtext:
1452 1009 value.text = newtext
1453 1010 self.last_syntax_error = value
1454 1011 return super(SyntaxTB, self).structured_traceback(etype, value, elist,
1455 1012 tb_offset=tb_offset, context=context)
1456 1013
1457 1014 def clear_err_state(self):
1458 1015 """Return the current error state and clear it"""
1459 1016 e = self.last_syntax_error
1460 1017 self.last_syntax_error = None
1461 1018 return e
1462 1019
1463 1020 def stb2text(self, stb):
1464 1021 """Convert a structured traceback (a list) to a string."""
1465 1022 return ''.join(stb)
1466 1023
1467 1024
1468 1025 # some internal-use functions
1469 1026 def text_repr(value):
1470 1027 """Hopefully pretty robust repr equivalent."""
1471 1028 # this is pretty horrible but should always return *something*
1472 1029 try:
1473 1030 return pydoc.text.repr(value)
1474 1031 except KeyboardInterrupt:
1475 1032 raise
1476 1033 except:
1477 1034 try:
1478 1035 return repr(value)
1479 1036 except KeyboardInterrupt:
1480 1037 raise
1481 1038 except:
1482 1039 try:
1483 1040 # all still in an except block so we catch
1484 1041 # getattr raising
1485 1042 name = getattr(value, '__name__', None)
1486 1043 if name:
1487 1044 # ick, recursion
1488 1045 return text_repr(name)
1489 1046 klass = getattr(value, '__class__', None)
1490 1047 if klass:
1491 1048 return '%s instance' % text_repr(klass)
1492 1049 except KeyboardInterrupt:
1493 1050 raise
1494 1051 except:
1495 1052 return 'UNRECOVERABLE REPR FAILURE'
1496 1053
1497 1054
1498 1055 def eqrepr(value, repr=text_repr):
1499 1056 return '=%s' % repr(value)
1500 1057
1501 1058
1502 1059 def nullrepr(value, repr=text_repr):
1503 1060 return ''
@@ -1,262 +1,263 b''
1 1 #!/usr/bin/env python3
2 2 # -*- coding: utf-8 -*-
3 3 """Setup script for IPython.
4 4
5 5 Under Posix environments it works like a typical setup.py script.
6 6 Under Windows, the command sdist is not supported, since IPython
7 7 requires utilities which are not available under Windows."""
8 8
9 9 #-----------------------------------------------------------------------------
10 10 # Copyright (c) 2008-2011, IPython Development Team.
11 11 # Copyright (c) 2001-2007, Fernando Perez <fernando.perez@colorado.edu>
12 12 # Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
13 13 # Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
14 14 #
15 15 # Distributed under the terms of the Modified BSD License.
16 16 #
17 17 # The full license is in the file COPYING.rst, distributed with this software.
18 18 #-----------------------------------------------------------------------------
19 19
20 20 from __future__ import print_function
21 21
22 22 import os
23 23 import sys
24 24
25 25 # **Python version check**
26 26 #
27 27 # This check is also made in IPython/__init__, don't forget to update both when
28 28 # changing Python version requirements.
29 29 if sys.version_info < (3, 6):
30 30 pip_message = 'This may be due to an out of date pip. Make sure you have pip >= 9.0.1.'
31 31 try:
32 32 import pip
33 33 pip_version = tuple([int(x) for x in pip.__version__.split('.')[:3]])
34 34 if pip_version < (9, 0, 1) :
35 35 pip_message = 'Your pip version is out of date, please install pip >= 9.0.1. '\
36 36 'pip {} detected.'.format(pip.__version__)
37 37 else:
38 38 # pip is new enough - it must be something else
39 39 pip_message = ''
40 40 except Exception:
41 41 pass
42 42
43 43
44 44 error = """
45 45 IPython 7.10+ supports Python 3.6 and above, following NEP 29.
46 46 When using Python 2.7, please install IPython 5.x LTS Long Term Support version.
47 47 Python 3.3 and 3.4 were supported up to IPython 6.x.
48 48 Python 3.5 was supported with IPython 7.0 to 7.9.
49 49
50 50 See IPython `README.rst` file for more information:
51 51
52 52 https://github.com/ipython/ipython/blob/master/README.rst
53 53
54 54 Python {py} detected.
55 55 {pip}
56 56 """.format(py=sys.version_info, pip=pip_message )
57 57
58 58 print(error, file=sys.stderr)
59 59 sys.exit(1)
60 60
61 61 # At least we're on the python version we need, move on.
62 62
63 63 # BEFORE importing distutils, remove MANIFEST. distutils doesn't properly
64 64 # update it when the contents of directories change.
65 65 if os.path.exists('MANIFEST'): os.remove('MANIFEST')
66 66
67 67 from distutils.core import setup
68 68
69 69 # Our own imports
70 70 from setupbase import target_update
71 71
72 72 from setupbase import (
73 73 setup_args,
74 74 find_packages,
75 75 find_package_data,
76 76 check_package_data_first,
77 77 find_entry_points,
78 78 build_scripts_entrypt,
79 79 find_data_files,
80 80 git_prebuild,
81 81 install_symlinked,
82 82 install_lib_symlink,
83 83 install_scripts_for_symlink,
84 84 unsymlink,
85 85 )
86 86
87 87 isfile = os.path.isfile
88 88 pjoin = os.path.join
89 89
90 90 #-------------------------------------------------------------------------------
91 91 # Handle OS specific things
92 92 #-------------------------------------------------------------------------------
93 93
94 94 if os.name in ('nt','dos'):
95 95 os_name = 'windows'
96 96 else:
97 97 os_name = os.name
98 98
99 99 # Under Windows, 'sdist' has not been supported. Now that the docs build with
100 100 # Sphinx it might work, but let's not turn it on until someone confirms that it
101 101 # actually works.
102 102 if os_name == 'windows' and 'sdist' in sys.argv:
103 103 print('The sdist command is not available under Windows. Exiting.')
104 104 sys.exit(1)
105 105
106 106
107 107 #-------------------------------------------------------------------------------
108 108 # Things related to the IPython documentation
109 109 #-------------------------------------------------------------------------------
110 110
111 111 # update the manuals when building a source dist
112 112 if len(sys.argv) >= 2 and sys.argv[1] in ('sdist','bdist_rpm'):
113 113
114 114 # List of things to be updated. Each entry is a triplet of args for
115 115 # target_update()
116 116 to_update = [
117 117 ('docs/man/ipython.1.gz',
118 118 ['docs/man/ipython.1'],
119 119 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz'),
120 120 ]
121 121
122 122
123 123 [ target_update(*t) for t in to_update ]
124 124
125 125 #---------------------------------------------------------------------------
126 126 # Find all the packages, package data, and data_files
127 127 #---------------------------------------------------------------------------
128 128
129 129 packages = find_packages()
130 130 package_data = find_package_data()
131 131
132 132 data_files = find_data_files()
133 133
134 134 setup_args['packages'] = packages
135 135 setup_args['package_data'] = package_data
136 136 setup_args['data_files'] = data_files
137 137
138 138 #---------------------------------------------------------------------------
139 139 # custom distutils commands
140 140 #---------------------------------------------------------------------------
141 141 # imports here, so they are after setuptools import if there was one
142 142 from distutils.command.sdist import sdist
143 143
144 144 setup_args['cmdclass'] = {
145 145 'build_py': \
146 146 check_package_data_first(git_prebuild('IPython')),
147 147 'sdist' : git_prebuild('IPython', sdist),
148 148 'symlink': install_symlinked,
149 149 'install_lib_symlink': install_lib_symlink,
150 150 'install_scripts_sym': install_scripts_for_symlink,
151 151 'unsymlink': unsymlink,
152 152 }
153 153
154 154
155 155 #---------------------------------------------------------------------------
156 156 # Handle scripts, dependencies, and setuptools specific things
157 157 #---------------------------------------------------------------------------
158 158
159 159 # For some commands, use setuptools. Note that we do NOT list install here!
160 160 # If you want a setuptools-enhanced install, just run 'setupegg.py install'
161 161 needs_setuptools = {'develop', 'release', 'bdist_egg', 'bdist_rpm',
162 162 'bdist', 'bdist_dumb', 'bdist_wininst', 'bdist_wheel',
163 163 'egg_info', 'easy_install', 'upload', 'install_egg_info',
164 164 }
165 165
166 166 if len(needs_setuptools.intersection(sys.argv)) > 0:
167 167 import setuptools
168 168
169 169 # This dict is used for passing extra arguments that are setuptools
170 170 # specific to setup
171 171 setuptools_extra_args = {}
172 172
173 173 # setuptools requirements
174 174
175 175 extras_require = dict(
176 176 parallel = ['ipyparallel'],
177 177 qtconsole = ['qtconsole'],
178 178 doc = ['Sphinx>=1.3'],
179 179 test = ['nose>=0.10.1', 'requests', 'testpath', 'pygments', 'nbformat', 'ipykernel', 'numpy>=1.14'],
180 180 terminal = [],
181 181 kernel = ['ipykernel'],
182 182 nbformat = ['nbformat'],
183 183 notebook = ['notebook', 'ipywidgets'],
184 184 nbconvert = ['nbconvert'],
185 185 )
186 186
187 187 install_requires = [
188 188 'setuptools>=18.5',
189 189 'jedi>=0.10',
190 190 'decorator',
191 191 'pickleshare',
192 192 'traitlets>=4.2',
193 193 'prompt_toolkit>=2.0.0,<3.1.0,!=3.0.0,!=3.0.1',
194 194 'pygments',
195 195 'backcall',
196 'stack_data',
196 197 ]
197 198
198 199 # Platform-specific dependencies:
199 200 # This is the correct way to specify these,
200 201 # but requires pip >= 6. pip < 6 ignores these.
201 202
202 203 extras_require.update({
203 204 ':sys_platform != "win32"': ['pexpect'],
204 205 ':sys_platform == "darwin"': ['appnope'],
205 206 ':sys_platform == "win32"': ['colorama'],
206 207 })
207 208 # FIXME: re-specify above platform dependencies for pip < 6
208 209 # These would result in non-portable bdists.
209 210 if not any(arg.startswith('bdist') for arg in sys.argv):
210 211 if sys.platform == 'darwin':
211 212 install_requires.extend(['appnope'])
212 213
213 214 if not sys.platform.startswith('win'):
214 215 install_requires.append('pexpect')
215 216
216 217 # workaround pypa/setuptools#147, where setuptools misspells
217 218 # platform_python_implementation as python_implementation
218 219 if 'setuptools' in sys.modules:
219 220 for key in list(extras_require):
220 221 if 'platform_python_implementation' in key:
221 222 new_key = key.replace('platform_python_implementation', 'python_implementation')
222 223 extras_require[new_key] = extras_require.pop(key)
223 224
224 225 everything = set()
225 226 for key, deps in extras_require.items():
226 227 if ':' not in key:
227 228 everything.update(deps)
228 229 extras_require['all'] = everything
229 230
230 231 if 'setuptools' in sys.modules:
231 232 setuptools_extra_args['python_requires'] = '>=3.6'
232 233 setuptools_extra_args['zip_safe'] = False
233 234 setuptools_extra_args['entry_points'] = {
234 235 'console_scripts': find_entry_points(),
235 236 'pygments.lexers': [
236 237 'ipythonconsole = IPython.lib.lexers:IPythonConsoleLexer',
237 238 'ipython = IPython.lib.lexers:IPythonLexer',
238 239 'ipython3 = IPython.lib.lexers:IPython3Lexer',
239 240 ],
240 241 }
241 242 setup_args['extras_require'] = extras_require
242 243 setup_args['install_requires'] = install_requires
243 244
244 245 else:
245 246 # scripts has to be a non-empty list, or install_scripts isn't called
246 247 setup_args['scripts'] = [e.split('=')[0].strip() for e in find_entry_points()]
247 248
248 249 setup_args['cmdclass']['build_scripts'] = build_scripts_entrypt
249 250
250 251 #---------------------------------------------------------------------------
251 252 # Do the actual setup now
252 253 #---------------------------------------------------------------------------
253 254
254 255 setup_args.update(setuptools_extra_args)
255 256
256 257
257 258
258 259 def main():
259 260 setup(**setup_args)
260 261
261 262 if __name__ == '__main__':
262 263 main()
General Comments 0
You need to be logged in to leave comments. Login now