-
Notifications
You must be signed in to change notification settings - Fork 2.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix a magical comment caused internal error #3740
Fix a magical comment caused internal error #3740
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you!
src/black/linegen.py
Outdated
not node.children[1] | ||
.prefix.strip() | ||
.replace(" ", "") | ||
.startswith("#type:ignore") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you use is_type_comment()
from lines.py
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Umm I don't think I can directly replace code here with the is_type_comment()
function, as the function expect a leaf
as input and check on its value
field, while here the comment is as a node
's prefix (node.children[1] is still a node), I tried to find some existing function to convert this prefix string into a leaf
, but I haven't found one yet... Any further guidance would be really helpful!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's true, the interface doesn't apply. However, there is also a difference in behavior: the other function specifically looks for # type: ignore
, but this one also allows # type:ignore
. Mypy allows both so I think your solution is better, but we should be consistent (see also #2501 which asks us to format type-ignore comments).
I think we should:
- Add a new function, say
is_type_ignore_comment_string
, that takes astr
and returns whether it's a type ignore comment. It should ignore whitespace. - Split
is_type_comment()
intois_type_comment()
andis_type_ignore_comment()
- Use
is_type_ignore_comment_string()
both here and fromis_type_ignore_comment()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We also discussed this in #3339. I think for now let's not worry about type:ignore
without the space and handle only # type: ignore
with a space. We can figure out how to deal with the spacing issue in the other PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gotcha! Thanks for the guidance on design! I'll then keep it consistent with the rest part of Black to only handle the with-space case.
Just to clarify my understanding - when you suggest splitting is_type_comment()
into is_type_comment()
and is_type_ignore_comment()
, does that mean we will be using the original is_type_comment()
to handle non-ignore type of comments and use the new is_type_ignore_comment()
to handle ignore-type of comments? (so all current usage of is_type_comment()
for ignore-type comments will be using the new one instead)
Btw, I noticed that in #3339, it's been mentioned that the type comment is a deprecated feature, I tried to search for information on this deprecation but couldn't quite find where Python states about this deprecation. I'm wondering if you know if there's a particular PEP doc or other places that states it's a deprecated feature? I think it would also be beneficial to have this discussion documented here for future reference.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently is_type_comment()
takes a suffix
argument, which is always passed as either ""
or " ignore"
. Calls that use the former should stay as is_type_coment()
, and calls that use the latter use is_type_ignore_comment()
.
What's deprecated-ish is using type comments for type annotations like x: [] # type: List[str]
. This was a compatibility feature introduced in PEP 484 for compatibility with Python 2 and Python 3.5, but it's not needed in modern versions of Python. Therefore, we're thinking of deprecating mypy support for it: python/mypy#12947. However, # type: ignore
has no such replacement and it's here to stay.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have updated the code. I also removed the optional string parameter suffix
in is_type_coment()
, This parameter was only used to pass in "ignore"
, and since the handling of ignore comments is now done by the new function is_type_ignore_comment()
, there is no need to keep this parameter. Also, considering that is_type_comment()
is responsible for handling only general types comments and there are plans to deprecate its support in the future, I added a note to its docstring stating that it might be deprecated in the future.
`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
Description
Fix #3737
Analysis of this issue:
Black has no problem parsing multiline consecutive magical comments like
type: ignore
, it works fine with these examples:But Black encountered issue when parsing multiline open-parenthesis consecutive magical comments, code like this will cause Black to produce an
INTERNAL ERROR: Black produced code that is not equivalent to the source.
problem:Solution
This PR resolves the issue by adding an additional check, before it try to remove outer parentheses.
Additional regression test has been added in
tests/test_black.py
, and the input & desired output has been placed undertests/data/miscellaneous
folder.With this patch, Black will produce the following output for the example code above:
Note that the innermost layer remains formatted, despite the presence of a
type: ignore
for that line, the reason is because I find when it comes to the innermost layer, it seem to be a different kind of node (the type of Node would be322
instead of267
for outer layers).So in order to change this behaviour, some nuanced modifications on a larger scale seems to be necessary while making sure not breaking any current things, meanwhile, it also makes sense to 'always format the innermost layer' based on examples here and in the original issue ticket. So I'm not entirely clear whether it's a good idea to do so. But for now, it correctly understands this kind of magic comment usage and no longer raises the internal error.
Checklist - did you ...
CHANGES.md
if necessary?Since it's a bug fixing and not making much enhancement, so I don't think anything is need to be added to documentation.
Please let me know if any changes are needed!