##// END OF EJS Templates
Merge pull request #6065 from atteroTheGreatest/i1673...
Thomas Kluyver -
r17170:2bf35f92 merge
parent child Browse files
Show More
@@ -2918,7 +2918,6 b' class InteractiveShell(SingletonConfigurable):'
2918 False : successful execution.
2918 False : successful execution.
2919 True : an error occurred.
2919 True : an error occurred.
2920 """
2920 """
2921
2922 # Set our own excepthook in case the user code tries to call it
2921 # Set our own excepthook in case the user code tries to call it
2923 # directly, so that the IPython crash handler doesn't get triggered
2922 # directly, so that the IPython crash handler doesn't get triggered
2924 old_excepthook,sys.excepthook = sys.excepthook, self.excepthook
2923 old_excepthook, sys.excepthook = sys.excepthook, self.excepthook
@@ -9,6 +9,7 b' from IPython.testing import tools as tt'
9 from IPython.testing.decorators import onlyif_unicode_paths
9 from IPython.testing.decorators import onlyif_unicode_paths
10 from IPython.utils.syspathcontext import prepended_to_syspath
10 from IPython.utils.syspathcontext import prepended_to_syspath
11 from IPython.utils.tempdir import TemporaryDirectory
11 from IPython.utils.tempdir import TemporaryDirectory
12 from IPython.utils.py3compat import PY3
12
13
13 ip = get_ipython()
14 ip = get_ipython()
14
15
@@ -147,3 +148,37 b' class SyntaxErrorTest(unittest.TestCase):'
147 except ValueError:
148 except ValueError:
148 with tt.AssertPrints('QWERTY'):
149 with tt.AssertPrints('QWERTY'):
149 ip.showsyntaxerror()
150 ip.showsyntaxerror()
151
152
153 class Python3ChainedExceptionsTest(unittest.TestCase):
154 DIRECT_CAUSE_ERROR_CODE = """
155 try:
156 x = 1 + 2
157 print(not_defined_here)
158 except Exception as e:
159 x += 55
160 x - 1
161 y = {}
162 raise KeyError('uh') from e
163 """
164
165 EXCEPTION_DURING_HANDLING_CODE = """
166 try:
167 x = 1 + 2
168 print(not_defined_here)
169 except Exception as e:
170 x += 55
171 x - 1
172 y = {}
173 raise KeyError('uh')
174 """
175
176 def test_direct_cause_error(self):
177 if PY3:
178 with tt.AssertPrints(["KeyError", "NameError", "direct cause"]):
179 ip.run_cell(self.DIRECT_CAUSE_ERROR_CODE)
180
181 def test_exception_during_handling_error(self):
182 if PY3:
183 with tt.AssertPrints(["KeyError", "NameError", "During handling"]):
184 ip.run_cell(self.EXCEPTION_DURING_HANDLING_CODE)
@@ -39,7 +39,7 b" Give it a shot--you'll love it or you'll hate it."
39 Verbose).
39 Verbose).
40
40
41
41
42 Installation instructions for ColorTB::
42 Installation instructions for VerboseTB::
43
43
44 import sys,ultratb
44 import sys,ultratb
45 sys.excepthook = ultratb.VerboseTB()
45 sys.excepthook = ultratb.VerboseTB()
@@ -141,6 +141,7 b' def inspect_error():'
141 error('Internal Python error in the inspect module.\n'
141 error('Internal Python error in the inspect module.\n'
142 'Below is the traceback from this internal error.\n')
142 'Below is the traceback from this internal error.\n')
143
143
144
144 # This function is a monkeypatch we apply to the Python inspect module. We have
145 # This function is a monkeypatch we apply to the Python inspect module. We have
145 # now found when it's needed (see discussion on issue gh-1456), and we have a
146 # now found when it's needed (see discussion on issue gh-1456), and we have a
146 # test case (IPython.core.tests.test_ultratb.ChangedPyFileTest) that fails if
147 # test case (IPython.core.tests.test_ultratb.ChangedPyFileTest) that fails if
@@ -220,9 +221,11 b' def findsource(object):'
220 return lines, lnum
221 return lines, lnum
221 raise IOError('could not find code object')
222 raise IOError('could not find code object')
222
223
224
223 # Monkeypatch inspect to apply our bugfix.
225 # Monkeypatch inspect to apply our bugfix.
224 def with_patch_inspect(f):
226 def with_patch_inspect(f):
225 """decorator for monkeypatching inspect.findsource"""
227 """decorator for monkeypatching inspect.findsource"""
228
226 def wrapped(*args, **kwargs):
229 def wrapped(*args, **kwargs):
227 save_findsource = inspect.findsource
230 save_findsource = inspect.findsource
228 inspect.findsource = findsource
231 inspect.findsource = findsource
@@ -230,8 +233,10 b' def with_patch_inspect(f):'
230 return f(*args, **kwargs)
233 return f(*args, **kwargs)
231 finally:
234 finally:
232 inspect.findsource = save_findsource
235 inspect.findsource = save_findsource
236
233 return wrapped
237 return wrapped
234
238
239
235 def fix_frame_records_filenames(records):
240 def fix_frame_records_filenames(records):
236 """Try to fix the filenames in each record from inspect.getinnerframes().
241 """Try to fix the filenames in each record from inspect.getinnerframes().
237
242
@@ -257,7 +262,6 b' def _fixed_getinnerframes(etb, context=1,tb_offset=0):'
257 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
262 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
258
263
259 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
264 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
260
261 # If the error is at the console, don't build any context, since it would
265 # If the error is at the console, don't build any context, since it would
262 # otherwise produce 5 blank lines printed out (there is no file at the
266 # otherwise produce 5 blank lines printed out (there is no file at the
263 # console)
267 # console)
@@ -290,6 +294,7 b' def _fixed_getinnerframes(etb, context=1,tb_offset=0):'
290
294
291 _parser = PyColorize.Parser()
295 _parser = PyColorize.Parser()
292
296
297
293 def _format_traceback_lines(lnum, index, lines, Colors, lvals=None,scheme=None):
298 def _format_traceback_lines(lnum, index, lines, Colors, lvals=None, scheme=None):
294 numbers_width = INDENT_SIZE - 1
299 numbers_width = INDENT_SIZE - 1
295 res = []
300 res = []
@@ -510,7 +515,7 b' class ListTB(TBTools):'
510 ## out_list.append(lines[-1])
515 ## out_list.append(lines[-1])
511
516
512 # This means it was indenting everything but the last line by a little
517 # This means it was indenting everything but the last line by a little
513 # bit. I've disabled this for now, but if we see ugliness somewhre we
518 # bit. I've disabled this for now, but if we see ugliness somewhere we
514 # can restore it.
519 # can restore it.
515
520
516 return out_list
521 return out_list
@@ -550,7 +555,6 b' class ListTB(TBTools):'
550 item += '%s %s%s\n' % (Colors.line, line.strip(),
555 item += '%s %s%s\n' % (Colors.line, line.strip(),
551 Colors.Normal)
556 Colors.Normal)
552 list.append(item)
557 list.append(item)
553 #from pprint import pformat; print 'LISTTB', pformat(list) # dbg
554 return list
558 return list
555
559
556 def _format_exception_only(self, etype, value):
560 def _format_exception_only(self, etype, value):
@@ -576,7 +580,6 b' class ListTB(TBTools):'
576 else:
580 else:
577 if issubclass(etype, SyntaxError):
581 if issubclass(etype, SyntaxError):
578 have_filedata = True
582 have_filedata = True
579 #print 'filename is',filename # dbg
580 if not value.filename: value.filename = "<string>"
583 if not value.filename: value.filename = "<string>"
581 if value.lineno:
584 if value.lineno:
582 lineno = value.lineno
585 lineno = value.lineno
@@ -636,7 +639,6 b' class ListTB(TBTools):'
636 """
639 """
637 return ListTB.structured_traceback(self, etype, value, [])
640 return ListTB.structured_traceback(self, etype, value, [])
638
641
639
640 def show_exception_only(self, etype, evalue):
642 def show_exception_only(self, etype, evalue):
641 """Only print the exception type and message, without a traceback.
643 """Only print the exception type and message, without a traceback.
642
644
@@ -659,6 +661,7 b' class ListTB(TBTools):'
659 except:
661 except:
660 return '<unprintable %s object>' % type(value).__name__
662 return '<unprintable %s object>' % type(value).__name__
661
663
664
662 #----------------------------------------------------------------------------
665 #----------------------------------------------------------------------------
663 class VerboseTB(TBTools):
666 class VerboseTB(TBTools):
664 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
667 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
@@ -691,103 +694,14 b' class VerboseTB(TBTools):'
691 check_cache = linecache.checkcache
694 check_cache = linecache.checkcache
692 self.check_cache = check_cache
695 self.check_cache = check_cache
693
696
694 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
697 def format_records(self, records):
695 context=5):
696 """Return a nice text document describing the traceback."""
697
698 tb_offset = self.tb_offset if tb_offset is None else tb_offset
699
700 # some locals
701 try:
702 etype = etype.__name__
703 except AttributeError:
704 pass
705 Colors = self.Colors # just a shorthand + quicker name lookup
698 Colors = self.Colors # just a shorthand + quicker name lookup
706 ColorsNormal = Colors.Normal # used a lot
699 ColorsNormal = Colors.Normal # used a lot
707 col_scheme = self.color_scheme_table.active_scheme_name
700 col_scheme = self.color_scheme_table.active_scheme_name
708 indent = ' '*INDENT_SIZE
701 indent = ' ' * INDENT_SIZE
709 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
702 em_normal = '%s\n%s%s' % (Colors.valEm, indent, ColorsNormal)
710 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
703 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
711 exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
712
713 # some internal-use functions
714 def text_repr(value):
715 """Hopefully pretty robust repr equivalent."""
716 # this is pretty horrible but should always return *something*
717 try:
718 return pydoc.text.repr(value)
719 except KeyboardInterrupt:
720 raise
721 except:
722 try:
723 return repr(value)
724 except KeyboardInterrupt:
725 raise
726 except:
727 try:
728 # all still in an except block so we catch
729 # getattr raising
730 name = getattr(value, '__name__', None)
731 if name:
732 # ick, recursion
733 return text_repr(name)
734 klass = getattr(value, '__class__', None)
735 if klass:
736 return '%s instance' % text_repr(klass)
737 except KeyboardInterrupt:
738 raise
739 except:
740 return 'UNRECOVERABLE REPR FAILURE'
741 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
742 def nullrepr(value, repr=text_repr): return ''
743
744 # meat of the code begins
745 try:
746 etype = etype.__name__
747 except AttributeError:
748 pass
749
750 if self.long_header:
751 # Header with the exception type, python version, and date
752 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
753 date = time.ctime(time.time())
754
755 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
756 exc, ' '*(75-len(str(etype))-len(pyver)),
757 pyver, date.rjust(75) )
758 head += "\nA problem occured executing Python code. Here is the sequence of function"\
759 "\ncalls leading up to the error, with the most recent (innermost) call last."
760 else:
761 # Simplified header
762 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
763 'Traceback (most recent call last)'.\
764 rjust(75 - len(str(etype)) ) )
765 frames = []
704 frames = []
766 # Flush cache before calling inspect. This helps alleviate some of the
767 # problems with python 2.3's inspect.py.
768 ##self.check_cache()
769 # Drop topmost frames if requested
770 try:
771 # Try the default getinnerframes and Alex's: Alex's fixes some
772 # problems, but it generates empty tracebacks for console errors
773 # (5 blanks lines) where none should be returned.
774 #records = inspect.getinnerframes(etb, context)[tb_offset:]
775 #print 'python records:', records # dbg
776 records = _fixed_getinnerframes(etb, context, tb_offset)
777 #print 'alex records:', records # dbg
778 except:
779
780 # FIXME: I've been getting many crash reports from python 2.3
781 # users, traceable to inspect.py. If I can find a small test-case
782 # to reproduce this, I should either write a better workaround or
783 # file a bug report against inspect (if that's the real problem).
784 # So far, I haven't been able to find an isolated example to
785 # reproduce the problem.
786 inspect_error()
787 traceback.print_exc(file=self.ostream)
788 info('\nUnfortunately, your original traceback can not be constructed.\n')
789 return ''
790
791 # build some color string templates outside these nested loops
705 # build some color string templates outside these nested loops
792 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
706 tpl_link = '%s%%s%s' % (Colors.filenameEm, ColorsNormal)
793 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
707 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
@@ -798,11 +712,11 b' class VerboseTB(TBTools):'
798 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
712 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
799 Colors.vName, ColorsNormal)
713 Colors.vName, ColorsNormal)
800 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
714 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
715
801 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
716 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
802 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
717 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm, Colors.line,
803 ColorsNormal)
718 ColorsNormal)
804
719
805 # now, loop over all records printing context and info
806 abspath = os.path.abspath
720 abspath = os.path.abspath
807 for frame, file, lnum, func, lines, index in records:
721 for frame, file, lnum, func, lines, index in records:
808 #print '*** record:',file,lnum,func,lines,index # dbg
722 #print '*** record:',file,lnum,func,lines,index # dbg
@@ -943,6 +857,43 b' class VerboseTB(TBTools):'
943 _format_traceback_lines(lnum,index,lines,Colors,lvals,
857 _format_traceback_lines(lnum, index, lines, Colors, lvals,
944 col_scheme))))
858 col_scheme))))
945
859
860 return frames
861
862 def prepare_chained_exception_message(self, cause):
863 direct_cause = "\nThe above exception was the direct cause of the following exception:\n"
864 exception_during_handling = "\nDuring handling of the above exception, another exception occurred:\n"
865
866 if cause:
867 message = [[direct_cause]]
868 else:
869 message = [[exception_during_handling]]
870 return message
871
872 def prepare_header(self, etype, long_version=False):
873 colors = self.Colors # just a shorthand + quicker name lookup
874 colorsnormal = colors.Normal # used a lot
875 exc = '%s%s%s' % (colors.excName, etype, colorsnormal)
876 if long_version:
877 # Header with the exception type, python version, and date
878 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
879 date = time.ctime(time.time())
880
881 head = '%s%s%s\n%s%s%s\n%s' % (colors.topline, '-' * 75, colorsnormal,
882 exc, ' ' * (75 - len(str(etype)) - len(pyver)),
883 pyver, date.rjust(75) )
884 head += "\nA problem occurred executing Python code. Here is the sequence of function" \
885 "\ncalls leading up to the error, with the most recent (innermost) call last."
886 else:
887 # Simplified header
888 head = '%s%s' % (exc, 'Traceback (most recent call last)'. \
889 rjust(75 - len(str(etype))) )
890
891 return head
892
893 def format_exception(self, etype, evalue):
894 colors = self.Colors # just a shorthand + quicker name lookup
895 colorsnormal = colors.Normal # used a lot
896 indent = ' ' * INDENT_SIZE
946 # Get (safely) a string form of the exception info
897 # Get (safely) a string form of the exception info
947 try:
898 try:
948 etype_str,evalue_str = map(str,(etype,evalue))
899 etype_str, evalue_str = map(str, (etype, evalue))
@@ -951,38 +902,123 b' class VerboseTB(TBTools):'
951 etype,evalue = str,sys.exc_info()[:2]
902 etype, evalue = str, sys.exc_info()[:2]
952 etype_str,evalue_str = map(str,(etype,evalue))
903 etype_str, evalue_str = map(str, (etype, evalue))
953 # ... and format it
904 # ... and format it
954 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
905 exception = ['%s%s%s: %s' % (colors.excName, etype_str,
955 ColorsNormal, py3compat.cast_unicode(evalue_str))]
906 colorsnormal, py3compat.cast_unicode(evalue_str))]
907
956 if (not py3compat.PY3) and type(evalue) is types.InstanceType:
908 if (not py3compat.PY3) and type(evalue) is types.InstanceType:
957 try:
909 try:
958 names = [w for w in dir(evalue) if isinstance(w, py3compat.string_types)]
910 names = [w for w in dir(evalue) if isinstance(w, py3compat.string_types)]
959 except:
911 except:
960 # Every now and then, an object with funny inernals blows up
912 # Every now and then, an object with funny internals blows up
961 # when dir() is called on it. We do the best we can to report
913 # when dir() is called on it. We do the best we can to report
962 # the problem and continue
914 # the problem and continue
963 _m = '%sException reporting error (object with broken dir())%s:'
915 _m = '%sException reporting error (object with broken dir())%s:'
964 exception.append(_m % (Colors.excName,ColorsNormal))
916 exception.append(_m % (colors.excName, colorsnormal))
965 etype_str,evalue_str = map(str,sys.exc_info()[:2])
917 etype_str, evalue_str = map(str, sys.exc_info()[:2])
966 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
918 exception.append('%s%s%s: %s' % (colors.excName, etype_str,
967 ColorsNormal, py3compat.cast_unicode(evalue_str)))
919 colorsnormal, py3compat.cast_unicode(evalue_str)))
968 names = []
920 names = []
969 for name in names:
921 for name in names:
970 value = text_repr(getattr(evalue, name))
922 value = text_repr(getattr(evalue, name))
971 exception.append('\n%s%s = %s' % (indent, name, value))
923 exception.append('\n%s%s = %s' % (indent, name, value))
972
924
973 # vds: >>
925 return exception
926
927 def format_exception_as_a_whole(self, etype, evalue, etb, number_of_lines_of_context, tb_offset):
928 # some locals
929 try:
930 etype = etype.__name__
931 except AttributeError:
932 pass
933
934 tb_offset = self.tb_offset if tb_offset is None else tb_offset
935 head = self.prepare_header(etype, self.long_header)
936 records = self.get_records(etb, number_of_lines_of_context, tb_offset)
937
938 frames = self.format_records(records)
939 if records is None:
940 return ""
941
942 formatted_exception = self.format_exception(etype, evalue)
974 if records:
943 if records:
975 filepath, lnum = records[-1][1:3]
944 filepath, lnum = records[-1][1:3]
976 #print "file:", str(file), "linenb", str(lnum) # dbg
977 filepath = os.path.abspath(filepath)
945 filepath = os.path.abspath(filepath)
978 ipinst = get_ipython()
946 ipinst = get_ipython()
979 if ipinst is not None:
947 if ipinst is not None:
980 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
948 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
981 # vds: <<
982
949
983 # return all our info assembled as a single string
950 return [[head] + frames + [''.join(formatted_exception[0])]]
984 # return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
951
985 return [head] + frames + [''.join(exception[0])]
952 def get_records(self, etb, number_of_lines_of_context, tb_offset):
953 try:
954 # Try the default getinnerframes and Alex's: Alex's fixes some
955 # problems, but it generates empty tracebacks for console errors
956 # (5 blanks lines) where none should be returned.
957 return _fixed_getinnerframes(etb, number_of_lines_of_context, tb_offset)
958 except:
959 # FIXME: I've been getting many crash reports from python 2.3
960 # users, traceable to inspect.py. If I can find a small test-case
961 # to reproduce this, I should either write a better workaround or
962 # file a bug report against inspect (if that's the real problem).
963 # So far, I haven't been able to find an isolated example to
964 # reproduce the problem.
965 inspect_error()
966 traceback.print_exc(file=self.ostream)
967 info('\nUnfortunately, your original traceback can not be constructed.\n')
968 return None
969
970 def get_parts_of_chained_exception(self, evalue):
971 def get_chained_exception(exception_value):
972 cause = getattr(exception_value, '__cause__', None)
973 if cause:
974 return cause
975 return getattr(exception_value, '__context__', None)
976
977 chained_evalue = get_chained_exception(evalue)
978
979 if chained_evalue:
980 return chained_evalue.__class__, chained_evalue, chained_evalue.__traceback__
981
982 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
983 number_of_lines_of_context=5):
984 """Return a nice text document describing the traceback."""
985
986 formatted_exception = self.format_exception_as_a_whole(etype, evalue, etb, number_of_lines_of_context,
987 tb_offset)
988
989 colors = self.Colors # just a shorthand + quicker name lookup
990 colorsnormal = colors.Normal # used a lot
991 head = '%s%s%s' % (colors.topline, '-' * 75, colorsnormal)
992 structured_traceback_parts = [head]
993 if py3compat.PY3:
994 chained_exceptions_tb_offset = 0
995 lines_of_context = 3
996 formatted_exceptions = formatted_exception
997 exception = self.get_parts_of_chained_exception(evalue)
998 if exception:
999 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
1000 etype, evalue, etb = exception
1001 else:
1002 evalue = None
1003 while evalue:
1004 formatted_exceptions += self.format_exception_as_a_whole(etype, evalue, etb, lines_of_context,
1005 chained_exceptions_tb_offset)
1006 exception = self.get_parts_of_chained_exception(evalue)
1007
1008 if exception:
1009 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
1010 etype, evalue, etb = exception
1011 else:
1012 evalue = None
1013
1014 # we want to see exceptions in a reversed order:
1015 # the first exception should be on top
1016 for formatted_exception in reversed(formatted_exceptions):
1017 structured_traceback_parts += formatted_exception
1018 else:
1019 structured_traceback_parts += formatted_exception[0]
1020
1021 return structured_traceback_parts
986
1022
987 def debugger(self,force=False):
1023 def debugger(self, force=False):
988 """Call up the pdb debugger if desired, always clean up the tb
1024 """Call up the pdb debugger if desired, always clean up the tb
@@ -1050,6 +1086,7 b' class VerboseTB(TBTools):'
1050 except KeyboardInterrupt:
1086 except KeyboardInterrupt:
1051 print("\nKeyboardInterrupt")
1087 print("\nKeyboardInterrupt")
1052
1088
1089
1053 #----------------------------------------------------------------------------
1090 #----------------------------------------------------------------------------
1054 class FormattedTB(VerboseTB, ListTB):
1091 class FormattedTB(VerboseTB, ListTB):
1055 """Subclass ListTB but allow calling with a traceback.
1092 """Subclass ListTB but allow calling with a traceback.
@@ -1089,13 +1126,13 b' class FormattedTB(VerboseTB, ListTB):'
1089 else:
1126 else:
1090 return None
1127 return None
1091
1128
1092 def structured_traceback(self, etype, value, tb, tb_offset=None, context=5):
1129 def structured_traceback(self, etype, value, tb, tb_offset=None, number_of_lines_of_context=5):
1093 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1130 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1094 mode = self.mode
1131 mode = self.mode
1095 if mode in self.verbose_modes:
1132 if mode in self.verbose_modes:
1096 # Verbose modes need a full traceback
1133 # Verbose modes need a full traceback
1097 return VerboseTB.structured_traceback(
1134 return VerboseTB.structured_traceback(
1098 self, etype, value, tb, tb_offset, context
1135 self, etype, value, tb, tb_offset, number_of_lines_of_context
1099 )
1136 )
1100 else:
1137 else:
1101 # We must check the source cache because otherwise we can print
1138 # We must check the source cache because otherwise we can print
@@ -1104,7 +1141,7 b' class FormattedTB(VerboseTB, ListTB):'
1104 # Now we can extract and format the exception
1141 # Now we can extract and format the exception
1105 elist = self._extract_tb(tb)
1142 elist = self._extract_tb(tb)
1106 return ListTB.structured_traceback(
1143 return ListTB.structured_traceback(
1107 self, etype, value, elist, tb_offset, context
1144 self, etype, value, elist, tb_offset, number_of_lines_of_context
1108 )
1145 )
1109
1146
1110 def stb2text(self, stb):
1147 def stb2text(self, stb):
@@ -1131,7 +1168,7 b' class FormattedTB(VerboseTB, ListTB):'
1131 # Set the join character for generating text tracebacks
1168 # Set the join character for generating text tracebacks
1132 self.tb_join_char = self._join_chars[self.mode]
1169 self.tb_join_char = self._join_chars[self.mode]
1133
1170
1134 # some convenient shorcuts
1171 # some convenient shortcuts
1135 def plain(self):
1172 def plain(self):
1136 self.set_mode(self.valid_modes[0])
1173 self.set_mode(self.valid_modes[0])
1137
1174
@@ -1141,6 +1178,7 b' class FormattedTB(VerboseTB, ListTB):'
1141 def verbose(self):
1178 def verbose(self):
1142 self.set_mode(self.valid_modes[2])
1179 self.set_mode(self.valid_modes[2])
1143
1180
1181
1144 #----------------------------------------------------------------------------
1182 #----------------------------------------------------------------------------
1145 class AutoFormattedTB(FormattedTB):
1183 class AutoFormattedTB(FormattedTB):
1146 """A traceback printer which can be called on the fly.
1184 """A traceback printer which can be called on the fly.
@@ -1167,7 +1205,6 b' class AutoFormattedTB(FormattedTB):'
1167 per-call basis (this overrides temporarily the instance's tb_offset
1205 per-call basis (this overrides temporarily the instance's tb_offset
1168 given at initialization time. """
1206 given at initialization time. """
1169
1207
1170
1171 if out is None:
1208 if out is None:
1172 out = self.ostream
1209 out = self.ostream
1173 out.flush()
1210 out.flush()
@@ -1182,18 +1219,20 b' class AutoFormattedTB(FormattedTB):'
1182 print("\nKeyboardInterrupt")
1219 print("\nKeyboardInterrupt")
1183
1220
1184 def structured_traceback(self, etype=None, value=None, tb=None,
1221 def structured_traceback(self, etype=None, value=None, tb=None,
1185 tb_offset=None, context=5):
1222 tb_offset=None, number_of_lines_of_context=5):
1186 if etype is None:
1223 if etype is None:
1187 etype,value,tb = sys.exc_info()
1224 etype, value, tb = sys.exc_info()
1188 self.tb = tb
1225 self.tb = tb
1189 return FormattedTB.structured_traceback(
1226 return FormattedTB.structured_traceback(
1190 self, etype, value, tb, tb_offset, context)
1227 self, etype, value, tb, tb_offset, number_of_lines_of_context)
1228
1191
1229
1192 #---------------------------------------------------------------------------
1230 #---------------------------------------------------------------------------
1193
1231
1194 # A simple class to preserve Nathan's original functionality.
1232 # A simple class to preserve Nathan's original functionality.
1195 class ColorTB(FormattedTB):
1233 class ColorTB(FormattedTB):
1196 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1234 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1235
1197 def __init__(self,color_scheme='Linux',call_pdb=0):
1236 def __init__(self, color_scheme='Linux', call_pdb=0):
1198 FormattedTB.__init__(self,color_scheme=color_scheme,
1237 FormattedTB.__init__(self, color_scheme=color_scheme,
1199 call_pdb=call_pdb)
1238 call_pdb=call_pdb)
@@ -1208,6 +1247,7 b' class SyntaxTB(ListTB):'
1208
1247
1209 def __call__(self, etype, value, elist):
1248 def __call__(self, etype, value, elist):
1210 self.last_syntax_error = value
1249 self.last_syntax_error = value
1250
1211 ListTB.__call__(self,etype,value,elist)
1251 ListTB.__call__(self, etype, value, elist)
1212
1252
1213 def structured_traceback(self, etype, value, elist, tb_offset=None,
1253 def structured_traceback(self, etype, value, elist, tb_offset=None,
@@ -1236,7 +1276,46 b' class SyntaxTB(ListTB):'
1236 return ''.join(stb)
1276 return ''.join(stb)
1237
1277
1238
1278
1279 # some internal-use functions
1280 def text_repr(value):
1281 """Hopefully pretty robust repr equivalent."""
1282 # this is pretty horrible but should always return *something*
1283 try:
1284 return pydoc.text.repr(value)
1285 except KeyboardInterrupt:
1286 raise
1287 except:
1288 try:
1289 return repr(value)
1290 except KeyboardInterrupt:
1291 raise
1292 except:
1293 try:
1294 # all still in an except block so we catch
1295 # getattr raising
1296 name = getattr(value, '__name__', None)
1297 if name:
1298 # ick, recursion
1299 return text_repr(name)
1300 klass = getattr(value, '__class__', None)
1301 if klass:
1302 return '%s instance' % text_repr(klass)
1303 except KeyboardInterrupt:
1304 raise
1305 except:
1306 return 'UNRECOVERABLE REPR FAILURE'
1307
1308
1309 def eqrepr(value, repr=text_repr):
1310 return '=%s' % repr(value)
1311
1312
1313 def nullrepr(value, repr=text_repr):
1314 return ''
1315
1316
1239 #----------------------------------------------------------------------------
1317 #----------------------------------------------------------------------------
1318
1240 # module testing (minimal)
1319 # module testing (minimal)
1241 if __name__ == "__main__":
1320 if __name__ == "__main__":
1242 def spam(c, d_e):
1321 def spam(c, d_e):
@@ -1,6 +1,7 b''
1 {
1 {
2 "metadata": {
2 "metadata": {
3 "name": ""
3 "name": "",
4 "signature": "sha256:9d47889f0678e9685429071216d0f3354db59bb66489f3225bcadfb6a1a9bbba"
4 },
5 },
5 "nbformat": 3,
6 "nbformat": 3,
6 "nbformat_minor": 0,
7 "nbformat_minor": 0,
@@ -21,7 +22,8 b''
21 "evalue": "message",
22 "evalue": "message",
22 "output_type": "pyerr",
23 "output_type": "pyerr",
23 "traceback": [
24 "traceback": [
24 "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[1;31mException\u001b[0m Traceback (most recent call last)",
25 "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
26 "\u001b[1;31mException\u001b[0m Traceback (most recent call last)",
25 "\u001b[1;32m<ipython-input-1-335814d14fc1>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[1;32mraise\u001b[0m \u001b[0mException\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"message\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
27 "\u001b[1;32m<ipython-input-1-335814d14fc1>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[1;32mraise\u001b[0m \u001b[0mException\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"message\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
26 "\u001b[1;31mException\u001b[0m: message"
28 "\u001b[1;31mException\u001b[0m: message"
27 ]
29 ]
General Comments 0
You need to be logged in to leave comments. Login now