summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaudiu Popa <cpopa@cloudbasesolutions.com>2015-07-06 19:57:11 +0300
committerClaudiu Popa <cpopa@cloudbasesolutions.com>2015-07-06 19:57:11 +0300
commit3ba401db3bd21a91449159b97a438ee23625eadc (patch)
tree39e271d82e601af6275428f2c668e51ea11ffc9d
parent7596535e16a1e9cd861aecfb36131c43f0edfe12 (diff)
downloadpylint-3ba401db3bd21a91449159b97a438ee23625eadc.tar.gz
Use safe_infer and has_known_bases from astroid.helpers. Closes issue #593.
-rw-r--r--pylint/checkers/base.py19
-rw-r--r--pylint/checkers/classes.py7
-rw-r--r--pylint/checkers/exceptions.py17
-rw-r--r--pylint/checkers/logging.py4
-rw-r--r--pylint/checkers/newstyle.py8
-rw-r--r--pylint/checkers/python3.py6
-rw-r--r--pylint/checkers/stdlib.py11
-rw-r--r--pylint/checkers/strings.py7
-rw-r--r--pylint/checkers/typecheck.py27
-rw-r--r--pylint/checkers/utils.py41
10 files changed, 61 insertions, 86 deletions
diff --git a/pylint/checkers/base.py b/pylint/checkers/base.py
index 2ef4b8f..13fc261 100644
--- a/pylint/checkers/base.py
+++ b/pylint/checkers/base.py
@@ -30,6 +30,7 @@ import astroid
import astroid.bases
import astroid.scoped_nodes
from astroid import are_exclusive, InferenceError
+from astroid import helpers
from pylint.interfaces import IAstroidChecker, INFERENCE, INFERENCE_FAILURE, HIGH
from pylint.utils import EmptyReport
@@ -41,9 +42,7 @@ from pylint.checkers.utils import (
is_builtin_object,
is_inside_except,
overrides_a_method,
- safe_infer,
get_argument_from_call,
- has_known_bases,
NoSuchArgumentError,
error_of_type,
unimplemented_abstract_methods,
@@ -178,7 +177,7 @@ def _determine_function_name_type(node):
if (isinstance(decorator, astroid.Name) or
(isinstance(decorator, astroid.Getattr) and
decorator.attrname == 'abstractproperty')):
- infered = safe_infer(decorator)
+ infered = helpers.safe_infer(decorator)
if infered and infered.qname() in PROPERTY_CLASSES:
return 'attr'
# If the function is decorated using the prop_method.{setter,getter}
@@ -669,7 +668,7 @@ functions, methods
inferred = None
emit = isinstance(test, (astroid.Const, ) + structs + const_nodes)
if not isinstance(test, except_nodes):
- inferred = safe_infer(test)
+ inferred = helpers.safe_infer(test)
if emit or isinstance(inferred, const_nodes):
self.add_message('using-constant-test', node=node)
@@ -952,7 +951,7 @@ functions, methods
def _check_reversed(self, node):
""" check that the argument to `reversed` is a sequence """
try:
- argument = safe_infer(get_argument_from_call(node, position=0))
+ argument = helpers.safe_infer(get_argument_from_call(node, position=0))
except NoSuchArgumentError:
self.add_message('missing-reversed-argument', node=node)
else:
@@ -1152,7 +1151,7 @@ class NameChecker(_BasicChecker):
if node.is_method():
if overrides_a_method(node.parent.frame(), node.name):
return
- confidence = (INFERENCE if has_known_bases(node.parent.frame())
+ confidence = (INFERENCE if helpers.has_known_bases(node.parent.frame())
else INFERENCE_FAILURE)
self._check_name(_determine_function_name_type(node),
@@ -1176,7 +1175,7 @@ class NameChecker(_BasicChecker):
self._check_name('inlinevar', node.name, node)
elif isinstance(frame, astroid.Module):
if isinstance(ass_type, astroid.Assign) and not in_loop(ass_type):
- if isinstance(safe_infer(ass_type.value), astroid.Class):
+ if isinstance(helpers.safe_infer(ass_type.value), astroid.Class):
self._check_name('class', node.name, node)
else:
if not _redefines_import(node):
@@ -1287,7 +1286,7 @@ class DocStringChecker(_BasicChecker):
ftype = node.is_method() and 'method' or 'function'
if isinstance(node.parent.frame(), astroid.Class):
overridden = False
- confidence = (INFERENCE if has_known_bases(node.parent.frame())
+ confidence = (INFERENCE if helpers.has_known_bases(node.parent.frame())
else INFERENCE_FAILURE)
# check if node is from a method overridden by its ancestor
for ancestor in node.parent.frame().ancestors():
@@ -1325,7 +1324,7 @@ class DocStringChecker(_BasicChecker):
if (node.body and isinstance(node.body[0], astroid.Discard) and
isinstance(node.body[0].value, astroid.CallFunc)):
# Most likely a string with a format call. Let's see.
- func = safe_infer(node.body[0].value.func)
+ func = helpers.safe_infer(node.body[0].value.func)
if (isinstance(func, astroid.BoundMethod)
and isinstance(func.bound, astroid.Instance)):
# Strings in Python 3, others in Python 2.
@@ -1378,7 +1377,7 @@ class LambdaForComprehensionChecker(_BasicChecker):
return
if not isinstance(node.args[0], astroid.Lambda):
return
- infered = safe_infer(node.func)
+ infered = helpers.safe_infer(node.func)
if (is_builtin_object(infered)
and infered.name in ['map', 'filter']):
self.add_message('deprecated-lambda', node=node)
diff --git a/pylint/checkers/classes.py b/pylint/checkers/classes.py
index 962cca5..c4f7ff0 100644
--- a/pylint/checkers/classes.py
+++ b/pylint/checkers/classes.py
@@ -26,13 +26,14 @@ from astroid.bases import Generator, BUILTINS
from astroid.exceptions import InconsistentMroError, DuplicateBasesError
from astroid import objects
from astroid.scoped_nodes import function_to_method
+from astroid import helpers
from pylint.interfaces import IAstroidChecker
from pylint.checkers import BaseChecker
from pylint.checkers.utils import (
PYMETHODS, SPECIAL_METHODS_PARAMS,
overrides_a_method, check_messages, is_attr_private,
- is_attr_protected, node_frame_class, safe_infer, is_builtin_object,
+ is_attr_protected, node_frame_class, is_builtin_object,
decorated_with_property, unimplemented_abstract_methods,
decorated_with)
from pylint.utils import deprecated_option, get_global_option
@@ -335,7 +336,7 @@ a metaclass class method.'}
a class or a type.
"""
for base in node.bases:
- ancestor = safe_infer(base)
+ ancestor = helpers.safe_infer(base)
if ancestor in (YES, None):
continue
if (isinstance(ancestor, astroid.Instance) and
@@ -554,7 +555,7 @@ a metaclass class method.'}
""" Check that the given assattr node
is defined in the class slots.
"""
- infered = safe_infer(node.expr)
+ infered = helpers.safe_infer(node.expr)
if infered and isinstance(infered, Instance):
klass = infered._proxied
if '__slots__' not in klass.locals or not klass.newstyle:
diff --git a/pylint/checkers/exceptions.py b/pylint/checkers/exceptions.py
index 63131a1..37b4c9f 100644
--- a/pylint/checkers/exceptions.py
+++ b/pylint/checkers/exceptions.py
@@ -19,6 +19,7 @@ import sys
import astroid
from astroid import YES, Instance, unpack_infer, List, Tuple
+from astroid import helpers
from logilab.common.compat import builtins
import six
@@ -27,9 +28,7 @@ from pylint.checkers.utils import (
is_raising,
check_messages,
inherit_from_std_ex,
- EXCEPTIONS_MODULE,
- has_known_bases,
- safe_infer)
+ EXCEPTIONS_MODULE)
from pylint.interfaces import IAstroidChecker
@@ -50,7 +49,7 @@ def _annotated_unpack_infer(stmt, context=None):
"""
if isinstance(stmt, (List, Tuple)):
for elt in stmt.elts:
- inferred = safe_infer(elt)
+ inferred = helpers.safe_infer(elt)
if inferred and inferred is not YES:
yield elt, inferred
return
@@ -168,7 +167,7 @@ class ExceptionsChecker(BaseChecker):
An exception context can be only `None` or an exception.
"""
- cause = safe_infer(node.cause)
+ cause = helpers.safe_infer(node.cause)
if cause in (YES, None):
return
if isinstance(cause, astroid.Const):
@@ -204,7 +203,7 @@ class ExceptionsChecker(BaseChecker):
# Verifying the other arguments is not
# the scope of this check.
first = expr.elts[0]
- inferred = safe_infer(first)
+ inferred = helpers.safe_infer(first)
if isinstance(inferred, Instance):
# pylint: disable=protected-access
inferred = inferred._proxied
@@ -227,7 +226,7 @@ class ExceptionsChecker(BaseChecker):
expr = expr._proxied
if (isinstance(expr, astroid.Class) and
not inherit_from_std_ex(expr) and
- has_known_bases(expr)):
+ helpers.has_known_bases(expr)):
if expr.newstyle:
self.add_message('raising-non-exception', node=node)
else:
@@ -241,7 +240,7 @@ class ExceptionsChecker(BaseChecker):
def _check_catching_non_exception(self, handler, exc, part):
if isinstance(exc, astroid.Tuple):
# Check if it is a tuple of exceptions.
- inferred = [safe_infer(elt) for elt in exc.elts]
+ inferred = [helpers.safe_infer(elt) for elt in exc.elts]
if any(node is astroid.YES for node in inferred):
# Don't emit if we don't know every component.
return
@@ -273,7 +272,7 @@ class ExceptionsChecker(BaseChecker):
if (not inherit_from_std_ex(exc) and
exc.name not in self.builtin_exceptions):
- if has_known_bases(exc):
+ if helpers.has_known_bases(exc):
self.add_message('catching-non-exception',
node=handler.type,
args=(exc.name, ))
diff --git a/pylint/checkers/logging.py b/pylint/checkers/logging.py
index d8e3529..e074a18 100644
--- a/pylint/checkers/logging.py
+++ b/pylint/checkers/logging.py
@@ -15,6 +15,8 @@
"""
import astroid
+from astroid import helpers
+
from pylint import checkers
from pylint import interfaces
from pylint.checkers import utils
@@ -78,7 +80,7 @@ def is_method_call(callfunc_node, types=(), methods=()):
"""
if not isinstance(callfunc_node, astroid.CallFunc):
return False
- func = utils.safe_infer(callfunc_node.func)
+ func = helpers.safe_infer(callfunc_node.func)
return (isinstance(func, astroid.BoundMethod)
and isinstance(func.bound, astroid.Instance)
and (func.bound.name in types if types else True)
diff --git a/pylint/checkers/newstyle.py b/pylint/checkers/newstyle.py
index f74e7f1..035aea2 100644
--- a/pylint/checkers/newstyle.py
+++ b/pylint/checkers/newstyle.py
@@ -18,12 +18,12 @@
import sys
import astroid
+from astroid import helpers
from pylint.interfaces import IAstroidChecker, INFERENCE, INFERENCE_FAILURE, HIGH
from pylint.checkers import BaseChecker
from pylint.checkers.utils import (
check_messages,
- has_known_bases,
node_frame_class,
)
@@ -82,7 +82,7 @@ class NewStyleConflictChecker(BaseChecker):
style class definition.
"""
if '__slots__' in node and not node.newstyle:
- confidence = (INFERENCE if has_known_bases(node)
+ confidence = (INFERENCE if helpers.has_known_bases(node)
else INFERENCE_FAILURE)
self.add_message('slots-on-old-class', node=node,
confidence=confidence)
@@ -101,7 +101,7 @@ class NewStyleConflictChecker(BaseChecker):
if (isinstance(parent, astroid.Class) and
not parent.newstyle and
isinstance(node.func, astroid.Name)):
- confidence = (INFERENCE if has_known_bases(parent)
+ confidence = (INFERENCE if helpers.has_known_bases(parent)
else INFERENCE_FAILURE)
name = node.func.name
if name == 'property':
@@ -127,7 +127,7 @@ class NewStyleConflictChecker(BaseChecker):
if isinstance(call, astroid.CallFunc) and \
isinstance(call.func, astroid.Name) and \
call.func.name == 'super':
- confidence = (INFERENCE if has_known_bases(klass)
+ confidence = (INFERENCE if helpers.has_known_bases(klass)
else INFERENCE_FAILURE)
if not klass.newstyle:
# super should not be used on an old style class
diff --git a/pylint/checkers/python3.py b/pylint/checkers/python3.py
index 6738ec6..0c1965e 100644
--- a/pylint/checkers/python3.py
+++ b/pylint/checkers/python3.py
@@ -19,6 +19,8 @@ import tokenize
import astroid
from astroid import bases
+from astroid import helpers
+
from pylint import checkers, interfaces
from pylint.utils import WarningScope
from pylint.checkers import utils
@@ -446,7 +448,7 @@ class Python3Checker(checkers.BaseChecker):
args = []
if (isinstance(node.func, astroid.Getattr)
and node.func.attrname == 'sort'):
- inferred = utils.safe_infer(node.func.expr)
+ inferred = helpers.safe_infer(node.func.expr)
if not inferred:
return
@@ -457,7 +459,7 @@ class Python3Checker(checkers.BaseChecker):
elif (isinstance(node.func, astroid.Name)
and node.func.name == 'sorted'):
- inferred = utils.safe_infer(node.func)
+ inferred = helpers.safe_infer(node.func)
if not inferred:
return
diff --git a/pylint/checkers/stdlib.py b/pylint/checkers/stdlib.py
index a3a6106..d0b53ef 100644
--- a/pylint/checkers/stdlib.py
+++ b/pylint/checkers/stdlib.py
@@ -20,6 +20,7 @@ import sys
import astroid
from astroid.bases import Instance
+from astroid import helpers
from pylint.interfaces import IAstroidChecker
from pylint.checkers import BaseChecker
@@ -124,7 +125,7 @@ class StdlibChecker(BaseChecker):
def visit_callfunc(self, node):
"""Visit a CallFunc node."""
if hasattr(node, 'func'):
- infer = utils.safe_infer(node.func)
+ infer = helpers.safe_infer(node.func)
if infer:
if infer.root().name == OPEN_MODULE:
if getattr(node.func, 'name', None) in ('open', 'file'):
@@ -186,7 +187,7 @@ class StdlibChecker(BaseChecker):
except utils.NoSuchArgumentError:
return
if mode_arg:
- mode_arg = utils.safe_infer(mode_arg)
+ mode_arg = helpers.safe_infer(mode_arg)
if (isinstance(mode_arg, astroid.Const)
and not _check_mode_str(mode_arg.value)):
self.add_message('bad-open-mode', node=node,
@@ -194,17 +195,17 @@ class StdlibChecker(BaseChecker):
def _check_type_x_is_y(self, node, left, operator, right):
"""Check for expressions like type(x) == Y."""
- left_func = utils.safe_infer(left.func)
+ left_func = helpers.safe_infer(left.func)
if not (isinstance(left_func, astroid.Class)
and left_func.qname() == TYPE_QNAME):
return
if operator in ('is', 'is not') and _is_one_arg_pos_call(right):
- right_func = utils.safe_infer(right.func)
+ right_func = helpers.safe_infer(right.func)
if (isinstance(right_func, astroid.Class)
and right_func.qname() == TYPE_QNAME):
# type(x) == type(a)
- right_arg = utils.safe_infer(right.args[0])
+ right_arg = helpers.safe_infer(right.args[0])
if not isinstance(right_arg, LITERAL_NODE_TYPES):
# not e.g. type(x) == type([])
return
diff --git a/pylint/checkers/strings.py b/pylint/checkers/strings.py
index 2640835..305ab54 100644
--- a/pylint/checkers/strings.py
+++ b/pylint/checkers/strings.py
@@ -24,6 +24,7 @@ import string
import numbers
import astroid
+from astroid import helpers
from pylint.interfaces import ITokenChecker, IAstroidChecker, IRawChecker
from pylint.checkers import BaseChecker, BaseTokenChecker
@@ -208,7 +209,7 @@ def get_args(callfunc):
for arg in callfunc.args:
if isinstance(arg, astroid.Keyword):
- named[arg.arg] = utils.safe_infer(arg.value)
+ named[arg.arg] = helpers.safe_infer(arg.value)
else:
positional += 1
return positional, named
@@ -333,12 +334,12 @@ class StringMethodsChecker(BaseChecker):
@check_messages(*(MSGS.keys()))
def visit_callfunc(self, node):
- func = utils.safe_infer(node.func)
+ func = helpers.safe_infer(node.func)
if (isinstance(func, astroid.BoundMethod)
and isinstance(func.bound, astroid.Instance)
and func.bound.name in ('str', 'unicode', 'bytes')):
if func.name in ('strip', 'lstrip', 'rstrip') and node.args:
- arg = utils.safe_infer(node.args[0])
+ arg = helpers.safe_infer(node.args[0])
if not isinstance(arg, astroid.Const):
return
if len(arg.value) != len(set(arg.value)):
diff --git a/pylint/checkers/typecheck.py b/pylint/checkers/typecheck.py
index 8fd0892..d56e66b 100644
--- a/pylint/checkers/typecheck.py
+++ b/pylint/checkers/typecheck.py
@@ -27,14 +27,13 @@ from astroid import (
)
from astroid.bases import BUILTINS
from astroid import objects
+from astroid import helpers
from pylint.interfaces import IAstroidChecker, INFERENCE, INFERENCE_FAILURE
from pylint.checkers import BaseChecker
from pylint.checkers.utils import (
- safe_infer, is_super,
- check_messages, decorated_with_property,
- decorated_with, has_known_bases,
- node_ignores_exception)
+ is_super, check_messages, decorated_with_property,
+ decorated_with, node_ignores_exception)
MSGS = {
'E1101': ('%s %r has no %r member',
@@ -130,7 +129,7 @@ def _emit_no_member(node, owner, owner_name, attrname,
if isinstance(owner, astroid.Function) and owner.decorators:
return False
if isinstance(owner, Instance):
- if owner.has_dynamic_getattr() or not has_known_bases(owner):
+ if owner.has_dynamic_getattr() or not helpers.has_known_bases(owner):
return False
if isinstance(owner, objects.Super):
# Verify if we are dealing with an invalid Super object.
@@ -141,7 +140,7 @@ def _emit_no_member(node, owner, owner_name, attrname,
owner.super_mro()
except (MroError, SuperError):
return False
- if not all(map(has_known_bases, owner.type.mro())):
+ if not all(map(helpers.has_known_bases, owner.type.mro())):
return False
# explicit skipping of module member access
if owner.root().name in ignored_modules:
@@ -356,7 +355,7 @@ accessed. Python regular expressions are accepted.'}
"""
if not isinstance(node.value, astroid.CallFunc):
return
- function_node = safe_infer(node.value.func)
+ function_node = helpers.safe_infer(node.value.func)
# skip class, generator and incomplete function definition
if not (isinstance(function_node, astroid.Function) and
function_node.root().fully_defined()):
@@ -394,7 +393,7 @@ accessed. Python regular expressions are accepted.'}
# we will not handle them here, right now.
expr = node.func.expr
- klass = safe_infer(expr)
+ klass = helpers.safe_infer(expr)
if (klass is None or klass is astroid.YES or
not isinstance(klass, astroid.Instance)):
return
@@ -437,7 +436,7 @@ accessed. Python regular expressions are accepted.'}
else:
num_positional_args += 1
- called = safe_infer(node.func)
+ called = helpers.safe_infer(node.func)
# only function, generator and object defining __call__ are allowed
if called is not None and not called.callable():
self.add_message('not-callable', node=node,
@@ -594,7 +593,7 @@ accessed. Python regular expressions are accepted.'}
# If the types can be determined, only allow indices to be int,
# slice or instances with __index__.
- parent_type = safe_infer(node.parent.value)
+ parent_type = helpers.safe_infer(node.parent.value)
if not isinstance(parent_type, (astroid.Class, astroid.Instance)):
return
@@ -636,7 +635,7 @@ accessed. Python regular expressions are accepted.'}
if isinstance(node, astroid.ExtSlice):
index_type = node
else:
- index_type = safe_infer(node)
+ index_type = helpers.safe_infer(node)
if index_type is None or index_type is astroid.YES:
return
@@ -664,7 +663,7 @@ accessed. Python regular expressions are accepted.'}
if index is None:
continue
- index_type = safe_infer(index)
+ index_type = helpers.safe_infer(index)
if index_type is None or index_type is astroid.YES:
continue
@@ -691,7 +690,7 @@ accessed. Python regular expressions are accepted.'}
@check_messages('not-context-manager')
def visit_with(self, node):
for ctx_mgr, _ in node.items:
- infered = safe_infer(ctx_mgr)
+ infered = helpers.safe_infer(ctx_mgr)
if infered is None or infered is astroid.YES:
continue
@@ -710,7 +709,7 @@ accessed. Python regular expressions are accepted.'}
if isinstance(infered, astroid.Instance):
# If we do not know the bases of this class,
# just skip it.
- if not has_known_bases(infered):
+ if not helpers.has_known_bases(infered):
continue
# Just ignore mixin classes.
if self.config.ignore_mixin_members:
diff --git a/pylint/checkers/utils.py b/pylint/checkers/utils.py
index b3ff019..aff56b0 100644
--- a/pylint/checkers/utils.py
+++ b/pylint/checkers/utils.py
@@ -24,6 +24,7 @@ import string
import warnings
import astroid
+from astroid import helpers
from astroid import scoped_nodes
from logilab.common.compat import builtins
from six.moves import map # pylint: disable=redefined-builtin
@@ -133,24 +134,6 @@ def clobber_in_except(node):
return (False, None)
-def safe_infer(node):
- """return the inferred value for the given node.
- Return None if inference failed or if there is some ambiguity (more than
- one node has been inferred)
- """
- try:
- inferit = node.infer()
- value = next(inferit)
- except astroid.InferenceError:
- return
- try:
- next(inferit)
- return # None if there is ambiguity on the inferred node
- except astroid.InferenceError:
- return # there is some kind of ambiguity
- except StopIteration:
- return value
-
def is_super(node):
"""return True if the node is referencing the "super" builtin function
"""
@@ -479,23 +462,6 @@ def is_import_error(handler):
return error_of_type(handler, ImportError)
-def has_known_bases(klass):
- """Returns true if all base classes of a class could be inferred."""
- try:
- return klass._all_bases_known
- except AttributeError:
- pass
- for base in klass.bases:
- result = safe_infer(base)
- # TODO: check for A->B->A->B pattern in class structure too?
- if (not isinstance(result, astroid.Class) or
- result is klass or
- not has_known_bases(result)):
- klass._all_bases_known = False
- return False
- klass._all_bases_known = True
- return True
-
def decorated_with_property(node):
""" Detect if the given function node is decorated with a property. """
if not node.decorators:
@@ -598,3 +564,8 @@ def node_ignores_exception(node, exception):
if handles_errors or empty_handlers:
return True
return False
+
+
+# TODO(cpopa): deprecate these or leave them as aliases?
+safe_infer = astroid.helpers.safe_infer
+has_known_bases = astroid.helpers.has_known_bases