##// END OF EJS Templates
i1673 implementation of py3 proper error handling...
Justyna Ilczuk -
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
@@ -262,7 +262,6 b' def _fixed_getinnerframes(etb, context=1, tb_offset=0):'
262 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
262 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
263
263
264 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
264 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
265
266 # 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
267 # 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
268 # console)
267 # console)
@@ -274,6 +273,15 b' def _fixed_getinnerframes(etb, context=1, tb_offset=0):'
274 except IndexError:
273 except IndexError:
275 pass
274 pass
276
275
276 # we don't want to truncate too much
277 # when normal exception occurs there are two records usually
278 # first is from ipython and has pre_hooks information and so on
279 # however sometimes we have tracebacks without additional ipython information
280 # for example from nested traceback (python3 exceptions have __context__ which
281 # stores information about previous exceptions)
282 if tb_offset >= len(records):
283 tb_offset = len(records) - 2
284
277 aux = traceback.extract_tb(etb)
285 aux = traceback.extract_tb(etb)
278 assert len(records) == len(aux)
286 assert len(records) == len(aux)
279 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
287 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
@@ -516,7 +524,7 b' class ListTB(TBTools):'
516 ## out_list.append(lines[-1])
524 ## out_list.append(lines[-1])
517
525
518 # This means it was indenting everything but the last line by a little
526 # This means it was indenting everything but the last line by a little
519 # bit. I've disabled this for now, but if we see ugliness somewhre we
527 # bit. I've disabled this for now, but if we see ugliness somewhere we
520 # can restore it.
528 # can restore it.
521
529
522 return out_list
530 return out_list
@@ -556,7 +564,6 b' class ListTB(TBTools):'
556 item += '%s %s%s\n' % (Colors.line, line.strip(),
564 item += '%s %s%s\n' % (Colors.line, line.strip(),
557 Colors.Normal)
565 Colors.Normal)
558 list.append(item)
566 list.append(item)
559 #from pprint import pformat; print 'LISTTB', pformat(list) # dbg
560 return list
567 return list
561
568
562 def _format_exception_only(self, etype, value):
569 def _format_exception_only(self, etype, value):
@@ -582,7 +589,6 b' class ListTB(TBTools):'
582 else:
589 else:
583 if issubclass(etype, SyntaxError):
590 if issubclass(etype, SyntaxError):
584 have_filedata = True
591 have_filedata = True
585 #print 'filename is',filename # dbg
586 if not value.filename: value.filename = "<string>"
592 if not value.filename: value.filename = "<string>"
587 if value.lineno:
593 if value.lineno:
588 lineno = value.lineno
594 lineno = value.lineno
@@ -697,107 +703,14 b' class VerboseTB(TBTools):'
697 check_cache = linecache.checkcache
703 check_cache = linecache.checkcache
698 self.check_cache = check_cache
704 self.check_cache = check_cache
699
705
700 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
706 def format_records(self, records):
701 context=5):
702 """Return a nice text document describing the traceback."""
703
704 tb_offset = self.tb_offset if tb_offset is None else tb_offset
705
706 # some locals
707 try:
708 etype = etype.__name__
709 except AttributeError:
710 pass
711 Colors = self.Colors # just a shorthand + quicker name lookup
707 Colors = self.Colors # just a shorthand + quicker name lookup
712 ColorsNormal = Colors.Normal # used a lot
708 ColorsNormal = Colors.Normal # used a lot
713 col_scheme = self.color_scheme_table.active_scheme_name
709 col_scheme = self.color_scheme_table.active_scheme_name
714 indent = ' ' * INDENT_SIZE
710 indent = ' ' * INDENT_SIZE
715 em_normal = '%s\n%s%s' % (Colors.valEm, indent, ColorsNormal)
711 em_normal = '%s\n%s%s' % (Colors.valEm, indent, ColorsNormal)
716 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
712 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
717 exc = '%s%s%s' % (Colors.excName, etype, ColorsNormal)
718
719 # some internal-use functions
720 def text_repr(value):
721 """Hopefully pretty robust repr equivalent."""
722 # this is pretty horrible but should always return *something*
723 try:
724 return pydoc.text.repr(value)
725 except KeyboardInterrupt:
726 raise
727 except:
728 try:
729 return repr(value)
730 except KeyboardInterrupt:
731 raise
732 except:
733 try:
734 # all still in an except block so we catch
735 # getattr raising
736 name = getattr(value, '__name__', None)
737 if name:
738 # ick, recursion
739 return text_repr(name)
740 klass = getattr(value, '__class__', None)
741 if klass:
742 return '%s instance' % text_repr(klass)
743 except KeyboardInterrupt:
744 raise
745 except:
746 return 'UNRECOVERABLE REPR FAILURE'
747
748 def eqrepr(value, repr=text_repr):
749 return '=%s' % repr(value)
750
751 def nullrepr(value, repr=text_repr):
752 return ''
753
754 # meat of the code begins
755 try:
756 etype = etype.__name__
757 except AttributeError:
758 pass
759
760 if self.long_header:
761 # Header with the exception type, python version, and date
762 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
763 date = time.ctime(time.time())
764
765 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-' * 75, ColorsNormal,
766 exc, ' ' * (75 - len(str(etype)) - len(pyver)),
767 pyver, date.rjust(75) )
768 head += "\nA problem occured executing Python code. Here is the sequence of function" \
769 "\ncalls leading up to the error, with the most recent (innermost) call last."
770 else:
771 # Simplified header
772 head = '%s%s%s\n%s%s' % (Colors.topline, '-' * 75, ColorsNormal, exc,
773 'Traceback (most recent call last)'. \
774 rjust(75 - len(str(etype))) )
775 frames = []
713 frames = []
776 # Flush cache before calling inspect. This helps alleviate some of the
777 # problems with python 2.3's inspect.py.
778 ##self.check_cache()
779 # Drop topmost frames if requested
780 try:
781 # Try the default getinnerframes and Alex's: Alex's fixes some
782 # problems, but it generates empty tracebacks for console errors
783 # (5 blanks lines) where none should be returned.
784 #records = inspect.getinnerframes(etb, context)[tb_offset:]
785 #print 'python records:', records # dbg
786 records = _fixed_getinnerframes(etb, context, tb_offset)
787 #print 'alex records:', records # dbg
788 except:
789
790 # FIXME: I've been getting many crash reports from python 2.3
791 # users, traceable to inspect.py. If I can find a small test-case
792 # to reproduce this, I should either write a better workaround or
793 # file a bug report against inspect (if that's the real problem).
794 # So far, I haven't been able to find an isolated example to
795 # reproduce the problem.
796 inspect_error()
797 traceback.print_exc(file=self.ostream)
798 info('\nUnfortunately, your original traceback can not be constructed.\n')
799 return ''
800
801 # build some color string templates outside these nested loops
714 # build some color string templates outside these nested loops
802 tpl_link = '%s%%s%s' % (Colors.filenameEm, ColorsNormal)
715 tpl_link = '%s%%s%s' % (Colors.filenameEm, ColorsNormal)
803 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
716 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
@@ -808,11 +721,11 b' class VerboseTB(TBTools):'
808 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
721 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
809 Colors.vName, ColorsNormal)
722 Colors.vName, ColorsNormal)
810 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
723 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
724
811 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
725 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
812 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm, Colors.line,
726 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm, Colors.line,
813 ColorsNormal)
727 ColorsNormal)
814
728
815 # now, loop over all records printing context and info
816 abspath = os.path.abspath
729 abspath = os.path.abspath
817 for frame, file, lnum, func, lines, index in records:
730 for frame, file, lnum, func, lines, index in records:
818 #print '*** record:',file,lnum,func,lines,index # dbg
731 #print '*** record:',file,lnum,func,lines,index # dbg
@@ -953,6 +866,47 b' class VerboseTB(TBTools):'
953 _format_traceback_lines(lnum, index, lines, Colors, lvals,
866 _format_traceback_lines(lnum, index, lines, Colors, lvals,
954 col_scheme))))
867 col_scheme))))
955
868
869 return frames
870
871 def prepare_chained_exception_message(self, cause):
872 direct_cause = "\nThe above exception was the direct cause of the following exception:\n"
873 exception_during_handling = "\nDuring handling of the above exception, another exception occurred:\n"
874
875 colors = self.Colors # just a shorthand + quicker name lookup
876 colorsnormal = colors.Normal # used a lot
877 head = '%s%s%s' % (colors.topline, '-' * 75, colorsnormal)
878 if cause:
879 message = [[head, direct_cause]]
880 else:
881 message = [[head, exception_during_handling]]
882 return message
883
884 def prepare_header(self, etype, long_version=False):
885 colors = self.Colors # just a shorthand + quicker name lookup
886 colorsnormal = colors.Normal # used a lot
887 exc = '%s%s%s' % (colors.excName, etype, colorsnormal)
888 if long_version:
889 # Header with the exception type, python version, and date
890 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
891 date = time.ctime(time.time())
892
893 head = '%s%s%s\n%s%s%s\n%s' % (colors.topline, '-' * 75, colorsnormal,
894 exc, ' ' * (75 - len(str(etype)) - len(pyver)),
895 pyver, date.rjust(75) )
896 head += "\nA problem occurred executing Python code. Here is the sequence of function" \
897 "\ncalls leading up to the error, with the most recent (innermost) call last."
898 else:
899 # Simplified header
900 head = '%s%s%s\n%s%s' % (colors.topline, '-' * 75, colorsnormal, exc,
901 'Traceback (most recent call last)'. \
902 rjust(75 - len(str(etype))) )
903
904 return head
905
906 def format_exception(self, etype, evalue):
907 colors = self.Colors # just a shorthand + quicker name lookup
908 colorsnormal = colors.Normal # used a lot
909 indent = ' ' * INDENT_SIZE
956 # Get (safely) a string form of the exception info
910 # Get (safely) a string form of the exception info
957 try:
911 try:
958 etype_str, evalue_str = map(str, (etype, evalue))
912 etype_str, evalue_str = map(str, (etype, evalue))
@@ -961,38 +915,119 b' class VerboseTB(TBTools):'
961 etype, evalue = str, sys.exc_info()[:2]
915 etype, evalue = str, sys.exc_info()[:2]
962 etype_str, evalue_str = map(str, (etype, evalue))
916 etype_str, evalue_str = map(str, (etype, evalue))
963 # ... and format it
917 # ... and format it
964 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
918 exception = ['%s%s%s: %s' % (colors.excName, etype_str,
965 ColorsNormal, py3compat.cast_unicode(evalue_str))]
919 colorsnormal, py3compat.cast_unicode(evalue_str))]
920
966 if (not py3compat.PY3) and type(evalue) is types.InstanceType:
921 if (not py3compat.PY3) and type(evalue) is types.InstanceType:
967 try:
922 try:
968 names = [w for w in dir(evalue) if isinstance(w, py3compat.string_types)]
923 names = [w for w in dir(evalue) if isinstance(w, py3compat.string_types)]
969 except:
924 except:
970 # Every now and then, an object with funny inernals blows up
925 # Every now and then, an object with funny internals blows up
971 # when dir() is called on it. We do the best we can to report
926 # when dir() is called on it. We do the best we can to report
972 # the problem and continue
927 # the problem and continue
973 _m = '%sException reporting error (object with broken dir())%s:'
928 _m = '%sException reporting error (object with broken dir())%s:'
974 exception.append(_m % (Colors.excName, ColorsNormal))
929 exception.append(_m % (colors.excName, colorsnormal))
975 etype_str, evalue_str = map(str, sys.exc_info()[:2])
930 etype_str, evalue_str = map(str, sys.exc_info()[:2])
976 exception.append('%s%s%s: %s' % (Colors.excName, etype_str,
931 exception.append('%s%s%s: %s' % (colors.excName, etype_str,
977 ColorsNormal, py3compat.cast_unicode(evalue_str)))
932 colorsnormal, py3compat.cast_unicode(evalue_str)))
978 names = []
933 names = []
979 for name in names:
934 for name in names:
980 value = text_repr(getattr(evalue, name))
935 value = text_repr(getattr(evalue, name))
981 exception.append('\n%s%s = %s' % (indent, name, value))
936 exception.append('\n%s%s = %s' % (indent, name, value))
937 return exception
938
939 def get_records(self, etb, number_of_lines_of_context, tb_offset):
940 try:
941 # Try the default getinnerframes and Alex's: Alex's fixes some
942 # problems, but it generates empty tracebacks for console errors
943 # (5 blanks lines) where none should be returned.
944 return _fixed_getinnerframes(etb, number_of_lines_of_context, tb_offset)
945 except:
946
947 # FIXME: I've been getting many crash reports from python 2.3
948 # users, traceable to inspect.py. If I can find a small test-case
949 # to reproduce this, I should either write a better workaround or
950 # file a bug report against inspect (if that's the real problem).
951 # So far, I haven't been able to find an isolated example to
952 # reproduce the problem.
953 inspect_error()
954 traceback.print_exc(file=self.ostream)
955 info('\nUnfortunately, your original traceback can not be constructed.\n')
956 return None
957
958 def get_exception_from_context(self, evalue):
959 if hasattr(evalue, '__context__'): # and not evalue.__suppress_context__:
960 context = evalue.__context__
961 if not context:
962 return None
963 else:
964 exception_traceback = context.__traceback__
965 exception_type = context.__class__.__name__
966 return exception_type, context, exception_traceback
967 else:
968 return None
969
970 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
971 number_of_lines_of_context=5):
972 """Return a nice text document describing the traceback."""
973 tb_offset = self.tb_offset if tb_offset is None else tb_offset
974
975 # some locals
976 try:
977 etype = etype.__name__
978 except AttributeError:
979 pass
980
981 structured_traceback_parts = []
982
983 exceptions = []
984 current_exception_value = evalue
985 if py3compat.PY3:
986 while current_exception_value:
987 head = self.prepare_header(etype, self.long_header)
988 records = self.get_records(etb, number_of_lines_of_context, tb_offset)
989
990 frames = self.format_records(records)
991 if records is None:
992 return ""
993
994 formatted_exception = self.format_exception(etype, current_exception_value)
995 if records:
996 filepath, lnum = records[-1][1:3]
997 filepath = os.path.abspath(filepath)
998 ipinst = get_ipython()
999 if ipinst is not None:
1000 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
1001
1002 exceptions += [[head] + frames + [''.join(formatted_exception[0])]]
982
1003
983 # vds: >>
1004 exception = self.get_exception_from_context(current_exception_value)
1005 if exception:
1006 exceptions += self.prepare_chained_exception_message(current_exception_value.__cause__)
1007 etype, current_exception_value, etb = exception
1008 else:
1009 break
1010
1011 for exception in reversed(exceptions):
1012 structured_traceback_parts += exception
1013 else:
1014 head = self.prepare_header(etype, self.long_header)
1015 records = self.get_records(etb, number_of_lines_of_context, tb_offset)
1016
1017 frames = self.format_records(records)
1018 if records is None:
1019 return ""
1020
1021 exception = self.format_exception(etype, evalue)
984 if records:
1022 if records:
985 filepath, lnum = records[-1][1:3]
1023 filepath, lnum = records[-1][1:3]
986 #print "file:", str(file), "linenb", str(lnum) # dbg
987 filepath = os.path.abspath(filepath)
1024 filepath = os.path.abspath(filepath)
988 ipinst = get_ipython()
1025 ipinst = get_ipython()
989 if ipinst is not None:
1026 if ipinst is not None:
990 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
1027 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
991 # vds: <<
1028 structured_traceback_parts.append([head] + frames + [''.join(exception[0])])
992
1029
993 # return all our info assembled as a single string
1030 return structured_traceback_parts
994 # return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
995 return [head] + frames + [''.join(exception[0])]
996
1031
997 def debugger(self, force=False):
1032 def debugger(self, force=False):
998 """Call up the pdb debugger if desired, always clean up the tb
1033 """Call up the pdb debugger if desired, always clean up the tb
@@ -1100,13 +1135,13 b' class FormattedTB(VerboseTB, ListTB):'
1100 else:
1135 else:
1101 return None
1136 return None
1102
1137
1103 def structured_traceback(self, etype, value, tb, tb_offset=None, context=5):
1138 def structured_traceback(self, etype, value, tb, tb_offset=None, number_of_lines_of_context=5):
1104 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1139 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1105 mode = self.mode
1140 mode = self.mode
1106 if mode in self.verbose_modes:
1141 if mode in self.verbose_modes:
1107 # Verbose modes need a full traceback
1142 # Verbose modes need a full traceback
1108 return VerboseTB.structured_traceback(
1143 return VerboseTB.structured_traceback(
1109 self, etype, value, tb, tb_offset, context
1144 self, etype, value, tb, tb_offset, number_of_lines_of_context
1110 )
1145 )
1111 else:
1146 else:
1112 # We must check the source cache because otherwise we can print
1147 # We must check the source cache because otherwise we can print
@@ -1115,7 +1150,7 b' class FormattedTB(VerboseTB, ListTB):'
1115 # Now we can extract and format the exception
1150 # Now we can extract and format the exception
1116 elist = self._extract_tb(tb)
1151 elist = self._extract_tb(tb)
1117 return ListTB.structured_traceback(
1152 return ListTB.structured_traceback(
1118 self, etype, value, elist, tb_offset, context
1153 self, etype, value, elist, tb_offset, number_of_lines_of_context
1119 )
1154 )
1120
1155
1121 def stb2text(self, stb):
1156 def stb2text(self, stb):
@@ -1193,12 +1228,12 b' class AutoFormattedTB(FormattedTB):'
1193 print("\nKeyboardInterrupt")
1228 print("\nKeyboardInterrupt")
1194
1229
1195 def structured_traceback(self, etype=None, value=None, tb=None,
1230 def structured_traceback(self, etype=None, value=None, tb=None,
1196 tb_offset=None, context=5):
1231 tb_offset=None, number_of_lines_of_context=5):
1197 if etype is None:
1232 if etype is None:
1198 etype, value, tb = sys.exc_info()
1233 etype, value, tb = sys.exc_info()
1199 self.tb = tb
1234 self.tb = tb
1200 return FormattedTB.structured_traceback(
1235 return FormattedTB.structured_traceback(
1201 self, etype, value, tb, tb_offset, context)
1236 self, etype, value, tb, tb_offset, number_of_lines_of_context)
1202
1237
1203
1238
1204 #---------------------------------------------------------------------------
1239 #---------------------------------------------------------------------------
@@ -1221,6 +1256,7 b' class SyntaxTB(ListTB):'
1221
1256
1222 def __call__(self, etype, value, elist):
1257 def __call__(self, etype, value, elist):
1223 self.last_syntax_error = value
1258 self.last_syntax_error = value
1259
1224 ListTB.__call__(self, etype, value, elist)
1260 ListTB.__call__(self, etype, value, elist)
1225
1261
1226 def structured_traceback(self, etype, value, elist, tb_offset=None,
1262 def structured_traceback(self, etype, value, elist, tb_offset=None,
@@ -1249,7 +1285,48 b' class SyntaxTB(ListTB):'
1249 return ''.join(stb)
1285 return ''.join(stb)
1250
1286
1251
1287
1288 # some internal-use functions
1289 def text_repr(value):
1290 """Hopefully pretty robust repr equivalent."""
1291 # this is pretty horrible but should always return *something*
1292 try:
1293 return pydoc.text.repr(value)
1294 except KeyboardInterrupt:
1295 raise
1296 except:
1297 try:
1298 return repr(value)
1299 except KeyboardInterrupt:
1300 raise
1301 except:
1302 try:
1303 # all still in an except block so we catch
1304 # getattr raising
1305 name = getattr(value, '__name__', None)
1306 if name:
1307 # ick, recursion
1308 return text_repr(name)
1309 klass = getattr(value, '__class__', None)
1310 if klass:
1311 return '%s instance' % text_repr(klass)
1312 except KeyboardInterrupt:
1313 raise
1314 except:
1315 return 'UNRECOVERABLE REPR FAILURE'
1316
1317
1318 def eqrepr(value, repr=text_repr):
1319 return '=%s' % repr(value)
1320
1321
1322 def nullrepr(value, repr=text_repr):
1323 return ''
1324
1325
1326
1327
1252 #----------------------------------------------------------------------------
1328 #----------------------------------------------------------------------------
1329
1253 # module testing (minimal)
1330 # module testing (minimal)
1254 if __name__ == "__main__":
1331 if __name__ == "__main__":
1255 def spam(c, d_e):
1332 def spam(c, d_e):
General Comments 0
You need to be logged in to leave comments. Login now