From 304ae035b9b5e42bb1eb65baecc58d5c9b5ab14d Mon Sep 17 00:00:00 2001 From: Claudiu Popa Date: Mon, 30 Nov 2015 15:50:45 +0200 Subject: Fix a crash which occurred when old visit methods are encountered in plugin modules. If a plugin uses an old visit method (visit_class for instance), this can lead to a crash in pylint's base checkers, because the logic in the PylintASTWalker assumes that all checkers have a visit_class / leave_class method. The patch fixes this by looking for both names. Closes issue #711. --- ChangeLog | 3 +++ pylint/test/unittest_lint.py | 19 ++++++++++++++++++- pylint/utils.py | 16 ++++++++-------- 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/ChangeLog b/ChangeLog index e53e79c..f97a547 100644 --- a/ChangeLog +++ b/ChangeLog @@ -10,6 +10,9 @@ ChangeLog for Pylint emitted when item deletion is tried on an object which doesn't have this ability. Closes issue #592. + * Fix a crash which occurred when old visit methods are encountered + in plugin modules. Closes issue #711. + * Added multiple warnings related to imports. 'wrong-import-order' is emitted when PEP 8 recommendations regarding imports are not respected (that is, standard imports should be followed by third-party diff --git a/pylint/test/unittest_lint.py b/pylint/test/unittest_lint.py index 3095108..5877d4c 100644 --- a/pylint/test/unittest_lint.py +++ b/pylint/test/unittest_lint.py @@ -33,6 +33,7 @@ from pylint.utils import MSG_STATE_SCOPE_CONFIG, MSG_STATE_SCOPE_MODULE, MSG_STA from pylint.testutils import TestReporter from pylint.reporters import text, html from pylint import checkers +from pylint.checkers.utils import check_messages from pylint import interfaces if os.name == 'java': @@ -217,6 +218,22 @@ class PyLinterTC(unittest.TestCase): linter.file_state = FileState('toto') return linter + def test_pylint_visit_method_taken_in_account(self): + class CustomChecker(checkers.BaseChecker): + __implements__ = interfaces.IAstroidChecker + name = 'custom' + msgs = {'W9999': ('', 'custom', '')} + + @check_messages('custom') + def visit_class(self, _): + pass + + self.linter.register_checker(CustomChecker(self.linter)) + self.linter.open() + out = six.moves.StringIO() + self.linter.set_reporter(text.TextReporter(out)) + self.linter.check('abc') + def test_enable_message(self): linter = self.init_linter() self.assertTrue(linter.is_message_enabled('W0101')) @@ -669,6 +686,6 @@ class MessagesStoreTC(unittest.TestCase): self.assertEqual('msg-symbol', self.store.check_message_id('old-symbol').symbol) - + if __name__ == '__main__': unittest.main() diff --git a/pylint/utils.py b/pylint/utils.py index 090b0a5..d2bca89 100644 --- a/pylint/utils.py +++ b/pylint/utils.py @@ -19,6 +19,7 @@ main pylint class from __future__ import print_function import collections +import itertools import os from os.path import dirname, basename, splitext, exists, isdir, join, normpath import re @@ -904,15 +905,14 @@ class PyLintASTWalker(object): # Detect if the node is a new name for a deprecated alias. # In this case, favour the methods for the deprecated # alias if any, in order to maintain backwards - # compatibility. If both of them are present, - # only the old ones will be called. + # compatibility. old_cid = DEPRECATED_ALIASES.get(cid) visit_events = () leave_events = () if old_cid: - visit_events = self.visit_events.get(old_cid) - leave_events = self.leave_events.get(old_cid) + visit_events = self.visit_events.get(old_cid, ()) + leave_events = self.leave_events.get(old_cid, ()) if visit_events or leave_events: msg = ("Implemented method {meth}_{old} instead of {meth}_{new}. " "This will be supported until Pylint 2.0.") @@ -923,10 +923,10 @@ class PyLintASTWalker(object): warnings.warn(msg.format(meth="leave", old=old_cid, new=cid), PendingDeprecationWarning) - if not visit_events: - visit_events = self.visit_events.get(cid) - if not leave_events: - leave_events = self.leave_events.get(cid) + visit_events = itertools.chain(visit_events, + self.visit_events.get(cid, ())) + leave_events = itertools.chain(leave_events, + self.leave_events.get(cid, ())) if astroid.is_statement: self.nbstatements += 1 -- cgit v1.2.1