Add orelse_lineno and orelse_col_offset to nodes.If#1480
Add orelse_lineno and orelse_col_offset to nodes.If#1480DanielNoord wants to merge 17 commits intopylint-dev:mainfrom
orelse_lineno and orelse_col_offset to nodes.If#1480Conversation
Pierre-Sassoulas
left a comment
There was a problem hiding this comment.
LGTM, that would be very useful indeed.
|
Drafting this. Thought about this some more over the weekend and I think it makes sense to also pick up the if:
...
elif:
...
else:
...The |
Pull Request Test Coverage Report for Build 2307861275
💛 - Coveralls |
Pierre-Sassoulas
left a comment
There was a problem hiding this comment.
Looks good, I think a review by Marc would be nice but if he does not have the time this can go :)
cdce8p
left a comment
There was a problem hiding this comment.
The current solution is quite inefficient. In worse case, the whole token list is generated multiple times for a single node. It would be better to calculate the end_line beforehand and using the generate_tokens iterator directly. For _get_position_info I've used node.end_lineno (were available) or iterated until the last line. Since it's a generator, we can exit early easily.
Besides the performance issue, I'm not sure a tokenize solution is the right approach. We need to search a whole range of lines which can contain basically any other nodes. For example, what about a nested function with an IfExp node in its body? There is also the issue of else which isn't exclusive to if - else. It can also be used with try and for. All in all, you would need to keep track of a lot of different things which I imaging will be pretty complicated.
Thinking about a different solution, is something preventing us to look at the first node in orelse and using its lineno and col_offset?
Some other questions:
- If that works, do we really need to add new node attributes in astroid? (Or can pylint deal with it itself.)
- What about other block nodes
forwithelse,trywithexcept,else, andfinally? How do we deal with them?
In the end, is a change worth the effort?
if condition:
do_something()
elif other_condition:
do_something_different()
else:
# We don't want to do anything here
# But we don't to disable a message: # pylint: disable=invalid-name
dont_do_anything()The issue with the approach and the code above is that we don't think comments into account. I thought this might become problematic, especially since the use-case for this is the handle disable comments in these blocks better. Doing The issue then became that I had to take quite large range of lines in order not to pass |
|
@cdce8p I changed the code to use a pretty naive but working solution. I'm not sure what the impact of Let me know what you think! |
cdce8p
left a comment
There was a problem hiding this comment.
Not particularly pretty, but I guess it should work.
Could you add some more test cases with for - else and try - except - else in addition to the nested one? This shouldn't be an issue with the current implementation, but those cases are never the less good as regression tests if we ever need to touch this part again.
Co-authored-by: Marc Mueller <30130371+cdce8p@users.noreply.github.com>
5461a80 to
4608fe4
Compare
|
@cdce8p After your comments I found out that we were actually missing some nodes which could have access to the same attributes. |
Let's step back for a moment. Just for me to understand, once the PR is merged how would you integrate the new information so that the issue is fixed? If I remember correctly, wouldn't you need to modify the Something else, although I'm not sure it's an issue, with this PR we're only addressing |
|
@cdce8p Current iteration is with changing The issue is basically the following example: if x:
1
elif y: # pylint: disable=pointless-statement
1
else:
1Which lines should be covered by the disable? With this proposal it would be 3 and 4. Similar examples can be seen in the tests. The PR would make it so that every keyword creates its own scope "disable-wise". That's not completely backwards compatible I think, but it does seem a little bit more logical and also more in line with other tools such as |
|
@Pierre-Sassoulas @jacobtylerwalls I can dust off this PR if we want. I think the last comment is a good summary of the changes, and is still valuable to make. What do you think? See also pylint-dev/pylint#872 |
|
I think this is very nice but it's going to break some expectations and external documentation (stackoverflow) about disable. Ho well.. |
|
👍 from me, we'll just need to update docs and decide if the pylint change goes in a minor or major. |
Steps
Description
This helps to identify where the
elsekeyword is. It can be very useful, for example, for this issue: pylint-dev/pylint#872.With a line number for the
elsekeyword we can separate the different blocks in theif...elseblock and handle the disables accordingly.Let me know what you guys think of this approach.
Type of Changes
Related Issue