mirror of
https://github.com/python/cpython.git
synced 2025-07-31 23:23:11 +00:00
Patch #1515343: Fix printing of deprecated string exceptions with a
value in the traceback module.
This commit is contained in:
parent
844f7ddcdc
commit
c13c34c39d
3 changed files with 93 additions and 46 deletions
|
@ -31,8 +31,9 @@ class TracebackCases(unittest.TestCase):
|
||||||
err = self.get_exception_format(self.syntax_error_with_caret,
|
err = self.get_exception_format(self.syntax_error_with_caret,
|
||||||
SyntaxError)
|
SyntaxError)
|
||||||
self.assert_(len(err) == 4)
|
self.assert_(len(err) == 4)
|
||||||
self.assert_("^" in err[2]) # third line has caret
|
|
||||||
self.assert_(err[1].strip() == "return x!")
|
self.assert_(err[1].strip() == "return x!")
|
||||||
|
self.assert_("^" in err[2]) # third line has caret
|
||||||
|
self.assert_(err[1].find("!") == err[2].find("^")) # in the right place
|
||||||
|
|
||||||
def test_nocaret(self):
|
def test_nocaret(self):
|
||||||
if is_jython:
|
if is_jython:
|
||||||
|
@ -47,8 +48,9 @@ class TracebackCases(unittest.TestCase):
|
||||||
err = self.get_exception_format(self.syntax_error_bad_indentation,
|
err = self.get_exception_format(self.syntax_error_bad_indentation,
|
||||||
IndentationError)
|
IndentationError)
|
||||||
self.assert_(len(err) == 4)
|
self.assert_(len(err) == 4)
|
||||||
self.assert_("^" in err[2])
|
|
||||||
self.assert_(err[1].strip() == "print 2")
|
self.assert_(err[1].strip() == "print 2")
|
||||||
|
self.assert_("^" in err[2])
|
||||||
|
self.assert_(err[1].find("2") == err[2].find("^"))
|
||||||
|
|
||||||
def test_bug737473(self):
|
def test_bug737473(self):
|
||||||
import sys, os, tempfile, time
|
import sys, os, tempfile, time
|
||||||
|
@ -109,6 +111,36 @@ def test():
|
||||||
lst = traceback.format_exception_only(e.__class__, e)
|
lst = traceback.format_exception_only(e.__class__, e)
|
||||||
self.assertEqual(lst, ['KeyboardInterrupt\n'])
|
self.assertEqual(lst, ['KeyboardInterrupt\n'])
|
||||||
|
|
||||||
|
# String exceptions are deprecated, but legal. The quirky form with
|
||||||
|
# separate "type" and "value" tends to break things, because
|
||||||
|
# not isinstance(value, type)
|
||||||
|
# and a string cannot be the first argument to issubclass.
|
||||||
|
#
|
||||||
|
# Note that sys.last_type and sys.last_value do not get set if an
|
||||||
|
# exception is caught, so we sort of cheat and just emulate them.
|
||||||
|
#
|
||||||
|
# test_string_exception1 is equivalent to
|
||||||
|
#
|
||||||
|
# >>> raise "String Exception"
|
||||||
|
#
|
||||||
|
# test_string_exception2 is equivalent to
|
||||||
|
#
|
||||||
|
# >>> raise "String Exception", "String Value"
|
||||||
|
#
|
||||||
|
def test_string_exception1(self):
|
||||||
|
str_type = "String Exception"
|
||||||
|
err = traceback.format_exception_only(str_type, None)
|
||||||
|
self.assert_(len(err) == 1)
|
||||||
|
self.assert_(err[0] == str_type + '\n')
|
||||||
|
|
||||||
|
def test_string_exception2(self):
|
||||||
|
str_type = "String Exception"
|
||||||
|
str_value = "String Value"
|
||||||
|
err = traceback.format_exception_only(str_type, str_value)
|
||||||
|
self.assert_(len(err) == 1)
|
||||||
|
self.assert_(err[0] == str_type + ': ' + str_value + '\n')
|
||||||
|
|
||||||
|
|
||||||
def test_main():
|
def test_main():
|
||||||
run_unittest(TracebackCases)
|
run_unittest(TracebackCases)
|
||||||
|
|
||||||
|
|
100
Lib/traceback.py
100
Lib/traceback.py
|
@ -150,51 +150,63 @@ def format_exception_only(etype, value):
|
||||||
|
|
||||||
The arguments are the exception type and value such as given by
|
The arguments are the exception type and value such as given by
|
||||||
sys.last_type and sys.last_value. The return value is a list of
|
sys.last_type and sys.last_value. The return value is a list of
|
||||||
strings, each ending in a newline. Normally, the list contains a
|
strings, each ending in a newline.
|
||||||
single string; however, for SyntaxError exceptions, it contains
|
|
||||||
several lines that (when printed) display detailed information
|
|
||||||
about where the syntax error occurred. The message indicating
|
|
||||||
which exception occurred is the always last string in the list.
|
|
||||||
"""
|
|
||||||
list = []
|
|
||||||
if (type(etype) == types.ClassType
|
|
||||||
or (isinstance(etype, type) and issubclass(etype, BaseException))):
|
|
||||||
stype = etype.__name__
|
|
||||||
else:
|
|
||||||
stype = etype
|
|
||||||
if value is None:
|
|
||||||
list.append(str(stype) + '\n')
|
|
||||||
else:
|
|
||||||
if issubclass(etype, SyntaxError):
|
|
||||||
try:
|
|
||||||
msg, (filename, lineno, offset, line) = value
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
if not filename: filename = "<string>"
|
|
||||||
list.append(' File "%s", line %d\n' %
|
|
||||||
(filename, lineno))
|
|
||||||
if line is not None:
|
|
||||||
i = 0
|
|
||||||
while i < len(line) and line[i].isspace():
|
|
||||||
i = i+1
|
|
||||||
list.append(' %s\n' % line.strip())
|
|
||||||
if offset is not None:
|
|
||||||
s = ' '
|
|
||||||
for c in line[i:offset-1]:
|
|
||||||
if c.isspace():
|
|
||||||
s = s + c
|
|
||||||
else:
|
|
||||||
s = s + ' '
|
|
||||||
list.append('%s^\n' % s)
|
|
||||||
value = msg
|
|
||||||
s = _some_str(value)
|
|
||||||
if s:
|
|
||||||
list.append('%s: %s\n' % (str(stype), s))
|
|
||||||
else:
|
|
||||||
list.append('%s\n' % str(stype))
|
|
||||||
return list
|
|
||||||
|
|
||||||
|
Normally, the list contains a single string; however, for
|
||||||
|
SyntaxError exceptions, it contains several lines that (when
|
||||||
|
printed) display detailed information about where the syntax
|
||||||
|
error occurred.
|
||||||
|
|
||||||
|
The message indicating which exception occurred is always the last
|
||||||
|
string in the list.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# An instance should not have a meaningful value parameter, but
|
||||||
|
# sometimes does, particularly for string exceptions, such as
|
||||||
|
# >>> raise string1, string2 # deprecated
|
||||||
|
#
|
||||||
|
# Clear these out first because issubtype(string1, SyntaxError)
|
||||||
|
# would throw another exception and mask the original problem.
|
||||||
|
if (isinstance(etype, BaseException) or
|
||||||
|
isinstance(etype, types.InstanceType) or
|
||||||
|
type(etype) is str):
|
||||||
|
return [_format_final_exc_line(etype, value)]
|
||||||
|
|
||||||
|
stype = etype.__name__
|
||||||
|
|
||||||
|
if not issubclass(etype, SyntaxError):
|
||||||
|
return [_format_final_exc_line(stype, value)]
|
||||||
|
|
||||||
|
# It was a syntax error; show exactly where the problem was found.
|
||||||
|
try:
|
||||||
|
msg, (filename, lineno, offset, badline) = value
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
filename = filename or "<string>"
|
||||||
|
lines = [(' File "%s", line %d\n' % (filename, lineno))]
|
||||||
|
if badline is not None:
|
||||||
|
lines.append(' %s\n' % badline.strip())
|
||||||
|
if offset is not None:
|
||||||
|
caretspace = badline[:offset].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
|
||||||
|
lines.append(' %s^\n' % ''.join(caretspace))
|
||||||
|
value = msg
|
||||||
|
|
||||||
|
lines.append(_format_final_exc_line(stype, value))
|
||||||
|
return lines
|
||||||
|
|
||||||
|
def _format_final_exc_line(etype, value):
|
||||||
|
"""Return a list of a single line -- normal case for format_exception_only"""
|
||||||
|
if value is None or not str(value):
|
||||||
|
line = "%s\n" % etype
|
||||||
|
else:
|
||||||
|
line = "%s: %s\n" % (etype, _some_str(value))
|
||||||
|
return line
|
||||||
|
|
||||||
def _some_str(value):
|
def _some_str(value):
|
||||||
try:
|
try:
|
||||||
return str(value)
|
return str(value)
|
||||||
|
|
|
@ -39,6 +39,9 @@ Core and builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Patch #1515343: Fix printing of deprecated string exceptions with a
|
||||||
|
value in the traceback module.
|
||||||
|
|
||||||
- Resync optparse with Optik 1.5.3: minor tweaks for/to tests.
|
- Resync optparse with Optik 1.5.3: minor tweaks for/to tests.
|
||||||
|
|
||||||
- Patch #1524429: Use repr() instead of backticks in Tkinter again.
|
- Patch #1524429: Use repr() instead of backticks in Tkinter again.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue