summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaudiu Popa <pcmanticore@gmail.com>2015-10-26 23:16:02 +0000
committerClaudiu Popa <pcmanticore@gmail.com>2015-10-26 23:16:02 +0000
commitc4e7c46703e54c7dfff51a984db85da1f09abc3c (patch)
treee3374edb0b3fb3428c48ec56633c798b6ae89347
parent486091452ad54d6bac7cc0100c62652e858aa8c8 (diff)
downloadpylint-c4e7c46703e54c7dfff51a984db85da1f09abc3c.tar.gz
Move unidiomatic-typecheck into the comparison checker from base.py, since it makes more sense for it to be there.
-rw-r--r--pylint/checkers/base.py52
-rw-r--r--pylint/checkers/stdlib.py45
2 files changed, 51 insertions, 46 deletions
diff --git a/pylint/checkers/base.py b/pylint/checkers/base.py
index c9e8b75..f368a65 100644
--- a/pylint/checkers/base.py
+++ b/pylint/checkers/base.py
@@ -62,6 +62,14 @@ REVERSED_PROTOCOL_METHOD = '__reversed__'
SEQUENCE_PROTOCOL_METHODS = ('__getitem__', '__len__')
REVERSED_METHODS = (SEQUENCE_PROTOCOL_METHODS,
(REVERSED_PROTOCOL_METHOD, ))
+TYPECHECK_COMPARISON_OPERATORS = frozenset(('is', 'is not', '==',
+ '!=', 'in', 'not in'))
+LITERAL_NODE_TYPES = (astroid.Const, astroid.Dict, astroid.List, astroid.Set)
+UNITTEST_CASE = 'unittest.case'
+if sys.version_info >= (3, 0):
+ TYPE_QNAME = 'builtins.type'
+else:
+ TYPE_QNAME = '__builtin__.type'
PY33 = sys.version_info >= (3, 3)
PY3K = sys.version_info >= (3, 0)
@@ -1455,6 +1463,14 @@ class LambdaForComprehensionChecker(_BasicChecker):
self.add_message('deprecated-lambda', node=node)
+def _is_one_arg_pos_call(call):
+ """Is this a call with exactly 1 argument,
+ where that argument is positional?
+ """
+ return (isinstance(call, astroid.Call)
+ and len(call.args) == 1 and not call.keywords)
+
+
class ComparisonChecker(_BasicChecker):
"""Checks for comparisons
@@ -1472,6 +1488,13 @@ class ComparisonChecker(_BasicChecker):
'Used when the constant is placed on the left side'
'of a comparison. It is usually clearer in intent to '
'place it in the right hand side of the comparison.'),
+ 'C0123': ('Using type() instead of isinstance() for a typecheck.',
+ 'unidiomatic-typecheck',
+ 'The idiomatic way to perform an explicit typecheck in '
+ 'Python is to use isinstance(x, Y) rather than '
+ 'type(x) == Y, type(x) is Y. Though there are unusual '
+ 'situations where these give different results.',
+ {'old_names': [('W0154', 'unidiomatic-typecheck')]}),
}
def _check_singleton_comparison(self, singleton, root_node):
@@ -1498,8 +1521,10 @@ class ComparisonChecker(_BasicChecker):
self.add_message('misplaced-comparison-constant', node=node,
args=(suggestion,))
- @check_messages('singleton-comparison', 'misplaced-comparison-constant')
+ @check_messages('singleton-comparison', 'misplaced-comparison-constant',
+ 'unidiomatic-typecheck')
def visit_compare(self, node):
+ self._check_unidiomatic_typecheck(node)
# NOTE: this checker only works with binary comparisons like 'x == 42'
# but not 'x == y == 42'
if len(node.ops) != 1:
@@ -1516,6 +1541,31 @@ class ComparisonChecker(_BasicChecker):
elif isinstance(right, astroid.Const):
self._check_singleton_comparison(right, node)
+ def _check_unidiomatic_typecheck(self, node):
+ operator, right = node.ops[0]
+ if operator in TYPECHECK_COMPARISON_OPERATORS:
+ left = node.left
+ if _is_one_arg_pos_call(left):
+ self._check_type_x_is_y(node, left, operator, right)
+
+ def _check_type_x_is_y(self, node, left, operator, right):
+ """Check for expressions like type(x) == Y."""
+ left_func = helpers.safe_infer(left.func)
+ if not (isinstance(left_func, astroid.ClassDef)
+ and left_func.qname() == TYPE_QNAME):
+ return
+
+ if operator in ('is', 'is not') and _is_one_arg_pos_call(right):
+ right_func = helpers.safe_infer(right.func)
+ if (isinstance(right_func, astroid.ClassDef)
+ and right_func.qname() == TYPE_QNAME):
+ # type(x) == type(a)
+ right_arg = helpers.safe_infer(right.args[0])
+ if not isinstance(right_arg, LITERAL_NODE_TYPES):
+ # not e.g. type(x) == type([])
+ return
+ self.add_message('unidiomatic-typecheck', node=node)
+
def register(linter):
"""required method to auto register this checker"""
diff --git a/pylint/checkers/stdlib.py b/pylint/checkers/stdlib.py
index 7df71b2..f583215 100644
--- a/pylint/checkers/stdlib.py
+++ b/pylint/checkers/stdlib.py
@@ -27,17 +27,12 @@ from pylint.checkers import BaseChecker
from pylint.checkers import utils
-TYPECHECK_COMPARISON_OPERATORS = frozenset(('is', 'is not', '==',
- '!=', 'in', 'not in'))
-LITERAL_NODE_TYPES = (astroid.Const, astroid.Dict, astroid.List, astroid.Set)
OPEN_FILES = {'open', 'file'}
UNITTEST_CASE = 'unittest.case'
if sys.version_info >= (3, 0):
OPEN_MODULE = '_io'
- TYPE_QNAME = 'builtins.type'
else:
OPEN_MODULE = '__builtin__'
- TYPE_QNAME = '__builtin__.type'
def _check_mode_str(mode):
@@ -82,14 +77,6 @@ def _check_mode_str(mode):
return True
-def _is_one_arg_pos_call(call):
- """Is this a call with exactly 1 argument,
- where that argument is positional?
- """
- return (isinstance(call, astroid.Call)
- and len(call.args) == 1 and not call.keywords)
-
-
class StdlibChecker(BaseChecker):
__implements__ = (IAstroidChecker,)
name = 'stdlib'
@@ -114,12 +101,6 @@ class StdlibChecker(BaseChecker):
'a condition. If a constant is passed as parameter, that '
'condition will be always true. In this case a warning '
'should be emitted.'),
- 'W1504': ('Using type() instead of isinstance() for a typecheck.',
- 'unidiomatic-typecheck',
- 'The idiomatic way to perform an explicit typecheck in '
- 'Python is to use isinstance(x, Y) rather than '
- 'type(x) == Y, type(x) is Y. Though there are unusual '
- 'situations where these give different results.'),
'W1505': ('Using deprecated method %s()',
'deprecated-method',
'The method is marked as deprecated and will be removed in '
@@ -231,14 +212,6 @@ class StdlibChecker(BaseChecker):
for value in node.values:
self._check_datetime(value)
- @utils.check_messages('unidiomatic-typecheck')
- def visit_compare(self, node):
- operator, right = node.ops[0]
- if operator in TYPECHECK_COMPARISON_OPERATORS:
- left = node.left
- if _is_one_arg_pos_call(left):
- self._check_type_x_is_y(node, left, operator, right)
-
def _check_deprecated_method(self, node, infer):
py_vers = sys.version_info[0]
@@ -296,24 +269,6 @@ class StdlibChecker(BaseChecker):
self.add_message('bad-open-mode', node=node,
args=mode_arg.value)
- def _check_type_x_is_y(self, node, left, operator, right):
- """Check for expressions like type(x) == Y."""
- left_func = helpers.safe_infer(left.func)
- if not (isinstance(left_func, astroid.ClassDef)
- and left_func.qname() == TYPE_QNAME):
- return
-
- if operator in ('is', 'is not') and _is_one_arg_pos_call(right):
- right_func = helpers.safe_infer(right.func)
- if (isinstance(right_func, astroid.ClassDef)
- and right_func.qname() == TYPE_QNAME):
- # type(x) == type(a)
- right_arg = helpers.safe_infer(right.args[0])
- if not isinstance(right_arg, LITERAL_NODE_TYPES):
- # not e.g. type(x) == type([])
- return
- self.add_message('unidiomatic-typecheck', node=node)
-
def register(linter):
"""required method to auto register this checker """