diff options
author | Roy Williams <roy.williams.iii@gmail.com> | 2016-12-05 15:06:45 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-12-05 15:06:45 -0800 |
commit | 38c652c17ad76e15a9da2f17f11f632e1027a76d (patch) | |
tree | 12b0e50d71623b189d11c3eea699320f77046166 /pylint | |
parent | 1c29c5156e954ec43be210b9521b92f987bf48fa (diff) | |
download | pylint-git-38c652c17ad76e15a9da2f17f11f632e1027a76d.tar.gz |
Add confidence to error messages about `str.translate` and `str.encode/decode` (#1197)
Diffstat (limited to 'pylint')
-rw-r--r-- | pylint/checkers/python3.py | 22 | ||||
-rw-r--r-- | pylint/test/unittest_checker_python3.py | 19 | ||||
-rw-r--r-- | pylint/testutils.py | 20 |
3 files changed, 45 insertions, 16 deletions
diff --git a/pylint/checkers/python3.py b/pylint/checkers/python3.py index 2b91e82d6..e2c6f12e2 100644 --- a/pylint/checkers/python3.py +++ b/pylint/checkers/python3.py @@ -16,6 +16,7 @@ import astroid from astroid import bases from pylint import checkers, interfaces +from pylint.interfaces import INFERENCE_FAILURE, INFERENCE from pylint.utils import WarningScope from pylint.checkers import utils @@ -614,12 +615,14 @@ class Python3Checker(checkers.BaseChecker): @staticmethod def _could_be_string(inferred_types): + confidence = INFERENCE if inferred_types else INFERENCE_FAILURE for inferred_type in inferred_types: - if not (inferred_type == astroid.Uninferable or ( - isinstance(inferred_type, astroid.Const) and - isinstance(inferred_type.value, six.string_types))): - return False - return True + if inferred_type is astroid.Uninferable: + confidence = INFERENCE_FAILURE + elif not (isinstance(inferred_type, astroid.Const) and + isinstance(inferred_type.value, six.string_types)): + return None + return confidence def visit_call(self, node): self._check_cmp_argument(node) @@ -628,14 +631,15 @@ class Python3Checker(checkers.BaseChecker): inferred_types = set() try: for inferred_receiver in node.func.expr.infer(): - inferred_types.add(type(inferred_receiver)) + inferred_types.add(inferred_receiver) if isinstance(inferred_receiver, astroid.Module): self._warn_if_deprecated(node, inferred_receiver.name, {node.func.attrname}) except astroid.InferenceError: pass if node.args: - if self._could_be_string(inferred_types): + is_str_confidence = self._could_be_string(inferred_types) + if is_str_confidence: if (node.func.attrname in ('encode', 'decode') and len(node.args) >= 1 and node.args[0]): first_arg = node.args[0] @@ -656,7 +660,9 @@ class Python3Checker(checkers.BaseChecker): # after checking several large codebases it did not have any false # positives while finding several real issues. This call pattern seems # rare enough that the trade off is worth it. - self.add_message('deprecated-str-translate-call', node=node) + self.add_message('deprecated-str-translate-call', + node=node, + confidence=is_str_confidence) return if node.keywords: return diff --git a/pylint/test/unittest_checker_python3.py b/pylint/test/unittest_checker_python3.py index 28a6d8052..165d9dad0 100644 --- a/pylint/test/unittest_checker_python3.py +++ b/pylint/test/unittest_checker_python3.py @@ -15,6 +15,7 @@ import astroid from pylint import testutils from pylint.checkers import python3 as checker +from pylint.interfaces import INFERENCE_FAILURE, INFERENCE def python2_only(test): @@ -652,16 +653,30 @@ class Python3CheckerTest(testutils.CheckerTestCase): node = astroid.extract_node(''' foobar.translate(None, 'abc123') #@ ''') - message = testutils.Message('deprecated-str-translate-call', node=node) + message = testutils.Message('deprecated-str-translate-call', node=node, + confidence=INFERENCE_FAILURE) with self.assertAddsMessages(message): self.checker.visit_call(node) @python2_only def test_bad_str_translate_call_variable(self): node = astroid.extract_node(''' + def raz(foobar): + foobar.translate(None, 'hello') #@ + ''') + message = testutils.Message('deprecated-str-translate-call', node=node, + confidence=INFERENCE_FAILURE) + with self.assertAddsMessages(message): + self.checker.visit_call(node) + + @python2_only + def test_bad_str_translate_call_infer_str(self): + node = astroid.extract_node(''' + foobar = "hello world" foobar.translate(None, foobar) #@ ''') - message = testutils.Message('deprecated-str-translate-call', node=node) + message = testutils.Message('deprecated-str-translate-call', node=node, + confidence=INFERENCE) with self.assertAddsMessages(message): self.checker.visit_call(node) diff --git a/pylint/testutils.py b/pylint/testutils.py index 892ca7c73..c6bd0a7a2 100644 --- a/pylint/testutils.py +++ b/pylint/testutils.py @@ -132,9 +132,18 @@ class TestReporter(BaseReporter): class Message(collections.namedtuple('Message', - ['msg_id', 'line', 'node', 'args'])): - def __new__(cls, msg_id, line=None, node=None, args=None): - return tuple.__new__(cls, (msg_id, line, node, args)) + ['msg_id', 'line', 'node', 'args', 'confidence'])): + def __new__(cls, msg_id, line=None, node=None, args=None, confidence=None): + return tuple.__new__(cls, (msg_id, line, node, args, confidence)) + + def __eq__(self, other): + if isinstance(other, Message): + if self.confidence and other.confidence: + return super(Message, self).__eq__(other) + return self[:-1] == other[:-1] + return NotImplemented # pragma: no cover + + __hash__ = None class UnittestLinter(object): @@ -151,9 +160,8 @@ class UnittestLinter(object): finally: self._messages = [] - def add_message(self, msg_id, line=None, node=None, args=None, - confidence=None): - self._messages.append(Message(msg_id, line, node, args)) + def add_message(self, msg_id, line=None, node=None, args=None, confidence=None): + self._messages.append(Message(msg_id, line, node, args, confidence)) def is_message_enabled(self, *unused_args, **unused_kwargs): return True |