Skip to content

Commit

Permalink
Fix a magical comment caused internal error (#3740)
Browse files Browse the repository at this point in the history
`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
  • Loading branch information
rdrll committed Jun 27, 2023
1 parent 31b3b67 commit 63481bb
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 8 deletions.
2 changes: 2 additions & 0 deletions CHANGES.md
Expand Up @@ -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

Expand Down
10 changes: 8 additions & 2 deletions src/black/linegen.py
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
5 changes: 3 additions & 2 deletions src/black/lines.py
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
23 changes: 19 additions & 4 deletions src/black/nodes.py
Expand Up @@ -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:
Expand Down
@@ -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

0 comments on commit 63481bb

Please sign in to comment.