Index: Lib/traceback.py =================================================================== --- Lib/traceback.py (revision 66701) +++ Lib/traceback.py (working copy) @@ -148,7 +148,7 @@ """ if file is None: file = sys.stderr - if chain: + if chain and value is not None: values = _iter_chain(value, tb) else: values = [(value, tb)] @@ -160,9 +160,8 @@ _print(file, 'Traceback (most recent call last):') print_tb(tb, limit, file) lines = format_exception_only(type(value), value) - for line in lines[:-1]: - _print(file, line, ' ') - _print(file, lines[-1], '') + for line in lines: + _print(file, line, '') def format_exception(etype, value, tb, limit=None, chain=True): """Format a stack trace and the exception information. @@ -174,7 +173,7 @@ printed as does print_exception(). """ list = [] - if chain: + if chain and value is not None: values = _iter_chain(value, tb) else: values = [(value, tb)] @@ -206,8 +205,8 @@ """ # Gracefully handle (the way Python 2.4 and earlier did) the case of # being called with (None, None). - if etype is None: - return [_format_final_exc_line(etype, value)] + if etype is None or etype is type(None): + return [_format_final_exc_line(None, value)] stype = etype.__name__ smod = etype.__module__ @@ -227,7 +226,10 @@ if badline is not None: lines.append(' %s\n' % badline.strip()) if offset is not None: - caretspace = badline[:offset].lstrip() + # The offset counts utf-8 bytes positions + badline = badline.encode('utf-8')[:offset].decode('utf-8') + offset = len(badline) + caretspace = badline.lstrip() # non-space whitespace (likes tabs) must be kept for alignment caretspace = ((c.isspace() and c or ' ') for c in caretspace) # only three spaces to account for offset1 == pos 0 Index: Lib/test/test_traceback.py =================================================================== --- Lib/test/test_traceback.py (revision 66701) +++ Lib/test/test_traceback.py (working copy) @@ -89,6 +89,12 @@ def test_without_exception(self): err = traceback.format_exception_only(None, None) self.assertEqual(err, ['None\n']) + err = traceback.format_exception(None, None, None) + self.assertEqual(err, ['None\n']) + with captured_output("stderr") as sio: + traceback.print_exception(None, None, None) + err = sio.getvalue() + self.assertEqual(err, 'None\n') class TracebackFormatTests(unittest.TestCase): @@ -197,8 +203,19 @@ self.assert_('inner_raise() # Marker' in blocks[2]) self.check_zero_div(blocks[2]) + def test_caret_multibyte(self): + try: + compile("caf\xe9! = 3", "?", "exec") + except SyntaxError as e: + exc = e + err = self.get_report(exc).splitlines() + self.assertEqual(len(err), 7) + self.assertEqual(err[4].strip(), "caf\xe9! = 3") + self.assert_("^" in err[5]) + self.assertEqual(err[4].find("!"), err[5].find("^")) + class PyExcReportingTests(BaseExceptionReportingTests, unittest.TestCase): # # This checks reporting through the 'traceback' module, with both