diff --git a/yapf/yapflib/errors.py b/yapf/yapflib/errors.py index 3a0102368..4e636c075 100644 --- a/yapf/yapflib/errors.py +++ b/yapf/yapflib/errors.py @@ -13,6 +13,7 @@ # limitations under the License. """YAPF error objects.""" +from yapf_third_party._ylib2to3.pgen2 import parse from yapf_third_party._ylib2to3.pgen2 import tokenize @@ -29,12 +30,26 @@ def FormatErrorMsg(e): Returns: A properly formatted error message string. """ + filename = getattr(e, 'filename', None) if isinstance(e, SyntaxError): - return '{}:{}:{}: {}'.format(e.filename, e.lineno, e.offset, e.msg) + return '{}:{}:{}: {}'.format(filename, e.lineno, e.offset, e.msg) if isinstance(e, tokenize.TokenError): - return '{}:{}:{}: {}'.format(e.filename, e.args[1][0], e.args[1][1], - e.args[0]) - return '{}:{}:{}: {}'.format(e.args[1][0], e.args[1][1], e.args[1][2], e.msg) + lineno = e.args[1][0] if len(e.args) > 1 and len(e.args[1]) > 0 else 1 + col = e.args[1][1] if len(e.args) > 1 and len(e.args[1]) > 1 else 0 + msg = e.args[0] if e.args else str(e) + return '{}:{}:{}: {}'.format(filename, lineno, col, msg) + if isinstance(e, parse.ParseError): + lineno = e.context[1][0] if e.context and len(e.context) > 1 and len( + e.context[1]) > 0 else 1 + col = e.context[1][1] if e.context and len(e.context) > 1 and len( + e.context[1]) > 1 else 0 + msg = e.msg if hasattr(e, 'msg') else str(e) + return '{}:{}:{}: {}'.format(filename, lineno, col, msg) + try: + return '{}:{}:{}: {}'.format(e.args[1][0], e.args[1][1], e.args[1][2], + e.msg) + except (AttributeError, IndexError, TypeError): + return '{}: {}'.format(filename, e) if filename else str(e) class YapfError(Exception): diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py index a9ca01188..d06f5b1ec 100644 --- a/yapftests/yapf_test.py +++ b/yapftests/yapf_test.py @@ -25,6 +25,7 @@ import unittest from io import StringIO +from yapf_third_party._ylib2to3.pgen2 import parse from yapf_third_party._ylib2to3.pgen2 import tokenize from yapf.yapflib import errors @@ -1565,6 +1566,31 @@ def testBadCode(self): code = 'x = """hello\n' self.assertRaises(errors.YapfError, yapf_api.FormatCode, code) + def testParseError(self): + code = 'f"{tab["SOME_STRING"]}"\n' + with self.assertRaisesRegex(errors.YapfError, r'bad input'): + yapf_api.FormatCode(code, filename='test.py') + + def testFormatErrorMsg(self): + s = SyntaxError('invalid syntax') + s.filename = 'foo.py' + s.lineno = 10 + s.offset = 5 + self.assertEqual(errors.FormatErrorMsg(s), 'foo.py:10:5: invalid syntax') + + t = tokenize.TokenError('EOF in multi-line string', (2, 4)) + t.filename = 'bar.py' + self.assertEqual( + errors.FormatErrorMsg(t), 'bar.py:2:4: EOF in multi-line string') + + p = parse.ParseError('bad input', 1, 'SOME_STRING', ('', (1, 8))) + p.filename = 'test.py' + self.assertEqual(errors.FormatErrorMsg(p), 'test.py:1:8: bad input') + + g = RuntimeError('unknown failure') + g.filename = 'baz.py' + self.assertEqual(errors.FormatErrorMsg(g), 'baz.py: unknown failure') + class DiffIndentTest(yapf_test_helper.YAPFTest):