Skip to content
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 crash on psycopg2 for elif used #5369

Merged
merged 12 commits into from
Nov 24, 2021
Merged

Conversation

Pierre-Sassoulas
Copy link
Member

@Pierre-Sassoulas Pierre-Sassoulas commented Nov 22, 2021

Type of Changes

Type
βœ“ πŸ› Bug fix
βœ“ πŸ”¨ Refactoring

Description

https://github.com/psycopg/psycopg/blob/master/psycopg/psycopg/_queries.py#L281

Exception on node <If l.281 at 0x7f2f9141a550>

pylint crashed with a IndexError and with the following stacktrace:

Traceback (most recent call last):
  File "/home/pierre/pylint/pylint/lint/pylinter.py", line 1035, in _check_files
    self._check_file(get_ast, check_astroid_module, file)
  File "/home/pierre/pylint/pylint/lint/pylinter.py", line 1070, in _check_file
    check_astroid_module(ast_node)
  File "/home/pierre/pylint/pylint/lint/pylinter.py", line 1204, in check_astroid_module
    retval = self._check_astroid_module(
  File "/home/pierre/pylint/pylint/lint/pylinter.py", line 1251, in _check_astroid_module
    walker.walk(node)
  File "/home/pierre/pylint/pylint/utils/ast_walker.py", line 75, in walk
    self.walk(child)
  File "/home/pierre/pylint/pylint/utils/ast_walker.py", line 75, in walk
    self.walk(child)
  File "/home/pierre/pylint/pylint/utils/ast_walker.py", line 75, in walk
    self.walk(child)
  [Previous line repeated 1 more time]
  File "/home/pierre/pylint/pylint/utils/ast_walker.py", line 72, in walk
    callback(astroid)
  File "/home/pierre/pylint/pylint/extensions/check_elif.py", line 69, in visit_if
    if not self._elifs[self._if_counter]:
IndexError: list index out of range

The hot fix would be:

--- a/pylint/extensions/check_elif.py
+++ b/pylint/extensions/check_elif.py
@@ -66,7 +66,7 @@ class ElseifUsedChecker(BaseTokenChecker):
             orelse = node.parent.orelse
             # current if node must directly follow an "else"
             if orelse and orelse == [node]:
-                if not self._elifs[self._if_counter]:
+                if self._if_counter < len(self._elifs) and not self._elifs[self._if_counter]:
                     self.add_message("else-if-used", node=node)
         self._if_counter += 1

It seem to me that counting the if/elif properly would take some time. I created a minimal reproduction example:

def _if_in_fstring_comprehension():
    order = {}
    if not "false":
        raise TypeError(
            f" {', '.join(sorted(i for i in order or () if i not in vars))}"
        )
    elif "true":
        raise TypeError("d")

The issue come from the f string with a comprehension inside it that is not separated for the token processing.

Detected in #5173

@Pierre-Sassoulas Pierre-Sassoulas added the Crash πŸ’₯ A bug that makes pylint crash label Nov 22, 2021
@Pierre-Sassoulas Pierre-Sassoulas added this to the 2.12.0 milestone Nov 22, 2021
@coveralls
Copy link

coveralls commented Nov 22, 2021

Pull Request Test Coverage Report for Build 1498507098

  • 9 of 9 (100.0%) changed or added relevant lines in 2 files are covered.
  • 64 unchanged lines in 10 files lost coverage.
  • Overall coverage increased (+0.007%) to 93.46%

Files with Coverage Reduction New Missed Lines %
pylint/config/option.py 1 83.02%
pylint/checkers/utils.py 2 95.4%
pylint/extensions/overlapping_exceptions.py 2 84.09%
pylint/message/message.py 2 86.67%
pylint/testutils/reporter_for_tests.py 3 93.48%
pylint/checkers/exceptions.py 5 97.27%
pylint/testutils/lint_module_test.py 9 74.7%
pylint/checkers/variables.py 11 95.6%
pylint/checkers/similar.py 12 96.34%
pylint/lint/pylinter.py 17 94.23%
Totals Coverage Status
Change from base Build 1493950870: 0.007%
Covered Lines: 13919
Relevant Lines: 14893

πŸ’› - Coveralls

@Pierre-Sassoulas Pierre-Sassoulas force-pushed the fix-elif-checker-crash branch 2 times, most recently from c2ce2bb to 7dda588 Compare November 22, 2021 17:33
@Pierre-Sassoulas Pierre-Sassoulas marked this pull request as draft November 22, 2021 18:09
@Pierre-Sassoulas
Copy link
Member Author

New warnings are false positives changing to draft.

@Pierre-Sassoulas Pierre-Sassoulas changed the title Migrate test for elif used in functional tests and fix a crash on psycopg2 Fix a crash on psycopg2 for elif used Nov 22, 2021
We do not remove the hotfix in order to have a false positive
instead of a crash is something else is still buggy.
@Pierre-Sassoulas Pierre-Sassoulas marked this pull request as ready for review November 23, 2021 19:05
@Pierre-Sassoulas
Copy link
Member Author

@DanielNoord @cdce8p this is ready for review.

Copy link
Collaborator

@DanielNoord DanielNoord left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! Small changes here and there which we could do, I'll leave that decision to you!

ChangeLog Outdated Show resolved Hide resolved
pylint/checkers/classes.py Show resolved Hide resolved
pylint/extensions/check_elif.py Outdated Show resolved Hide resolved
tests/functional/ext/check_elif/check_elif.txt Outdated Show resolved Hide resolved
tests/functional/ext/check_elif/check_elif.py Outdated Show resolved Hide resolved
and (node.lineno, node.col_offset) in self._elifs
and self._elifs[(node.lineno, node.col_offset)] == "if"
):
self.add_message("else-if-used", node=node, confidence=HIGH)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ˜„

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not having an off by one error when we miscount an If increased the confidence πŸ˜„ But really the other option are:

Confidence = namedtuple("Confidence", ["name", "description"])
# Warning Certainties
HIGH = Confidence("HIGH", "No false positive possible.")
INFERENCE = Confidence("INFERENCE", "Warning based on inference result.")
INFERENCE_FAILURE = Confidence(
    "INFERENCE_FAILURE", "Warning based on inference with failures."
)
UNDEFINED = Confidence("UNDEFINED", "Warning without any associated confidence level.")

CONFIDENCE_LEVELS = [HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED]

There's no inference here, so it should probably by HIGH. But also, we should probably refactor this (?) It was not used before so we might as well make it make sense. I'm not confident enough to say there will never be any false positive just because there was no inference.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like we could use a NO_INFERENCE level. Maybe add the to the growing list of todo's for 2.13?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated #5317

@Pierre-Sassoulas
Copy link
Member Author

I don't understand the 64 unchanged lines in 10 files lost coverage. from coverall. Maybe I need to rebase on main ?

@DanielNoord
Copy link
Collaborator

I don't understand the 64 unchanged lines in 10 files lost coverage. from coverall. Maybe I need to rebase on main ?

The report on coveralls is different, see:
https://coveralls.io/builds/44507140

@Pierre-Sassoulas Pierre-Sassoulas merged commit e8fa469 into main Nov 24, 2021
@Pierre-Sassoulas Pierre-Sassoulas deleted the fix-elif-checker-crash branch November 24, 2021 09:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Crash πŸ’₯ A bug that makes pylint crash
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants