Fix a magical comment caused internal error (#3740)

`is_type_comment` now specifically deals with general type comments for a leaf.
`is_type_ignore_comment` now handles type comments contains ignore annotation for a leaf
`is_type_ignore_comment_string` used to determine if a string is an ignore type comment
This commit is contained in:
rdrll 2023-06-27 07:23:39 -07:00 committed by GitHub
parent 31b3b6701d
commit 63481bb926
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 73 additions and 8 deletions

View File

@ -12,6 +12,8 @@
- Fix a bug where an illegal trailing comma was added to return type annotations using
PEP 604 unions (#3735)
- Fix a bug where multi-line open parenthesis magic comment like `type: ignore` were not
correctly parsed (#3740)
### Preview style

View File

@ -49,6 +49,7 @@
is_stub_body,
is_stub_suite,
is_tuple_containing_walrus,
is_type_ignore_comment_string,
is_vararg,
is_walrus_assignment,
is_yield,
@ -1399,8 +1400,13 @@ def maybe_make_parens_invisible_in_atom(
if is_lpar_token(first) and is_rpar_token(last):
middle = node.children[1]
# make parentheses invisible
first.value = ""
last.value = ""
if (
# If the prefix of `middle` includes a type comment with
# ignore annotation, then we do not remove the parentheses
not is_type_ignore_comment_string(middle.prefix.strip())
):
first.value = ""
last.value = ""
maybe_make_parens_invisible_in_atom(
middle,
parent=parent,

View File

@ -28,6 +28,7 @@
is_multiline_string,
is_one_sequence_between,
is_type_comment,
is_type_ignore_comment,
is_with_or_async_with_stmt,
replace_child,
syms,
@ -251,7 +252,7 @@ def contains_uncollapsable_type_comments(self) -> bool:
for comment in comments:
if is_type_comment(comment):
if comment_seen or (
not is_type_comment(comment, " ignore")
not is_type_ignore_comment(comment)
and leaf_id not in ignored_ids
):
return True
@ -288,7 +289,7 @@ def contains_unsplittable_type_ignore(self) -> bool:
# line.
for node in self.leaves[-2:]:
for comment in self.comments.get(id(node), []):
if is_type_comment(comment, " ignore"):
if is_type_ignore_comment(comment):
return True
return False

View File

@ -816,12 +816,27 @@ def is_async_stmt_or_funcdef(leaf: Leaf) -> bool:
)
def is_type_comment(leaf: Leaf, suffix: str = "") -> bool:
"""Return True if the given leaf is a special comment.
Only returns true for type comments for now."""
def is_type_comment(leaf: Leaf) -> bool:
"""Return True if the given leaf is a type comment. This function should only
be used for general type comments (excluding ignore annotations, which should
use `is_type_ignore_comment`). Note that general type comments are no longer
used in modern version of Python, this function may be deprecated in the future."""
t = leaf.type
v = leaf.value
return t in {token.COMMENT, STANDALONE_COMMENT} and v.startswith("# type:" + suffix)
return t in {token.COMMENT, STANDALONE_COMMENT} and v.startswith("# type:")
def is_type_ignore_comment(leaf: Leaf) -> bool:
"""Return True if the given leaf is a type comment with ignore annotation."""
t = leaf.type
v = leaf.value
return t in {token.COMMENT, STANDALONE_COMMENT} and is_type_ignore_comment_string(v)
def is_type_ignore_comment_string(value: str) -> bool:
"""Return True if the given string match with type comment with
ignore annotation."""
return value.startswith("# type: ignore")
def wrap_in_parentheses(parent: Node, child: LN, *, visible: bool = True) -> None:

View File

@ -0,0 +1,41 @@
# This is a regression test. Issue #3737
a = ( # type: ignore
int( # type: ignore
int( # type: ignore
int( # type: ignore
6
)
)
)
)
b = (
int(
6
)
)
print( "111") # type: ignore
print( "111" ) # type: ignore
print( "111" ) # type: ignore
# output
# This is a regression test. Issue #3737
a = ( # type: ignore
int( # type: ignore
int( # type: ignore
int(6) # type: ignore
)
)
)
b = int(6)
print("111") # type: ignore
print("111") # type: ignore
print("111") # type: ignore