Handle unicode paths more thoroughly.

Further testing exposed that we weren't decoding where we could, and
the SyntaxError special case needed to be updated too.
This commit is contained in:
Robert Collins 2015-03-09 19:54:59 +13:00
parent ffe9882743
commit 37c5f154f0
2 changed files with 94 additions and 6 deletions

View File

@ -164,6 +164,18 @@ def _some_str(value):
# --
def _some_fs_str(value):
"""_some_str, but for filesystem paths."""
if value is None:
return None
try:
if type(value) is bytes:
return value.decode(sys.getfilesystemencoding())
except:
pass
return _some_str(value)
def print_exc(limit=None, file=None, chain=True):
"""Shorthand for 'print_exception(*sys.exc_info(), limit, file)'."""
print_exception(*sys.exc_info(), limit=limit, file=file, chain=chain)
@ -380,7 +392,7 @@ class StackSummary(list):
for frame in self:
row = []
row.append(u(' File "{0}", line {1}, in {2}\n').format(
_some_str(frame.filename), frame.lineno, frame.name))
_some_fs_str(frame.filename), frame.lineno, frame.name))
if frame.line:
row.append(u(' {0}\n').format(frame.line.strip()))
if frame.locals:
@ -526,7 +538,7 @@ class TracebackException:
return
# It was a syntax error; show exactly where the problem was found.
filename = self.filename or u("<string>")
filename = _some_fs_str(self.filename) or u("<string>")
lineno = str(self.lineno) or u('?')
yield u(' File "{0}", line {1}\n').format(filename, lineno)

View File

@ -607,14 +607,26 @@ class TestStack(unittest.TestCase):
[' File "foo.py", line 1, in fred\n line\n'],
s.format())
@unittest.skipIf(sys.getfilesystemencoding()=='ANSI_X3.4-1968',
'Requires non-ascii fs encoding')
def test_format_unicode_filename(self):
# Filenames in Python2 may be bytestrings that will fail to implicit
# decode.
fname = u('\u5341').encode(sys.getfilesystemencoding())
s = traceback.StackSummary.from_list([(fname, 1, 'fred', 'line')])
self.assertEqual(
[u(' File "\u5341", line 1, in fred\n line\n')],
s.format())
def test_format_bad_filename(self):
# Filenames in Python2 may be bytestrings that will fail to implicit
# decode.
# This won't decode via the implicit(ascii) codec.
fname = u('\u5341').encode('shift-jis')
# This won't decode via the implicit(ascii) codec or the default
# fs encoding (unless the encoding is a wildcard encoding).
fname = b('\x8b')
s = traceback.StackSummary.from_list([(fname, 1, 'fred', 'line')])
self.assertEqual(
[' File "b\'\\x8f\\\\\'", line 1, in fred\n line\n'],
[' File "b\'\\x8b\'", line 1, in fred\n line\n'],
s.format())
def test_locals(self):
@ -639,7 +651,7 @@ class TestStack(unittest.TestCase):
traceback.walk_stack(None), capture_locals=True, limit=1)
s = some_inner(3, 4)
self.assertEqual(
[' File "' + FNAME + '", line 639, '
[' File "' + FNAME + '", line 651, '
'in some_inner\n'
' traceback.walk_stack(None), capture_locals=True, limit=1)\n'
' a = 1\n'
@ -821,3 +833,67 @@ class TestTracebackException(unittest.TestCase):
u(' ^\n'),
u('SyntaxError: uh oh\n')],
list(exc.format()))
@unittest.skipUnless(sys.version_info[0] < 3, "Applies to 2.x only.")
@unittest.skipIf(sys.getfilesystemencoding()=='ANSI_X3.4-1968',
'Requires non-ascii fs encoding')
def test_format_unicode_filename(self):
# Filenames in Python2 may be bytestrings that will fail to implicit
# decode.
fname = u('\u5341').encode(sys.getfilesystemencoding())
lines = u("1\n2\n3\n")
fake_module = dict(
__name__='fred',
__loader__=FakeLoader(lines)
)
linecache.updatecache(fname, fake_module)
e = SyntaxError("uh oh")
e.filename = fname
e.lineno = 2
e.text = b('something wrong')
e.offset = 1
c = test_code(fname, 'method')
f = test_frame(c, fake_module, {'something': 1})
tb = test_tb(f, 2, None)
exc = traceback.TracebackException(SyntaxError, e, tb)
list(exc.format_exception_only())
self.assertEqual([
u('Traceback (most recent call last):\n'),
u(' File "\u5341", line 2, in method\n 2\n'),
u(' File "\u5341", line 2\n'),
u(' something wrong\n'),
u(' ^\n'),
u('SyntaxError: uh oh\n')],
list(exc.format()))
@unittest.skipUnless(sys.version_info[0] < 3, "Applies to 2.x only.")
def test_format_bad_filename(self):
# Filenames in Python2 may be bytestrings that will fail to implicit
# decode.
# This won't decode via the implicit(ascii) codec or the default
# fs encoding (unless the encoding is a wildcard encoding).
fname = b('\x8b')
lines = u("1\n2\n3\n")
fake_module = dict(
__name__='fred',
__loader__=FakeLoader(lines)
)
linecache.updatecache(fname, fake_module)
e = SyntaxError("uh oh")
e.filename = fname
e.lineno = 2
e.text = b('something wrong')
e.offset = 1
c = test_code(fname, 'method')
f = test_frame(c, fake_module, {'something': 1})
tb = test_tb(f, 2, None)
exc = traceback.TracebackException(SyntaxError, e, tb)
list(exc.format_exception_only())
self.assertEqual([
u('Traceback (most recent call last):\n'),
b(' File "b\'\\x8b\'", line 2, in method\n 2\n').decode(),
b(' File "b\'\\x8b\'", line 2\n').decode(),
u(' something wrong\n'),
u(' ^\n'),
u('SyntaxError: uh oh\n')],
list(exc.format()))