##// END OF EJS Templates
Restore option to auto-edit files on syntax error
Thomas Kluyver -
Show More
@@ -1,1484 +1,1485 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 unencryted
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 You can implement other color schemes easily, the syntax is fairly
71 71 self-explanatory. Please send back new schemes you develop to the author for
72 72 possible inclusion in future releases.
73 73
74 74 Inheritance diagram:
75 75
76 76 .. inheritance-diagram:: IPython.core.ultratb
77 77 :parts: 3
78 78 """
79 79
80 80 #*****************************************************************************
81 81 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
82 82 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
83 83 #
84 84 # Distributed under the terms of the BSD License. The full license is in
85 85 # the file COPYING, distributed as part of this software.
86 86 #*****************************************************************************
87 87
88 88 from __future__ import absolute_import
89 89 from __future__ import unicode_literals
90 90 from __future__ import print_function
91 91
92 92 import dis
93 93 import inspect
94 94 import keyword
95 95 import linecache
96 96 import os
97 97 import pydoc
98 98 import re
99 99 import sys
100 100 import time
101 101 import tokenize
102 102 import traceback
103 103 import types
104 104
105 105 try: # Python 2
106 106 generate_tokens = tokenize.generate_tokens
107 107 except AttributeError: # Python 3
108 108 generate_tokens = tokenize.tokenize
109 109
110 110 # For purposes of monkeypatching inspect to fix a bug in it.
111 111 from inspect import getsourcefile, getfile, getmodule, \
112 112 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
113 113
114 114 # IPython's own modules
115 115 # Modified pdb which doesn't damage IPython's readline handling
116 116 from IPython import get_ipython
117 117 from IPython.core import debugger
118 118 from IPython.core.display_trap import DisplayTrap
119 119 from IPython.core.excolors import exception_colors
120 120 from IPython.utils import PyColorize
121 121 from IPython.utils import openpy
122 122 from IPython.utils import path as util_path
123 123 from IPython.utils import py3compat
124 124 from IPython.utils import ulinecache
125 125 from IPython.utils.data import uniq_stable
126 126 from IPython.utils.terminal import get_terminal_size
127 127 from logging import info, error
128 128
129 129 import IPython.utils.colorable as colorable
130 130
131 131 # Globals
132 132 # amount of space to put line numbers before verbose tracebacks
133 133 INDENT_SIZE = 8
134 134
135 135 # Default color scheme. This is used, for example, by the traceback
136 136 # formatter. When running in an actual IPython instance, the user's rc.colors
137 137 # value is used, but having a module global makes this functionality available
138 138 # to users of ultratb who are NOT running inside ipython.
139 139 DEFAULT_SCHEME = 'NoColor'
140 140
141 141 # ---------------------------------------------------------------------------
142 142 # Code begins
143 143
144 144 # Utility functions
145 145 def inspect_error():
146 146 """Print a message about internal inspect errors.
147 147
148 148 These are unfortunately quite common."""
149 149
150 150 error('Internal Python error in the inspect module.\n'
151 151 'Below is the traceback from this internal error.\n')
152 152
153 153
154 154 # This function is a monkeypatch we apply to the Python inspect module. We have
155 155 # now found when it's needed (see discussion on issue gh-1456), and we have a
156 156 # test case (IPython.core.tests.test_ultratb.ChangedPyFileTest) that fails if
157 157 # the monkeypatch is not applied. TK, Aug 2012.
158 158 def findsource(object):
159 159 """Return the entire source file and starting line number for an object.
160 160
161 161 The argument may be a module, class, method, function, traceback, frame,
162 162 or code object. The source code is returned as a list of all the lines
163 163 in the file and the line number indexes a line in that list. An IOError
164 164 is raised if the source code cannot be retrieved.
165 165
166 166 FIXED version with which we monkeypatch the stdlib to work around a bug."""
167 167
168 168 file = getsourcefile(object) or getfile(object)
169 169 # If the object is a frame, then trying to get the globals dict from its
170 170 # module won't work. Instead, the frame object itself has the globals
171 171 # dictionary.
172 172 globals_dict = None
173 173 if inspect.isframe(object):
174 174 # XXX: can this ever be false?
175 175 globals_dict = object.f_globals
176 176 else:
177 177 module = getmodule(object, file)
178 178 if module:
179 179 globals_dict = module.__dict__
180 180 lines = linecache.getlines(file, globals_dict)
181 181 if not lines:
182 182 raise IOError('could not get source code')
183 183
184 184 if ismodule(object):
185 185 return lines, 0
186 186
187 187 if isclass(object):
188 188 name = object.__name__
189 189 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
190 190 # make some effort to find the best matching class definition:
191 191 # use the one with the least indentation, which is the one
192 192 # that's most probably not inside a function definition.
193 193 candidates = []
194 194 for i in range(len(lines)):
195 195 match = pat.match(lines[i])
196 196 if match:
197 197 # if it's at toplevel, it's already the best one
198 198 if lines[i][0] == 'c':
199 199 return lines, i
200 200 # else add whitespace to candidate list
201 201 candidates.append((match.group(1), i))
202 202 if candidates:
203 203 # this will sort by whitespace, and by line number,
204 204 # less whitespace first
205 205 candidates.sort()
206 206 return lines, candidates[0][1]
207 207 else:
208 208 raise IOError('could not find class definition')
209 209
210 210 if ismethod(object):
211 211 object = object.__func__
212 212 if isfunction(object):
213 213 object = object.__code__
214 214 if istraceback(object):
215 215 object = object.tb_frame
216 216 if isframe(object):
217 217 object = object.f_code
218 218 if iscode(object):
219 219 if not hasattr(object, 'co_firstlineno'):
220 220 raise IOError('could not find function definition')
221 221 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
222 222 pmatch = pat.match
223 223 # fperez - fix: sometimes, co_firstlineno can give a number larger than
224 224 # the length of lines, which causes an error. Safeguard against that.
225 225 lnum = min(object.co_firstlineno, len(lines)) - 1
226 226 while lnum > 0:
227 227 if pmatch(lines[lnum]):
228 228 break
229 229 lnum -= 1
230 230
231 231 return lines, lnum
232 232 raise IOError('could not find code object')
233 233
234 234
235 235 # This is a patched version of inspect.getargs that applies the (unmerged)
236 236 # patch for http://bugs.python.org/issue14611 by Stefano Taschini. This fixes
237 237 # https://github.com/ipython/ipython/issues/8205 and
238 238 # https://github.com/ipython/ipython/issues/8293
239 239 def getargs(co):
240 240 """Get information about the arguments accepted by a code object.
241 241
242 242 Three things are returned: (args, varargs, varkw), where 'args' is
243 243 a list of argument names (possibly containing nested lists), and
244 244 'varargs' and 'varkw' are the names of the * and ** arguments or None."""
245 245 if not iscode(co):
246 246 raise TypeError('{!r} is not a code object'.format(co))
247 247
248 248 nargs = co.co_argcount
249 249 names = co.co_varnames
250 250 args = list(names[:nargs])
251 251 step = 0
252 252
253 253 # The following acrobatics are for anonymous (tuple) arguments.
254 254 for i in range(nargs):
255 255 if args[i][:1] in ('', '.'):
256 256 stack, remain, count = [], [], []
257 257 while step < len(co.co_code):
258 258 op = ord(co.co_code[step])
259 259 step = step + 1
260 260 if op >= dis.HAVE_ARGUMENT:
261 261 opname = dis.opname[op]
262 262 value = ord(co.co_code[step]) + ord(co.co_code[step+1])*256
263 263 step = step + 2
264 264 if opname in ('UNPACK_TUPLE', 'UNPACK_SEQUENCE'):
265 265 remain.append(value)
266 266 count.append(value)
267 267 elif opname in ('STORE_FAST', 'STORE_DEREF'):
268 268 if op in dis.haslocal:
269 269 stack.append(co.co_varnames[value])
270 270 elif op in dis.hasfree:
271 271 stack.append((co.co_cellvars + co.co_freevars)[value])
272 272 # Special case for sublists of length 1: def foo((bar))
273 273 # doesn't generate the UNPACK_TUPLE bytecode, so if
274 274 # `remain` is empty here, we have such a sublist.
275 275 if not remain:
276 276 stack[0] = [stack[0]]
277 277 break
278 278 else:
279 279 remain[-1] = remain[-1] - 1
280 280 while remain[-1] == 0:
281 281 remain.pop()
282 282 size = count.pop()
283 283 stack[-size:] = [stack[-size:]]
284 284 if not remain:
285 285 break
286 286 remain[-1] = remain[-1] - 1
287 287 if not remain:
288 288 break
289 289 args[i] = stack[0]
290 290
291 291 varargs = None
292 292 if co.co_flags & inspect.CO_VARARGS:
293 293 varargs = co.co_varnames[nargs]
294 294 nargs = nargs + 1
295 295 varkw = None
296 296 if co.co_flags & inspect.CO_VARKEYWORDS:
297 297 varkw = co.co_varnames[nargs]
298 298 return inspect.Arguments(args, varargs, varkw)
299 299
300 300
301 301 # Monkeypatch inspect to apply our bugfix.
302 302 def with_patch_inspect(f):
303 303 """decorator for monkeypatching inspect.findsource"""
304 304
305 305 def wrapped(*args, **kwargs):
306 306 save_findsource = inspect.findsource
307 307 save_getargs = inspect.getargs
308 308 inspect.findsource = findsource
309 309 inspect.getargs = getargs
310 310 try:
311 311 return f(*args, **kwargs)
312 312 finally:
313 313 inspect.findsource = save_findsource
314 314 inspect.getargs = save_getargs
315 315
316 316 return wrapped
317 317
318 318
319 319 if py3compat.PY3:
320 320 fixed_getargvalues = inspect.getargvalues
321 321 else:
322 322 # Fixes for https://github.com/ipython/ipython/issues/8293
323 323 # and https://github.com/ipython/ipython/issues/8205.
324 324 # The relevant bug is caused by failure to correctly handle anonymous tuple
325 325 # unpacking, which only exists in Python 2.
326 326 fixed_getargvalues = with_patch_inspect(inspect.getargvalues)
327 327
328 328
329 329 def fix_frame_records_filenames(records):
330 330 """Try to fix the filenames in each record from inspect.getinnerframes().
331 331
332 332 Particularly, modules loaded from within zip files have useless filenames
333 333 attached to their code object, and inspect.getinnerframes() just uses it.
334 334 """
335 335 fixed_records = []
336 336 for frame, filename, line_no, func_name, lines, index in records:
337 337 # Look inside the frame's globals dictionary for __file__,
338 338 # which should be better. However, keep Cython filenames since
339 339 # we prefer the source filenames over the compiled .so file.
340 340 filename = py3compat.cast_unicode_py2(filename, "utf-8")
341 341 if not filename.endswith(('.pyx', '.pxd', '.pxi')):
342 342 better_fn = frame.f_globals.get('__file__', None)
343 343 if isinstance(better_fn, str):
344 344 # Check the type just in case someone did something weird with
345 345 # __file__. It might also be None if the error occurred during
346 346 # import.
347 347 filename = better_fn
348 348 fixed_records.append((frame, filename, line_no, func_name, lines, index))
349 349 return fixed_records
350 350
351 351
352 352 @with_patch_inspect
353 353 def _fixed_getinnerframes(etb, context=1, tb_offset=0):
354 354 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
355 355
356 356 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
357 357 # If the error is at the console, don't build any context, since it would
358 358 # otherwise produce 5 blank lines printed out (there is no file at the
359 359 # console)
360 360 rec_check = records[tb_offset:]
361 361 try:
362 362 rname = rec_check[0][1]
363 363 if rname == '<ipython console>' or rname.endswith('<string>'):
364 364 return rec_check
365 365 except IndexError:
366 366 pass
367 367
368 368 aux = traceback.extract_tb(etb)
369 369 assert len(records) == len(aux)
370 370 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
371 371 maybeStart = lnum - 1 - context // 2
372 372 start = max(maybeStart, 0)
373 373 end = start + context
374 374 lines = ulinecache.getlines(file)[start:end]
375 375 buf = list(records[i])
376 376 buf[LNUM_POS] = lnum
377 377 buf[INDEX_POS] = lnum - 1 - start
378 378 buf[LINES_POS] = lines
379 379 records[i] = tuple(buf)
380 380 return records[tb_offset:]
381 381
382 382 # Helper function -- largely belongs to VerboseTB, but we need the same
383 383 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
384 384 # can be recognized properly by ipython.el's py-traceback-line-re
385 385 # (SyntaxErrors have to be treated specially because they have no traceback)
386 386
387 387 _parser = PyColorize.Parser()
388 388
389 389
390 390 def _format_traceback_lines(lnum, index, lines, Colors, lvals=None, scheme=None):
391 391 numbers_width = INDENT_SIZE - 1
392 392 res = []
393 393 i = lnum - index
394 394
395 395 # This lets us get fully syntax-highlighted tracebacks.
396 396 if scheme is None:
397 397 ipinst = get_ipython()
398 398 if ipinst is not None:
399 399 scheme = ipinst.colors
400 400 else:
401 401 scheme = DEFAULT_SCHEME
402 402
403 403 _line_format = _parser.format2
404 404
405 405 for line in lines:
406 406 line = py3compat.cast_unicode(line)
407 407
408 408 new_line, err = _line_format(line, 'str', scheme)
409 409 if not err: line = new_line
410 410
411 411 if i == lnum:
412 412 # This is the line with the error
413 413 pad = numbers_width - len(str(i))
414 414 num = '%s%s' % (debugger.make_arrow(pad), str(lnum))
415 415 line = '%s%s%s %s%s' % (Colors.linenoEm, num,
416 416 Colors.line, line, Colors.Normal)
417 417 else:
418 418 num = '%*s' % (numbers_width, i)
419 419 line = '%s%s%s %s' % (Colors.lineno, num,
420 420 Colors.Normal, line)
421 421
422 422 res.append(line)
423 423 if lvals and i == lnum:
424 424 res.append(lvals + '\n')
425 425 i = i + 1
426 426 return res
427 427
428 428 def is_recursion_error(etype, value, records):
429 429 try:
430 430 # RecursionError is new in Python 3.5
431 431 recursion_error_type = RecursionError
432 432 except NameError:
433 433 recursion_error_type = RuntimeError
434 434
435 435 # The default recursion limit is 1000, but some of that will be taken up
436 436 # by stack frames in IPython itself. >500 frames probably indicates
437 437 # a recursion error.
438 438 return (etype is recursion_error_type) \
439 439 and "recursion" in str(value).lower() \
440 440 and len(records) > 500
441 441
442 442 def find_recursion(etype, value, records):
443 443 """Identify the repeating stack frames from a RecursionError traceback
444 444
445 445 'records' is a list as returned by VerboseTB.get_records()
446 446
447 447 Returns (last_unique, repeat_length)
448 448 """
449 449 # This involves a bit of guesswork - we want to show enough of the traceback
450 450 # to indicate where the recursion is occurring. We guess that the innermost
451 451 # quarter of the traceback (250 frames by default) is repeats, and find the
452 452 # first frame (from in to out) that looks different.
453 453 if not is_recursion_error(etype, value, records):
454 454 return len(records), 0
455 455
456 456 # Select filename, lineno, func_name to track frames with
457 457 records = [r[1:4] for r in records]
458 458 inner_frames = records[-(len(records)//4):]
459 459 frames_repeated = set(inner_frames)
460 460
461 461 last_seen_at = {}
462 462 longest_repeat = 0
463 463 i = len(records)
464 464 for frame in reversed(records):
465 465 i -= 1
466 466 if frame not in frames_repeated:
467 467 last_unique = i
468 468 break
469 469
470 470 if frame in last_seen_at:
471 471 distance = last_seen_at[frame] - i
472 472 longest_repeat = max(longest_repeat, distance)
473 473
474 474 last_seen_at[frame] = i
475 475 else:
476 476 last_unique = 0 # The whole traceback was recursion
477 477
478 478 return last_unique, longest_repeat
479 479
480 480 #---------------------------------------------------------------------------
481 481 # Module classes
482 482 class TBTools(colorable.Colorable):
483 483 """Basic tools used by all traceback printer classes."""
484 484
485 485 # Number of frames to skip when reporting tracebacks
486 486 tb_offset = 0
487 487
488 488 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=None, config=None):
489 489 # Whether to call the interactive pdb debugger after printing
490 490 # tracebacks or not
491 491 super(TBTools, self).__init__(parent=parent, config=config)
492 492 self.call_pdb = call_pdb
493 493
494 494 # Output stream to write to. Note that we store the original value in
495 495 # a private attribute and then make the public ostream a property, so
496 496 # that we can delay accessing io.stdout until runtime. The way
497 497 # things are written now, the io.stdout object is dynamically managed
498 498 # so a reference to it should NEVER be stored statically. This
499 499 # property approach confines this detail to a single location, and all
500 500 # subclasses can simply access self.ostream for writing.
501 501 self._ostream = ostream
502 502
503 503 # Create color table
504 504 self.color_scheme_table = exception_colors()
505 505
506 506 self.set_colors(color_scheme)
507 507 self.old_scheme = color_scheme # save initial value for toggles
508 508
509 509 if call_pdb:
510 510 self.pdb = debugger.Pdb(self.color_scheme_table.active_scheme_name)
511 511 else:
512 512 self.pdb = None
513 513
514 514 def _get_ostream(self):
515 515 """Output stream that exceptions are written to.
516 516
517 517 Valid values are:
518 518
519 519 - None: the default, which means that IPython will dynamically resolve
520 520 to io.stdout. This ensures compatibility with most tools, including
521 521 Windows (where plain stdout doesn't recognize ANSI escapes).
522 522
523 523 - Any object with 'write' and 'flush' attributes.
524 524 """
525 525 return sys.stdout if self._ostream is None else self._ostream
526 526
527 527 def _set_ostream(self, val):
528 528 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
529 529 self._ostream = val
530 530
531 531 ostream = property(_get_ostream, _set_ostream)
532 532
533 533 def set_colors(self, *args, **kw):
534 534 """Shorthand access to the color table scheme selector method."""
535 535
536 536 # Set own color table
537 537 self.color_scheme_table.set_active_scheme(*args, **kw)
538 538 # for convenience, set Colors to the active scheme
539 539 self.Colors = self.color_scheme_table.active_colors
540 540 # Also set colors of debugger
541 541 if hasattr(self, 'pdb') and self.pdb is not None:
542 542 self.pdb.set_colors(*args, **kw)
543 543
544 544 def color_toggle(self):
545 545 """Toggle between the currently active color scheme and NoColor."""
546 546
547 547 if self.color_scheme_table.active_scheme_name == 'NoColor':
548 548 self.color_scheme_table.set_active_scheme(self.old_scheme)
549 549 self.Colors = self.color_scheme_table.active_colors
550 550 else:
551 551 self.old_scheme = self.color_scheme_table.active_scheme_name
552 552 self.color_scheme_table.set_active_scheme('NoColor')
553 553 self.Colors = self.color_scheme_table.active_colors
554 554
555 555 def stb2text(self, stb):
556 556 """Convert a structured traceback (a list) to a string."""
557 557 return '\n'.join(stb)
558 558
559 559 def text(self, etype, value, tb, tb_offset=None, context=5):
560 560 """Return formatted traceback.
561 561
562 562 Subclasses may override this if they add extra arguments.
563 563 """
564 564 tb_list = self.structured_traceback(etype, value, tb,
565 565 tb_offset, context)
566 566 return self.stb2text(tb_list)
567 567
568 568 def structured_traceback(self, etype, evalue, tb, tb_offset=None,
569 569 context=5, mode=None):
570 570 """Return a list of traceback frames.
571 571
572 572 Must be implemented by each class.
573 573 """
574 574 raise NotImplementedError()
575 575
576 576
577 577 #---------------------------------------------------------------------------
578 578 class ListTB(TBTools):
579 579 """Print traceback information from a traceback list, with optional color.
580 580
581 581 Calling requires 3 arguments: (etype, evalue, elist)
582 582 as would be obtained by::
583 583
584 584 etype, evalue, tb = sys.exc_info()
585 585 if tb:
586 586 elist = traceback.extract_tb(tb)
587 587 else:
588 588 elist = None
589 589
590 590 It can thus be used by programs which need to process the traceback before
591 591 printing (such as console replacements based on the code module from the
592 592 standard library).
593 593
594 594 Because they are meant to be called without a full traceback (only a
595 595 list), instances of this class can't call the interactive pdb debugger."""
596 596
597 597 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=None):
598 598 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
599 599 ostream=ostream, parent=parent)
600 600
601 601 def __call__(self, etype, value, elist):
602 602 self.ostream.flush()
603 603 self.ostream.write(self.text(etype, value, elist))
604 604 self.ostream.write('\n')
605 605
606 606 def structured_traceback(self, etype, value, elist, tb_offset=None,
607 607 context=5):
608 608 """Return a color formatted string with the traceback info.
609 609
610 610 Parameters
611 611 ----------
612 612 etype : exception type
613 613 Type of the exception raised.
614 614
615 615 value : object
616 616 Data stored in the exception
617 617
618 618 elist : list
619 619 List of frames, see class docstring for details.
620 620
621 621 tb_offset : int, optional
622 622 Number of frames in the traceback to skip. If not given, the
623 623 instance value is used (set in constructor).
624 624
625 625 context : int, optional
626 626 Number of lines of context information to print.
627 627
628 628 Returns
629 629 -------
630 630 String with formatted exception.
631 631 """
632 632 tb_offset = self.tb_offset if tb_offset is None else tb_offset
633 633 Colors = self.Colors
634 634 out_list = []
635 635 if elist:
636 636
637 637 if tb_offset and len(elist) > tb_offset:
638 638 elist = elist[tb_offset:]
639 639
640 640 out_list.append('Traceback %s(most recent call last)%s:' %
641 641 (Colors.normalEm, Colors.Normal) + '\n')
642 642 out_list.extend(self._format_list(elist))
643 643 # The exception info should be a single entry in the list.
644 644 lines = ''.join(self._format_exception_only(etype, value))
645 645 out_list.append(lines)
646 646
647 647 # Note: this code originally read:
648 648
649 649 ## for line in lines[:-1]:
650 650 ## out_list.append(" "+line)
651 651 ## out_list.append(lines[-1])
652 652
653 653 # This means it was indenting everything but the last line by a little
654 654 # bit. I've disabled this for now, but if we see ugliness somewhere we
655 655 # can restore it.
656 656
657 657 return out_list
658 658
659 659 def _format_list(self, extracted_list):
660 660 """Format a list of traceback entry tuples for printing.
661 661
662 662 Given a list of tuples as returned by extract_tb() or
663 663 extract_stack(), return a list of strings ready for printing.
664 664 Each string in the resulting list corresponds to the item with the
665 665 same index in the argument list. Each string ends in a newline;
666 666 the strings may contain internal newlines as well, for those items
667 667 whose source text line is not None.
668 668
669 669 Lifted almost verbatim from traceback.py
670 670 """
671 671
672 672 Colors = self.Colors
673 673 list = []
674 674 for filename, lineno, name, line in extracted_list[:-1]:
675 675 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
676 676 (Colors.filename, py3compat.cast_unicode_py2(filename, "utf-8"), Colors.Normal,
677 677 Colors.lineno, lineno, Colors.Normal,
678 678 Colors.name, py3compat.cast_unicode_py2(name, "utf-8"), Colors.Normal)
679 679 if line:
680 680 item += ' %s\n' % line.strip()
681 681 list.append(item)
682 682 # Emphasize the last entry
683 683 filename, lineno, name, line = extracted_list[-1]
684 684 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
685 685 (Colors.normalEm,
686 686 Colors.filenameEm, py3compat.cast_unicode_py2(filename, "utf-8"), Colors.normalEm,
687 687 Colors.linenoEm, lineno, Colors.normalEm,
688 688 Colors.nameEm, py3compat.cast_unicode_py2(name, "utf-8"), Colors.normalEm,
689 689 Colors.Normal)
690 690 if line:
691 691 item += '%s %s%s\n' % (Colors.line, line.strip(),
692 692 Colors.Normal)
693 693 list.append(item)
694 694 return list
695 695
696 696 def _format_exception_only(self, etype, value):
697 697 """Format the exception part of a traceback.
698 698
699 699 The arguments are the exception type and value such as given by
700 700 sys.exc_info()[:2]. The return value is a list of strings, each ending
701 701 in a newline. Normally, the list contains a single string; however,
702 702 for SyntaxError exceptions, it contains several lines that (when
703 703 printed) display detailed information about where the syntax error
704 704 occurred. The message indicating which exception occurred is the
705 705 always last string in the list.
706 706
707 707 Also lifted nearly verbatim from traceback.py
708 708 """
709 709 have_filedata = False
710 710 Colors = self.Colors
711 711 list = []
712 712 stype = Colors.excName + etype.__name__ + Colors.Normal
713 713 if value is None:
714 714 # Not sure if this can still happen in Python 2.6 and above
715 715 list.append(py3compat.cast_unicode(stype) + '\n')
716 716 else:
717 717 if issubclass(etype, SyntaxError):
718 718 have_filedata = True
719 719 if not value.filename: value.filename = "<string>"
720 720 if value.lineno:
721 721 lineno = value.lineno
722 722 textline = ulinecache.getline(value.filename, value.lineno)
723 723 else:
724 724 lineno = 'unknown'
725 725 textline = ''
726 726 list.append('%s File %s"%s"%s, line %s%s%s\n' % \
727 727 (Colors.normalEm,
728 728 Colors.filenameEm, py3compat.cast_unicode(value.filename), Colors.normalEm,
729 729 Colors.linenoEm, lineno, Colors.Normal ))
730 730 if textline == '':
731 731 textline = py3compat.cast_unicode(value.text, "utf-8")
732 732
733 733 if textline is not None:
734 734 i = 0
735 735 while i < len(textline) and textline[i].isspace():
736 736 i += 1
737 737 list.append('%s %s%s\n' % (Colors.line,
738 738 textline.strip(),
739 739 Colors.Normal))
740 740 if value.offset is not None:
741 741 s = ' '
742 742 for c in textline[i:value.offset - 1]:
743 743 if c.isspace():
744 744 s += c
745 745 else:
746 746 s += ' '
747 747 list.append('%s%s^%s\n' % (Colors.caret, s,
748 748 Colors.Normal))
749 749
750 750 try:
751 751 s = value.msg
752 752 except Exception:
753 753 s = self._some_str(value)
754 754 if s:
755 755 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
756 756 Colors.Normal, s))
757 757 else:
758 758 list.append('%s\n' % str(stype))
759 759
760 760 # sync with user hooks
761 761 if have_filedata:
762 762 ipinst = get_ipython()
763 763 if ipinst is not None:
764 764 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
765 765
766 766 return list
767 767
768 768 def get_exception_only(self, etype, value):
769 769 """Only print the exception type and message, without a traceback.
770 770
771 771 Parameters
772 772 ----------
773 773 etype : exception type
774 774 value : exception value
775 775 """
776 776 return ListTB.structured_traceback(self, etype, value, [])
777 777
778 778 def show_exception_only(self, etype, evalue):
779 779 """Only print the exception type and message, without a traceback.
780 780
781 781 Parameters
782 782 ----------
783 783 etype : exception type
784 784 value : exception value
785 785 """
786 786 # This method needs to use __call__ from *this* class, not the one from
787 787 # a subclass whose signature or behavior may be different
788 788 ostream = self.ostream
789 789 ostream.flush()
790 790 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
791 791 ostream.flush()
792 792
793 793 def _some_str(self, value):
794 794 # Lifted from traceback.py
795 795 try:
796 796 return str(value)
797 797 except:
798 798 return '<unprintable %s object>' % type(value).__name__
799 799
800 800
801 801 #----------------------------------------------------------------------------
802 802 class VerboseTB(TBTools):
803 803 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
804 804 of HTML. Requires inspect and pydoc. Crazy, man.
805 805
806 806 Modified version which optionally strips the topmost entries from the
807 807 traceback, to be used with alternate interpreters (because their own code
808 808 would appear in the traceback)."""
809 809
810 810 def __init__(self, color_scheme='Linux', call_pdb=False, ostream=None,
811 811 tb_offset=0, long_header=False, include_vars=True,
812 812 check_cache=None):
813 813 """Specify traceback offset, headers and color scheme.
814 814
815 815 Define how many frames to drop from the tracebacks. Calling it with
816 816 tb_offset=1 allows use of this handler in interpreters which will have
817 817 their own code at the top of the traceback (VerboseTB will first
818 818 remove that frame before printing the traceback info)."""
819 819 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
820 820 ostream=ostream)
821 821 self.tb_offset = tb_offset
822 822 self.long_header = long_header
823 823 self.include_vars = include_vars
824 824 # By default we use linecache.checkcache, but the user can provide a
825 825 # different check_cache implementation. This is used by the IPython
826 826 # kernel to provide tracebacks for interactive code that is cached,
827 827 # by a compiler instance that flushes the linecache but preserves its
828 828 # own code cache.
829 829 if check_cache is None:
830 830 check_cache = linecache.checkcache
831 831 self.check_cache = check_cache
832 832
833 833 def format_records(self, records, last_unique, recursion_repeat):
834 834 """Format the stack frames of the traceback"""
835 835 frames = []
836 836 for r in records[:last_unique+recursion_repeat+1]:
837 837 #print '*** record:',file,lnum,func,lines,index # dbg
838 838 frames.append(self.format_record(*r))
839 839
840 840 if recursion_repeat:
841 841 frames.append('... last %d frames repeated, from the frame below ...\n' % recursion_repeat)
842 842 frames.append(self.format_record(*records[last_unique+recursion_repeat+1]))
843 843
844 844 return frames
845 845
846 846 def format_record(self, frame, file, lnum, func, lines, index):
847 847 """Format a single stack frame"""
848 848 Colors = self.Colors # just a shorthand + quicker name lookup
849 849 ColorsNormal = Colors.Normal # used a lot
850 850 col_scheme = self.color_scheme_table.active_scheme_name
851 851 indent = ' ' * INDENT_SIZE
852 852 em_normal = '%s\n%s%s' % (Colors.valEm, indent, ColorsNormal)
853 853 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
854 854 tpl_link = '%s%%s%s' % (Colors.filenameEm, ColorsNormal)
855 855 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
856 856 ColorsNormal)
857 857 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
858 858 (Colors.vName, Colors.valEm, ColorsNormal)
859 859 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
860 860 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
861 861 Colors.vName, ColorsNormal)
862 862 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
863 863
864 864 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
865 865 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm, Colors.line,
866 866 ColorsNormal)
867 867
868 868 abspath = os.path.abspath
869 869
870 870
871 871 if not file:
872 872 file = '?'
873 873 elif file.startswith(str("<")) and file.endswith(str(">")):
874 874 # Not a real filename, no problem...
875 875 pass
876 876 elif not os.path.isabs(file):
877 877 # Try to make the filename absolute by trying all
878 878 # sys.path entries (which is also what linecache does)
879 879 for dirname in sys.path:
880 880 try:
881 881 fullname = os.path.join(dirname, file)
882 882 if os.path.isfile(fullname):
883 883 file = os.path.abspath(fullname)
884 884 break
885 885 except Exception:
886 886 # Just in case that sys.path contains very
887 887 # strange entries...
888 888 pass
889 889
890 890 file = py3compat.cast_unicode(file, util_path.fs_encoding)
891 891 link = tpl_link % file
892 892 args, varargs, varkw, locals = fixed_getargvalues(frame)
893 893
894 894 if func == '?':
895 895 call = ''
896 896 else:
897 897 # Decide whether to include variable details or not
898 898 var_repr = self.include_vars and eqrepr or nullrepr
899 899 try:
900 900 call = tpl_call % (func, inspect.formatargvalues(args,
901 901 varargs, varkw,
902 902 locals, formatvalue=var_repr))
903 903 except KeyError:
904 904 # This happens in situations like errors inside generator
905 905 # expressions, where local variables are listed in the
906 906 # line, but can't be extracted from the frame. I'm not
907 907 # 100% sure this isn't actually a bug in inspect itself,
908 908 # but since there's no info for us to compute with, the
909 909 # best we can do is report the failure and move on. Here
910 910 # we must *not* call any traceback construction again,
911 911 # because that would mess up use of %debug later on. So we
912 912 # simply report the failure and move on. The only
913 913 # limitation will be that this frame won't have locals
914 914 # listed in the call signature. Quite subtle problem...
915 915 # I can't think of a good way to validate this in a unit
916 916 # test, but running a script consisting of:
917 917 # dict( (k,v.strip()) for (k,v) in range(10) )
918 918 # will illustrate the error, if this exception catch is
919 919 # disabled.
920 920 call = tpl_call_fail % func
921 921
922 922 # Don't attempt to tokenize binary files.
923 923 if file.endswith(('.so', '.pyd', '.dll')):
924 924 return '%s %s\n' % (link, call)
925 925
926 926 elif file.endswith(('.pyc', '.pyo')):
927 927 # Look up the corresponding source file.
928 928 file = openpy.source_from_cache(file)
929 929
930 930 def linereader(file=file, lnum=[lnum], getline=ulinecache.getline):
931 931 line = getline(file, lnum[0])
932 932 lnum[0] += 1
933 933 return line
934 934
935 935 # Build the list of names on this line of code where the exception
936 936 # occurred.
937 937 try:
938 938 names = []
939 939 name_cont = False
940 940
941 941 for token_type, token, start, end, line in generate_tokens(linereader):
942 942 # build composite names
943 943 if token_type == tokenize.NAME and token not in keyword.kwlist:
944 944 if name_cont:
945 945 # Continuation of a dotted name
946 946 try:
947 947 names[-1].append(token)
948 948 except IndexError:
949 949 names.append([token])
950 950 name_cont = False
951 951 else:
952 952 # Regular new names. We append everything, the caller
953 953 # will be responsible for pruning the list later. It's
954 954 # very tricky to try to prune as we go, b/c composite
955 955 # names can fool us. The pruning at the end is easy
956 956 # to do (or the caller can print a list with repeated
957 957 # names if so desired.
958 958 names.append([token])
959 959 elif token == '.':
960 960 name_cont = True
961 961 elif token_type == tokenize.NEWLINE:
962 962 break
963 963
964 964 except (IndexError, UnicodeDecodeError, SyntaxError):
965 965 # signals exit of tokenizer
966 966 # SyntaxError can occur if the file is not actually Python
967 967 # - see gh-6300
968 968 pass
969 969 except tokenize.TokenError as msg:
970 970 _m = ("An unexpected error occurred while tokenizing input\n"
971 971 "The following traceback may be corrupted or invalid\n"
972 972 "The error message is: %s\n" % msg)
973 973 error(_m)
974 974
975 975 # Join composite names (e.g. "dict.fromkeys")
976 976 names = ['.'.join(n) for n in names]
977 977 # prune names list of duplicates, but keep the right order
978 978 unique_names = uniq_stable(names)
979 979
980 980 # Start loop over vars
981 981 lvals = []
982 982 if self.include_vars:
983 983 for name_full in unique_names:
984 984 name_base = name_full.split('.', 1)[0]
985 985 if name_base in frame.f_code.co_varnames:
986 986 if name_base in locals:
987 987 try:
988 988 value = repr(eval(name_full, locals))
989 989 except:
990 990 value = undefined
991 991 else:
992 992 value = undefined
993 993 name = tpl_local_var % name_full
994 994 else:
995 995 if name_base in frame.f_globals:
996 996 try:
997 997 value = repr(eval(name_full, frame.f_globals))
998 998 except:
999 999 value = undefined
1000 1000 else:
1001 1001 value = undefined
1002 1002 name = tpl_global_var % name_full
1003 1003 lvals.append(tpl_name_val % (name, value))
1004 1004 if lvals:
1005 1005 lvals = '%s%s' % (indent, em_normal.join(lvals))
1006 1006 else:
1007 1007 lvals = ''
1008 1008
1009 1009 level = '%s %s\n' % (link, call)
1010 1010
1011 1011 if index is None:
1012 1012 return level
1013 1013 else:
1014 1014 return '%s%s' % (level, ''.join(
1015 1015 _format_traceback_lines(lnum, index, lines, Colors, lvals,
1016 1016 col_scheme)))
1017 1017
1018 1018 def prepare_chained_exception_message(self, cause):
1019 1019 direct_cause = "\nThe above exception was the direct cause of the following exception:\n"
1020 1020 exception_during_handling = "\nDuring handling of the above exception, another exception occurred:\n"
1021 1021
1022 1022 if cause:
1023 1023 message = [[direct_cause]]
1024 1024 else:
1025 1025 message = [[exception_during_handling]]
1026 1026 return message
1027 1027
1028 1028 def prepare_header(self, etype, long_version=False):
1029 1029 colors = self.Colors # just a shorthand + quicker name lookup
1030 1030 colorsnormal = colors.Normal # used a lot
1031 1031 exc = '%s%s%s' % (colors.excName, etype, colorsnormal)
1032 1032 width = min(75, get_terminal_size()[0])
1033 1033 if long_version:
1034 1034 # Header with the exception type, python version, and date
1035 1035 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
1036 1036 date = time.ctime(time.time())
1037 1037
1038 1038 head = '%s%s%s\n%s%s%s\n%s' % (colors.topline, '-' * width, colorsnormal,
1039 1039 exc, ' ' * (width - len(str(etype)) - len(pyver)),
1040 1040 pyver, date.rjust(width) )
1041 1041 head += "\nA problem occurred executing Python code. Here is the sequence of function" \
1042 1042 "\ncalls leading up to the error, with the most recent (innermost) call last."
1043 1043 else:
1044 1044 # Simplified header
1045 1045 head = '%s%s' % (exc, 'Traceback (most recent call last)'. \
1046 1046 rjust(width - len(str(etype))) )
1047 1047
1048 1048 return head
1049 1049
1050 1050 def format_exception(self, etype, evalue):
1051 1051 colors = self.Colors # just a shorthand + quicker name lookup
1052 1052 colorsnormal = colors.Normal # used a lot
1053 1053 indent = ' ' * INDENT_SIZE
1054 1054 # Get (safely) a string form of the exception info
1055 1055 try:
1056 1056 etype_str, evalue_str = map(str, (etype, evalue))
1057 1057 except:
1058 1058 # User exception is improperly defined.
1059 1059 etype, evalue = str, sys.exc_info()[:2]
1060 1060 etype_str, evalue_str = map(str, (etype, evalue))
1061 1061 # ... and format it
1062 1062 exception = ['%s%s%s: %s' % (colors.excName, etype_str,
1063 1063 colorsnormal, py3compat.cast_unicode(evalue_str))]
1064 1064
1065 1065 if (not py3compat.PY3) and type(evalue) is types.InstanceType:
1066 1066 try:
1067 1067 names = [w for w in dir(evalue) if isinstance(w, py3compat.string_types)]
1068 1068 except:
1069 1069 # Every now and then, an object with funny internals blows up
1070 1070 # when dir() is called on it. We do the best we can to report
1071 1071 # the problem and continue
1072 1072 _m = '%sException reporting error (object with broken dir())%s:'
1073 1073 exception.append(_m % (colors.excName, colorsnormal))
1074 1074 etype_str, evalue_str = map(str, sys.exc_info()[:2])
1075 1075 exception.append('%s%s%s: %s' % (colors.excName, etype_str,
1076 1076 colorsnormal, py3compat.cast_unicode(evalue_str)))
1077 1077 names = []
1078 1078 for name in names:
1079 1079 value = text_repr(getattr(evalue, name))
1080 1080 exception.append('\n%s%s = %s' % (indent, name, value))
1081 1081
1082 1082 return exception
1083 1083
1084 1084 def format_exception_as_a_whole(self, etype, evalue, etb, number_of_lines_of_context, tb_offset):
1085 1085 """Formats the header, traceback and exception message for a single exception.
1086 1086
1087 1087 This may be called multiple times by Python 3 exception chaining
1088 1088 (PEP 3134).
1089 1089 """
1090 1090 # some locals
1091 1091 orig_etype = etype
1092 1092 try:
1093 1093 etype = etype.__name__
1094 1094 except AttributeError:
1095 1095 pass
1096 1096
1097 1097 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1098 1098 head = self.prepare_header(etype, self.long_header)
1099 1099 records = self.get_records(etb, number_of_lines_of_context, tb_offset)
1100 1100
1101 1101 if records is None:
1102 1102 return ""
1103 1103
1104 1104 last_unique, recursion_repeat = find_recursion(orig_etype, evalue, records)
1105 1105
1106 1106 frames = self.format_records(records, last_unique, recursion_repeat)
1107 1107
1108 1108 formatted_exception = self.format_exception(etype, evalue)
1109 1109 if records:
1110 1110 filepath, lnum = records[-1][1:3]
1111 1111 filepath = os.path.abspath(filepath)
1112 1112 ipinst = get_ipython()
1113 1113 if ipinst is not None:
1114 1114 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
1115 1115
1116 1116 return [[head] + frames + [''.join(formatted_exception[0])]]
1117 1117
1118 1118 def get_records(self, etb, number_of_lines_of_context, tb_offset):
1119 1119 try:
1120 1120 # Try the default getinnerframes and Alex's: Alex's fixes some
1121 1121 # problems, but it generates empty tracebacks for console errors
1122 1122 # (5 blanks lines) where none should be returned.
1123 1123 return _fixed_getinnerframes(etb, number_of_lines_of_context, tb_offset)
1124 1124 except:
1125 1125 # FIXME: I've been getting many crash reports from python 2.3
1126 1126 # users, traceable to inspect.py. If I can find a small test-case
1127 1127 # to reproduce this, I should either write a better workaround or
1128 1128 # file a bug report against inspect (if that's the real problem).
1129 1129 # So far, I haven't been able to find an isolated example to
1130 1130 # reproduce the problem.
1131 1131 inspect_error()
1132 1132 traceback.print_exc(file=self.ostream)
1133 1133 info('\nUnfortunately, your original traceback can not be constructed.\n')
1134 1134 return None
1135 1135
1136 1136 def get_parts_of_chained_exception(self, evalue):
1137 1137 def get_chained_exception(exception_value):
1138 1138 cause = getattr(exception_value, '__cause__', None)
1139 1139 if cause:
1140 1140 return cause
1141 1141 if getattr(exception_value, '__suppress_context__', False):
1142 1142 return None
1143 1143 return getattr(exception_value, '__context__', None)
1144 1144
1145 1145 chained_evalue = get_chained_exception(evalue)
1146 1146
1147 1147 if chained_evalue:
1148 1148 return chained_evalue.__class__, chained_evalue, chained_evalue.__traceback__
1149 1149
1150 1150 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
1151 1151 number_of_lines_of_context=5):
1152 1152 """Return a nice text document describing the traceback."""
1153 1153
1154 1154 formatted_exception = self.format_exception_as_a_whole(etype, evalue, etb, number_of_lines_of_context,
1155 1155 tb_offset)
1156 1156
1157 1157 colors = self.Colors # just a shorthand + quicker name lookup
1158 1158 colorsnormal = colors.Normal # used a lot
1159 1159 head = '%s%s%s' % (colors.topline, '-' * min(75, get_terminal_size()[0]), colorsnormal)
1160 1160 structured_traceback_parts = [head]
1161 1161 if py3compat.PY3:
1162 1162 chained_exceptions_tb_offset = 0
1163 1163 lines_of_context = 3
1164 1164 formatted_exceptions = formatted_exception
1165 1165 exception = self.get_parts_of_chained_exception(evalue)
1166 1166 if exception:
1167 1167 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
1168 1168 etype, evalue, etb = exception
1169 1169 else:
1170 1170 evalue = None
1171 1171 chained_exc_ids = set()
1172 1172 while evalue:
1173 1173 formatted_exceptions += self.format_exception_as_a_whole(etype, evalue, etb, lines_of_context,
1174 1174 chained_exceptions_tb_offset)
1175 1175 exception = self.get_parts_of_chained_exception(evalue)
1176 1176
1177 1177 if exception and not id(exception[1]) in chained_exc_ids:
1178 1178 chained_exc_ids.add(id(exception[1])) # trace exception to avoid infinite 'cause' loop
1179 1179 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
1180 1180 etype, evalue, etb = exception
1181 1181 else:
1182 1182 evalue = None
1183 1183
1184 1184 # we want to see exceptions in a reversed order:
1185 1185 # the first exception should be on top
1186 1186 for formatted_exception in reversed(formatted_exceptions):
1187 1187 structured_traceback_parts += formatted_exception
1188 1188 else:
1189 1189 structured_traceback_parts += formatted_exception[0]
1190 1190
1191 1191 return structured_traceback_parts
1192 1192
1193 1193 def debugger(self, force=False):
1194 1194 """Call up the pdb debugger if desired, always clean up the tb
1195 1195 reference.
1196 1196
1197 1197 Keywords:
1198 1198
1199 1199 - force(False): by default, this routine checks the instance call_pdb
1200 1200 flag and does not actually invoke the debugger if the flag is false.
1201 1201 The 'force' option forces the debugger to activate even if the flag
1202 1202 is false.
1203 1203
1204 1204 If the call_pdb flag is set, the pdb interactive debugger is
1205 1205 invoked. In all cases, the self.tb reference to the current traceback
1206 1206 is deleted to prevent lingering references which hamper memory
1207 1207 management.
1208 1208
1209 1209 Note that each call to pdb() does an 'import readline', so if your app
1210 1210 requires a special setup for the readline completers, you'll have to
1211 1211 fix that by hand after invoking the exception handler."""
1212 1212
1213 1213 if force or self.call_pdb:
1214 1214 if self.pdb is None:
1215 1215 self.pdb = debugger.Pdb(
1216 1216 self.color_scheme_table.active_scheme_name)
1217 1217 # the system displayhook may have changed, restore the original
1218 1218 # for pdb
1219 1219 display_trap = DisplayTrap(hook=sys.__displayhook__)
1220 1220 with display_trap:
1221 1221 self.pdb.reset()
1222 1222 # Find the right frame so we don't pop up inside ipython itself
1223 1223 if hasattr(self, 'tb') and self.tb is not None:
1224 1224 etb = self.tb
1225 1225 else:
1226 1226 etb = self.tb = sys.last_traceback
1227 1227 while self.tb is not None and self.tb.tb_next is not None:
1228 1228 self.tb = self.tb.tb_next
1229 1229 if etb and etb.tb_next:
1230 1230 etb = etb.tb_next
1231 1231 self.pdb.botframe = etb.tb_frame
1232 1232 self.pdb.interaction(self.tb.tb_frame, self.tb)
1233 1233
1234 1234 if hasattr(self, 'tb'):
1235 1235 del self.tb
1236 1236
1237 1237 def handler(self, info=None):
1238 1238 (etype, evalue, etb) = info or sys.exc_info()
1239 1239 self.tb = etb
1240 1240 ostream = self.ostream
1241 1241 ostream.flush()
1242 1242 ostream.write(self.text(etype, evalue, etb))
1243 1243 ostream.write('\n')
1244 1244 ostream.flush()
1245 1245
1246 1246 # Changed so an instance can just be called as VerboseTB_inst() and print
1247 1247 # out the right info on its own.
1248 1248 def __call__(self, etype=None, evalue=None, etb=None):
1249 1249 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
1250 1250 if etb is None:
1251 1251 self.handler()
1252 1252 else:
1253 1253 self.handler((etype, evalue, etb))
1254 1254 try:
1255 1255 self.debugger()
1256 1256 except KeyboardInterrupt:
1257 1257 print("\nKeyboardInterrupt")
1258 1258
1259 1259
1260 1260 #----------------------------------------------------------------------------
1261 1261 class FormattedTB(VerboseTB, ListTB):
1262 1262 """Subclass ListTB but allow calling with a traceback.
1263 1263
1264 1264 It can thus be used as a sys.excepthook for Python > 2.1.
1265 1265
1266 1266 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
1267 1267
1268 1268 Allows a tb_offset to be specified. This is useful for situations where
1269 1269 one needs to remove a number of topmost frames from the traceback (such as
1270 1270 occurs with python programs that themselves execute other python code,
1271 1271 like Python shells). """
1272 1272
1273 1273 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1274 1274 ostream=None,
1275 1275 tb_offset=0, long_header=False, include_vars=False,
1276 1276 check_cache=None):
1277 1277
1278 1278 # NEVER change the order of this list. Put new modes at the end:
1279 1279 self.valid_modes = ['Plain', 'Context', 'Verbose']
1280 1280 self.verbose_modes = self.valid_modes[1:3]
1281 1281
1282 1282 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
1283 1283 ostream=ostream, tb_offset=tb_offset,
1284 1284 long_header=long_header, include_vars=include_vars,
1285 1285 check_cache=check_cache)
1286 1286
1287 1287 # Different types of tracebacks are joined with different separators to
1288 1288 # form a single string. They are taken from this dict
1289 1289 self._join_chars = dict(Plain='', Context='\n', Verbose='\n')
1290 1290 # set_mode also sets the tb_join_char attribute
1291 1291 self.set_mode(mode)
1292 1292
1293 1293 def _extract_tb(self, tb):
1294 1294 if tb:
1295 1295 return traceback.extract_tb(tb)
1296 1296 else:
1297 1297 return None
1298 1298
1299 1299 def structured_traceback(self, etype, value, tb, tb_offset=None, number_of_lines_of_context=5):
1300 1300 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1301 1301 mode = self.mode
1302 1302 if mode in self.verbose_modes:
1303 1303 # Verbose modes need a full traceback
1304 1304 return VerboseTB.structured_traceback(
1305 1305 self, etype, value, tb, tb_offset, number_of_lines_of_context
1306 1306 )
1307 1307 else:
1308 1308 # We must check the source cache because otherwise we can print
1309 1309 # out-of-date source code.
1310 1310 self.check_cache()
1311 1311 # Now we can extract and format the exception
1312 1312 elist = self._extract_tb(tb)
1313 1313 return ListTB.structured_traceback(
1314 1314 self, etype, value, elist, tb_offset, number_of_lines_of_context
1315 1315 )
1316 1316
1317 1317 def stb2text(self, stb):
1318 1318 """Convert a structured traceback (a list) to a string."""
1319 1319 return self.tb_join_char.join(stb)
1320 1320
1321 1321
1322 1322 def set_mode(self, mode=None):
1323 1323 """Switch to the desired mode.
1324 1324
1325 1325 If mode is not specified, cycles through the available modes."""
1326 1326
1327 1327 if not mode:
1328 1328 new_idx = (self.valid_modes.index(self.mode) + 1 ) % \
1329 1329 len(self.valid_modes)
1330 1330 self.mode = self.valid_modes[new_idx]
1331 1331 elif mode not in self.valid_modes:
1332 1332 raise ValueError('Unrecognized mode in FormattedTB: <' + mode + '>\n'
1333 1333 'Valid modes: ' + str(self.valid_modes))
1334 1334 else:
1335 1335 self.mode = mode
1336 1336 # include variable details only in 'Verbose' mode
1337 1337 self.include_vars = (self.mode == self.valid_modes[2])
1338 1338 # Set the join character for generating text tracebacks
1339 1339 self.tb_join_char = self._join_chars[self.mode]
1340 1340
1341 1341 # some convenient shortcuts
1342 1342 def plain(self):
1343 1343 self.set_mode(self.valid_modes[0])
1344 1344
1345 1345 def context(self):
1346 1346 self.set_mode(self.valid_modes[1])
1347 1347
1348 1348 def verbose(self):
1349 1349 self.set_mode(self.valid_modes[2])
1350 1350
1351 1351
1352 1352 #----------------------------------------------------------------------------
1353 1353 class AutoFormattedTB(FormattedTB):
1354 1354 """A traceback printer which can be called on the fly.
1355 1355
1356 1356 It will find out about exceptions by itself.
1357 1357
1358 1358 A brief example::
1359 1359
1360 1360 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1361 1361 try:
1362 1362 ...
1363 1363 except:
1364 1364 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1365 1365 """
1366 1366
1367 1367 def __call__(self, etype=None, evalue=None, etb=None,
1368 1368 out=None, tb_offset=None):
1369 1369 """Print out a formatted exception traceback.
1370 1370
1371 1371 Optional arguments:
1372 1372 - out: an open file-like object to direct output to.
1373 1373
1374 1374 - tb_offset: the number of frames to skip over in the stack, on a
1375 1375 per-call basis (this overrides temporarily the instance's tb_offset
1376 1376 given at initialization time. """
1377 1377
1378 1378 if out is None:
1379 1379 out = self.ostream
1380 1380 out.flush()
1381 1381 out.write(self.text(etype, evalue, etb, tb_offset))
1382 1382 out.write('\n')
1383 1383 out.flush()
1384 1384 # FIXME: we should remove the auto pdb behavior from here and leave
1385 1385 # that to the clients.
1386 1386 try:
1387 1387 self.debugger()
1388 1388 except KeyboardInterrupt:
1389 1389 print("\nKeyboardInterrupt")
1390 1390
1391 1391 def structured_traceback(self, etype=None, value=None, tb=None,
1392 1392 tb_offset=None, number_of_lines_of_context=5):
1393 1393 if etype is None:
1394 1394 etype, value, tb = sys.exc_info()
1395 1395 self.tb = tb
1396 1396 return FormattedTB.structured_traceback(
1397 1397 self, etype, value, tb, tb_offset, number_of_lines_of_context)
1398 1398
1399 1399
1400 1400 #---------------------------------------------------------------------------
1401 1401
1402 1402 # A simple class to preserve Nathan's original functionality.
1403 1403 class ColorTB(FormattedTB):
1404 1404 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1405 1405
1406 1406 def __init__(self, color_scheme='Linux', call_pdb=0, **kwargs):
1407 1407 FormattedTB.__init__(self, color_scheme=color_scheme,
1408 1408 call_pdb=call_pdb, **kwargs)
1409 1409
1410 1410
1411 1411 class SyntaxTB(ListTB):
1412 1412 """Extension which holds some state: the last exception value"""
1413 1413
1414 1414 def __init__(self, color_scheme='NoColor'):
1415 1415 ListTB.__init__(self, color_scheme)
1416 1416 self.last_syntax_error = None
1417 1417
1418 1418 def __call__(self, etype, value, elist):
1419 1419 self.last_syntax_error = value
1420 1420
1421 1421 ListTB.__call__(self, etype, value, elist)
1422 1422
1423 1423 def structured_traceback(self, etype, value, elist, tb_offset=None,
1424 1424 context=5):
1425 1425 # If the source file has been edited, the line in the syntax error can
1426 1426 # be wrong (retrieved from an outdated cache). This replaces it with
1427 1427 # the current value.
1428 1428 if isinstance(value, SyntaxError) \
1429 1429 and isinstance(value.filename, py3compat.string_types) \
1430 1430 and isinstance(value.lineno, int):
1431 1431 linecache.checkcache(value.filename)
1432 1432 newtext = ulinecache.getline(value.filename, value.lineno)
1433 1433 if newtext:
1434 1434 value.text = newtext
1435 self.last_syntax_error = value
1435 1436 return super(SyntaxTB, self).structured_traceback(etype, value, elist,
1436 1437 tb_offset=tb_offset, context=context)
1437 1438
1438 1439 def clear_err_state(self):
1439 1440 """Return the current error state and clear it"""
1440 1441 e = self.last_syntax_error
1441 1442 self.last_syntax_error = None
1442 1443 return e
1443 1444
1444 1445 def stb2text(self, stb):
1445 1446 """Convert a structured traceback (a list) to a string."""
1446 1447 return ''.join(stb)
1447 1448
1448 1449
1449 1450 # some internal-use functions
1450 1451 def text_repr(value):
1451 1452 """Hopefully pretty robust repr equivalent."""
1452 1453 # this is pretty horrible but should always return *something*
1453 1454 try:
1454 1455 return pydoc.text.repr(value)
1455 1456 except KeyboardInterrupt:
1456 1457 raise
1457 1458 except:
1458 1459 try:
1459 1460 return repr(value)
1460 1461 except KeyboardInterrupt:
1461 1462 raise
1462 1463 except:
1463 1464 try:
1464 1465 # all still in an except block so we catch
1465 1466 # getattr raising
1466 1467 name = getattr(value, '__name__', None)
1467 1468 if name:
1468 1469 # ick, recursion
1469 1470 return text_repr(name)
1470 1471 klass = getattr(value, '__class__', None)
1471 1472 if klass:
1472 1473 return '%s instance' % text_repr(klass)
1473 1474 except KeyboardInterrupt:
1474 1475 raise
1475 1476 except:
1476 1477 return 'UNRECOVERABLE REPR FAILURE'
1477 1478
1478 1479
1479 1480 def eqrepr(value, repr=text_repr):
1480 1481 return '=%s' % repr(value)
1481 1482
1482 1483
1483 1484 def nullrepr(value, repr=text_repr):
1484 1485 return ''
@@ -1,321 +1,390 b''
1 1 """IPython terminal interface using prompt_toolkit in place of readline"""
2 2 from __future__ import print_function
3 3
4 4 import os
5 5 import sys
6 6 import signal
7 from warnings import warn
7 8
9 from IPython.core.error import TryNext
8 10 from IPython.core.interactiveshell import InteractiveShell
9 11 from IPython.utils.py3compat import PY3, cast_unicode_py2, input
10 12 from IPython.utils.terminal import toggle_set_term_title, set_term_title
11 13 from IPython.utils.process import abbrev_cwd
12 14 from traitlets import Bool, CBool, Unicode, Dict
13 15
14 16 from prompt_toolkit.completion import Completer, Completion
15 17 from prompt_toolkit.enums import DEFAULT_BUFFER
16 18 from prompt_toolkit.filters import HasFocus, HasSelection, Condition
17 19 from prompt_toolkit.history import InMemoryHistory
18 20 from prompt_toolkit.shortcuts import create_prompt_application, create_eventloop
19 21 from prompt_toolkit.interface import CommandLineInterface
20 22 from prompt_toolkit.key_binding.manager import KeyBindingManager
21 23 from prompt_toolkit.key_binding.vi_state import InputMode
22 24 from prompt_toolkit.key_binding.bindings.vi import ViStateFilter
23 25 from prompt_toolkit.keys import Keys
24 26 from prompt_toolkit.layout.lexers import Lexer
25 27 from prompt_toolkit.layout.lexers import PygmentsLexer
26 28 from prompt_toolkit.styles import PygmentsStyle
27 29
28 30 from pygments.styles import get_style_by_name
29 31 from pygments.lexers import Python3Lexer, BashLexer, PythonLexer
30 32 from pygments.token import Token
31 33
32 34 from .pt_inputhooks import get_inputhook_func
33 35 from .interactiveshell import get_default_editor, TerminalMagics
34 36
35 37
36 38
37 39 class IPythonPTCompleter(Completer):
38 40 """Adaptor to provide IPython completions to prompt_toolkit"""
39 41 def __init__(self, ipy_completer):
40 42 self.ipy_completer = ipy_completer
41 43
42 44 def get_completions(self, document, complete_event):
43 45 if not document.current_line.strip():
44 46 return
45 47
46 48 used, matches = self.ipy_completer.complete(
47 49 line_buffer=document.current_line,
48 50 cursor_pos=document.cursor_position_col
49 51 )
50 52 start_pos = -len(used)
51 53 for m in matches:
52 54 yield Completion(m, start_position=start_pos)
53 55
54 56
55 57 class IPythonPTLexer(Lexer):
56 58 """
57 59 Wrapper around PythonLexer and BashLexer.
58 60 """
59 61 def __init__(self):
60 62 self.python_lexer = PygmentsLexer(Python3Lexer if PY3 else PythonLexer)
61 63 self.shell_lexer = PygmentsLexer(BashLexer)
62 64
63 65 def lex_document(self, cli, document):
64 66 if document.text.startswith('!'):
65 67 return self.shell_lexer.lex_document(cli, document)
66 68 else:
67 69 return self.python_lexer.lex_document(cli, document)
68 70
69 71
70 72 class TerminalInteractiveShell(InteractiveShell):
71 73 colors_force = True
72 74
73 75 pt_cli = None
74 76
77 autoedit_syntax = CBool(False, config=True,
78 help="auto editing of files with syntax errors.")
79
75 80 confirm_exit = CBool(True, config=True,
76 81 help="""
77 82 Set to confirm when you try to exit IPython with an EOF (Control-D
78 83 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
79 84 you can force a direct exit without any confirmation.""",
80 85 )
81 86 vi_mode = Bool(False, config=True,
82 87 help="Use vi style keybindings at the prompt",
83 88 )
84 89
85 90 mouse_support = Bool(False, config=True,
86 91 help="Enable mouse support in the prompt"
87 92 )
88 93
89 94 highlighting_style = Unicode('', config=True,
90 95 help="The name of a Pygments style to use for syntax highlighting"
91 96 )
92 97
93 98 highlighting_style_overrides = Dict(config=True,
94 99 help="Override highlighting format for specific tokens"
95 100 )
96 101
97 102 editor = Unicode(get_default_editor(), config=True,
98 103 help="Set the editor used by IPython (default to $EDITOR/vi/notepad)."
99 104 )
100 105
101 106 term_title = Bool(True, config=True,
102 107 help="Automatically set the terminal title"
103 108 )
104 109 def _term_title_changed(self, name, new_value):
105 110 self.init_term_title()
106 111
107 112 def init_term_title(self):
108 113 # Enable or disable the terminal title.
109 114 if self.term_title:
110 115 toggle_set_term_title(True)
111 116 set_term_title('IPython: ' + abbrev_cwd())
112 117 else:
113 118 toggle_set_term_title(False)
114 119
115 120 def get_prompt_tokens(self, cli):
116 121 return [
117 122 (Token.Prompt, 'In ['),
118 123 (Token.PromptNum, str(self.execution_count)),
119 124 (Token.Prompt, ']: '),
120 125 ]
121 126
122 127 def get_continuation_tokens(self, cli, width):
123 128 return [
124 129 (Token.Prompt, (' ' * (width - 5)) + '...: '),
125 130 ]
126 131
127 132 def init_prompt_toolkit_cli(self):
128 133 if ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or not sys.stdin.isatty():
129 134 # Fall back to plain non-interactive output for tests.
130 135 # This is very limited, and only accepts a single line.
131 136 def prompt():
132 137 return cast_unicode_py2(input('In [%d]: ' % self.execution_count))
133 138 self.prompt_for_code = prompt
134 139 return
135 140
136 141 kbmanager = KeyBindingManager.for_prompt(enable_vi_mode=self.vi_mode)
137 142 insert_mode = ViStateFilter(kbmanager.get_vi_state, InputMode.INSERT)
138 143 # Ctrl+J == Enter, seemingly
139 144 @kbmanager.registry.add_binding(Keys.ControlJ,
140 145 filter=(HasFocus(DEFAULT_BUFFER)
141 146 & ~HasSelection()
142 147 & insert_mode
143 148 ))
144 149 def _(event):
145 150 b = event.current_buffer
146 151 d = b.document
147 152 if not (d.on_last_line or d.cursor_position_row >= d.line_count
148 153 - d.empty_line_count_at_the_end()):
149 154 b.newline()
150 155 return
151 156
152 157 status, indent = self.input_splitter.check_complete(d.text)
153 158
154 159 if (status != 'incomplete') and b.accept_action.is_returnable:
155 160 b.accept_action.validate_and_handle(event.cli, b)
156 161 else:
157 162 b.insert_text('\n' + (' ' * (indent or 0)))
158 163
159 164 @kbmanager.registry.add_binding(Keys.ControlC, filter=HasFocus(DEFAULT_BUFFER))
160 165 def _(event):
161 166 event.current_buffer.reset()
162 167
163 168 supports_suspend = Condition(lambda cli: hasattr(signal, 'SIGTSTP'))
164 169
165 170 @kbmanager.registry.add_binding(Keys.ControlZ, filter=supports_suspend)
166 171 def _(event):
167 172 event.cli.suspend_to_background()
168 173
169 174 @Condition
170 175 def cursor_in_leading_ws(cli):
171 176 before = cli.application.buffer.document.current_line_before_cursor
172 177 return (not before) or before.isspace()
173 178
174 179 # Ctrl+I == Tab
175 180 @kbmanager.registry.add_binding(Keys.ControlI,
176 181 filter=(HasFocus(DEFAULT_BUFFER)
177 182 & ~HasSelection()
178 183 & insert_mode
179 184 & cursor_in_leading_ws
180 185 ))
181 186 def _(event):
182 187 event.current_buffer.insert_text(' ' * 4)
183 188
184 189 # Pre-populate history from IPython's history database
185 190 history = InMemoryHistory()
186 191 last_cell = u""
187 192 for _, _, cell in self.history_manager.get_tail(self.history_load_length,
188 193 include_latest=True):
189 194 # Ignore blank lines and consecutive duplicates
190 195 cell = cell.rstrip()
191 196 if cell and (cell != last_cell):
192 197 history.append(cell)
193 198
194 199 style_overrides = {
195 200 Token.Prompt: '#009900',
196 201 Token.PromptNum: '#00ff00 bold',
197 202 }
198 203 if self.highlighting_style:
199 204 style_cls = get_style_by_name(self.highlighting_style)
200 205 else:
201 206 style_cls = get_style_by_name('default')
202 207 # The default theme needs to be visible on both a dark background
203 208 # and a light background, because we can't tell what the terminal
204 209 # looks like. These tweaks to the default theme help with that.
205 210 style_overrides.update({
206 211 Token.Number: '#007700',
207 212 Token.Operator: 'noinherit',
208 213 Token.String: '#BB6622',
209 214 Token.Name.Function: '#2080D0',
210 215 Token.Name.Class: 'bold #2080D0',
211 216 Token.Name.Namespace: 'bold #2080D0',
212 217 })
213 218 style_overrides.update(self.highlighting_style_overrides)
214 219 style = PygmentsStyle.from_defaults(pygments_style_cls=style_cls,
215 220 style_dict=style_overrides)
216 221
217 222 app = create_prompt_application(multiline=True,
218 223 lexer=IPythonPTLexer(),
219 224 get_prompt_tokens=self.get_prompt_tokens,
220 225 get_continuation_tokens=self.get_continuation_tokens,
221 226 key_bindings_registry=kbmanager.registry,
222 227 history=history,
223 228 completer=IPythonPTCompleter(self.Completer),
224 229 enable_history_search=True,
225 230 style=style,
226 231 mouse_support=self.mouse_support,
227 232 reserve_space_for_menu=6,
228 233 )
229 234
230 235 self.pt_cli = CommandLineInterface(app,
231 236 eventloop=create_eventloop(self.inputhook))
232 237
233 238 def prompt_for_code(self):
234 239 document = self.pt_cli.run(pre_run=self.pre_prompt)
235 240 return document.text
236 241
237 242 def init_io(self):
238 243 if sys.platform not in {'win32', 'cli'}:
239 244 return
240 245
241 246 import colorama
242 247 colorama.init()
243 248
244 249 # For some reason we make these wrappers around stdout/stderr.
245 250 # For now, we need to reset them so all output gets coloured.
246 251 # https://github.com/ipython/ipython/issues/8669
247 252 from IPython.utils import io
248 253 io.stdout = io.IOStream(sys.stdout)
249 254 io.stderr = io.IOStream(sys.stderr)
250 255
251 256 def init_magics(self):
252 257 super(TerminalInteractiveShell, self).init_magics()
253 258 self.register_magics(TerminalMagics)
254 259
255 260 def init_alias(self):
256 261 # The parent class defines aliases that can be safely used with any
257 262 # frontend.
258 263 super(TerminalInteractiveShell, self).init_alias()
259 264
260 265 # Now define aliases that only make sense on the terminal, because they
261 266 # need direct access to the console in a way that we can't emulate in
262 267 # GUI or web frontend
263 268 if os.name == 'posix':
264 269 for cmd in ['clear', 'more', 'less', 'man']:
265 270 self.alias_manager.soft_define_alias(cmd, cmd)
266 271
267 272
268 273 def __init__(self, *args, **kwargs):
269 274 super(TerminalInteractiveShell, self).__init__(*args, **kwargs)
270 275 self.init_prompt_toolkit_cli()
271 276 self.init_term_title()
272 277 self.keep_running = True
273 278
274 279 def ask_exit(self):
275 280 self.keep_running = False
276 281
277 282 rl_next_input = None
278 283
279 284 def pre_prompt(self):
280 285 if self.rl_next_input:
281 286 self.pt_cli.application.buffer.text = cast_unicode_py2(self.rl_next_input)
282 287 self.rl_next_input = None
283 288
284 289 def interact(self):
285 290 while self.keep_running:
286 291 print(self.separate_in, end='')
287 292
288 293 try:
289 294 code = self.prompt_for_code()
290 295 except EOFError:
291 296 if (not self.confirm_exit) \
292 297 or self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'):
293 298 self.ask_exit()
294 299
295 300 else:
296 301 if code:
297 302 self.run_cell(code, store_history=True)
303 if self.autoedit_syntax and self.SyntaxTB.last_syntax_error:
304 self.edit_syntax_error()
298 305
299 306 def mainloop(self):
300 307 # An extra layer of protection in case someone mashing Ctrl-C breaks
301 308 # out of our internal code.
302 309 while True:
303 310 try:
304 311 self.interact()
305 312 break
306 313 except KeyboardInterrupt:
307 314 print("\nKeyboardInterrupt escaped interact()\n")
308 315
309 316 _inputhook = None
310 317 def inputhook(self, context):
311 318 if self._inputhook is not None:
312 319 self._inputhook(context)
313 320
314 321 def enable_gui(self, gui=None):
315 322 if gui:
316 323 self._inputhook = get_inputhook_func(gui)
317 324 else:
318 325 self._inputhook = None
319 326
327 # Methods to support auto-editing of SyntaxErrors:
328
329 def edit_syntax_error(self):
330 """The bottom half of the syntax error handler called in the main loop.
331
332 Loop until syntax error is fixed or user cancels.
333 """
334
335 while self.SyntaxTB.last_syntax_error:
336 # copy and clear last_syntax_error
337 err = self.SyntaxTB.clear_err_state()
338 if not self._should_recompile(err):
339 return
340 try:
341 # may set last_syntax_error again if a SyntaxError is raised
342 self.safe_execfile(err.filename, self.user_ns)
343 except:
344 self.showtraceback()
345 else:
346 try:
347 f = open(err.filename)
348 try:
349 # This should be inside a display_trap block and I
350 # think it is.
351 sys.displayhook(f.read())
352 finally:
353 f.close()
354 except:
355 self.showtraceback()
356
357 def _should_recompile(self, e):
358 """Utility routine for edit_syntax_error"""
359
360 if e.filename in ('<ipython console>', '<input>', '<string>',
361 '<console>', '<BackgroundJob compilation>',
362 None):
363 return False
364 try:
365 if (self.autoedit_syntax and
366 not self.ask_yes_no(
367 'Return to editor to correct syntax error? '
368 '[Y/n] ', 'y')):
369 return False
370 except EOFError:
371 return False
372
373 def int0(x):
374 try:
375 return int(x)
376 except TypeError:
377 return 0
378
379 # always pass integer line and offset values to editor hook
380 try:
381 self.hooks.fix_error_editor(e.filename,
382 int0(e.lineno), int0(e.offset),
383 e.msg)
384 except TryNext:
385 warn('Could not open editor')
386 return False
387 return True
388
320 389 if __name__ == '__main__':
321 390 TerminalInteractiveShell.instance().interact()
General Comments 0
You need to be logged in to leave comments. Login now