Support files with type comment syntax errors (#3594)
This commit is contained in:
parent
dba3c2695c
commit
53c23e62df
@ -38,6 +38,8 @@
|
|||||||
|
|
||||||
<!-- Changes to the parser or to version autodetection -->
|
<!-- Changes to the parser or to version autodetection -->
|
||||||
|
|
||||||
|
- Added support for formatting files with invalid type comments (#3594)
|
||||||
|
|
||||||
### Performance
|
### Performance
|
||||||
|
|
||||||
<!-- Changes that improve Black's performance. -->
|
<!-- Changes that improve Black's performance. -->
|
||||||
|
@ -148,24 +148,29 @@ def lib2to3_unparse(node: Node) -> str:
|
|||||||
|
|
||||||
|
|
||||||
def parse_single_version(
|
def parse_single_version(
|
||||||
src: str, version: Tuple[int, int]
|
src: str, version: Tuple[int, int], *, type_comments: bool
|
||||||
) -> Union[ast.AST, ast3.AST]:
|
) -> Union[ast.AST, ast3.AST]:
|
||||||
filename = "<unknown>"
|
filename = "<unknown>"
|
||||||
# typed-ast is needed because of feature version limitations in the builtin ast 3.8>
|
# typed-ast is needed because of feature version limitations in the builtin ast 3.8>
|
||||||
if sys.version_info >= (3, 8) and version >= (3,):
|
if sys.version_info >= (3, 8) and version >= (3,):
|
||||||
return ast.parse(src, filename, feature_version=version, type_comments=True)
|
return ast.parse(
|
||||||
|
src, filename, feature_version=version, type_comments=type_comments
|
||||||
|
)
|
||||||
|
|
||||||
if _IS_PYPY:
|
if _IS_PYPY:
|
||||||
# PyPy 3.7 doesn't support type comment tracking which is not ideal, but there's
|
# PyPy 3.7 doesn't support type comment tracking which is not ideal, but there's
|
||||||
# not much we can do as typed-ast won't work either.
|
# not much we can do as typed-ast won't work either.
|
||||||
if sys.version_info >= (3, 8):
|
if sys.version_info >= (3, 8):
|
||||||
return ast3.parse(src, filename, type_comments=True)
|
return ast3.parse(src, filename, type_comments=type_comments)
|
||||||
else:
|
else:
|
||||||
return ast3.parse(src, filename)
|
return ast3.parse(src, filename)
|
||||||
else:
|
else:
|
||||||
|
if type_comments:
|
||||||
# Typed-ast is guaranteed to be used here and automatically tracks type
|
# Typed-ast is guaranteed to be used here and automatically tracks type
|
||||||
# comments separately.
|
# comments separately.
|
||||||
return ast3.parse(src, filename, feature_version=version[1])
|
return ast3.parse(src, filename, feature_version=version[1])
|
||||||
|
else:
|
||||||
|
return ast.parse(src, filename)
|
||||||
|
|
||||||
|
|
||||||
def parse_ast(src: str) -> Union[ast.AST, ast3.AST]:
|
def parse_ast(src: str) -> Union[ast.AST, ast3.AST]:
|
||||||
@ -175,11 +180,18 @@ def parse_ast(src: str) -> Union[ast.AST, ast3.AST]:
|
|||||||
first_error = ""
|
first_error = ""
|
||||||
for version in sorted(versions, reverse=True):
|
for version in sorted(versions, reverse=True):
|
||||||
try:
|
try:
|
||||||
return parse_single_version(src, version)
|
return parse_single_version(src, version, type_comments=True)
|
||||||
except SyntaxError as e:
|
except SyntaxError as e:
|
||||||
if not first_error:
|
if not first_error:
|
||||||
first_error = str(e)
|
first_error = str(e)
|
||||||
|
|
||||||
|
# Try to parse without type comments
|
||||||
|
for version in sorted(versions, reverse=True):
|
||||||
|
try:
|
||||||
|
return parse_single_version(src, version, type_comments=False)
|
||||||
|
except SyntaxError:
|
||||||
|
pass
|
||||||
|
|
||||||
raise SyntaxError(first_error)
|
raise SyntaxError(first_error)
|
||||||
|
|
||||||
|
|
||||||
|
11
tests/data/type_comments/type_comment_syntax_error.py
Normal file
11
tests/data/type_comments/type_comment_syntax_error.py
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
def foo(
|
||||||
|
# type: Foo
|
||||||
|
x): pass
|
||||||
|
|
||||||
|
# output
|
||||||
|
|
||||||
|
def foo(
|
||||||
|
# type: Foo
|
||||||
|
x,
|
||||||
|
):
|
||||||
|
pass
|
@ -196,3 +196,10 @@ def test_power_op_newline() -> None:
|
|||||||
# requires line_length=0
|
# requires line_length=0
|
||||||
source, expected = read_data("miscellaneous", "power_op_newline")
|
source, expected = read_data("miscellaneous", "power_op_newline")
|
||||||
assert_format(source, expected, mode=black.Mode(line_length=0))
|
assert_format(source, expected, mode=black.Mode(line_length=0))
|
||||||
|
|
||||||
|
|
||||||
|
def test_type_comment_syntax_error() -> None:
|
||||||
|
"""Test that black is able to format python code with type comment syntax errors."""
|
||||||
|
source, expected = read_data("type_comments", "type_comment_syntax_error")
|
||||||
|
assert_format(source, expected)
|
||||||
|
black.assert_equivalent(source, expected)
|
||||||
|
Loading…
Reference in New Issue
Block a user