summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaudiu Popa <pcmanticore@gmail.com>2015-11-20 12:52:19 +0200
committerClaudiu Popa <pcmanticore@gmail.com>2015-11-20 12:52:19 +0200
commitfb6b47b10084423e6c43a30538cb8eca39ce7408 (patch)
treeba07148af593966260188a6b09fddcd4379a95f6
parentf137fdb1f38054fc5a1a967dbe6ff37a12ab9adb (diff)
downloadpylint-fb6b47b10084423e6c43a30538cb8eca39ce7408.tar.gz
Import has_known_bases and safe_infer back into pylint from astroid, until the latter stabilizes its API.
Currently astroid goes into a total revamp, having a couple of development branches with partially incompatible APIs, which means that pylint can't rely on the exact location of has_known_bases and safe_infer until astroid reaches a new major release. With this in mind, these two functions are backported in pylint again.
-rw-r--r--pylint/checkers/async.py5
-rw-r--r--pylint/checkers/base.py27
-rw-r--r--pylint/checkers/classes.py10
-rw-r--r--pylint/checkers/exceptions.py17
-rw-r--r--pylint/checkers/logging.py3
-rw-r--r--pylint/checkers/newstyle.py9
-rw-r--r--pylint/checkers/python3.py5
-rw-r--r--pylint/checkers/stdlib.py3
-rw-r--r--pylint/checkers/strings.py7
-rw-r--r--pylint/checkers/typecheck.py33
-rw-r--r--pylint/checkers/utils.py55
-rw-r--r--pylint/checkers/variables.py6
12 files changed, 106 insertions, 74 deletions
diff --git a/pylint/checkers/async.py b/pylint/checkers/async.py
index bd82931..c1914f4 100644
--- a/pylint/checkers/async.py
+++ b/pylint/checkers/async.py
@@ -17,7 +17,6 @@
import astroid
from astroid import exceptions
-from astroid import helpers
from pylint import checkers
from pylint.checkers import utils as checker_utils
@@ -53,7 +52,7 @@ class AsyncChecker(checkers.BaseChecker):
@checker_utils.check_messages('not-async-context-manager')
def visit_asyncwith(self, node):
for ctx_mgr, _ in node.items:
- infered = helpers.safe_infer(ctx_mgr)
+ infered = utils.safe_infer(ctx_mgr)
if infered is None or infered is astroid.YES:
continue
@@ -65,7 +64,7 @@ class AsyncChecker(checkers.BaseChecker):
if isinstance(infered, astroid.Instance):
# If we do not know the bases of this class,
# just skip it.
- if not helpers.has_known_bases(infered):
+ if not utils.has_known_bases(infered):
continue
# Just ignore mixin classes.
if self._ignore_mixin_members:
diff --git a/pylint/checkers/base.py b/pylint/checkers/base.py
index 6929a7a..fe2578e 100644
--- a/pylint/checkers/base.py
+++ b/pylint/checkers/base.py
@@ -28,7 +28,6 @@ import astroid
import astroid.bases
import astroid.scoped_nodes
from astroid import are_exclusive, InferenceError
-from astroid import helpers
from pylint.interfaces import (IAstroidChecker, ITokenChecker, INFERENCE,
INFERENCE_FAILURE, HIGH)
@@ -46,6 +45,8 @@ from pylint.checkers.utils import (
NoSuchArgumentError,
error_of_type,
unimplemented_abstract_methods,
+ has_known_bases,
+ safe_infer
)
from pylint.reporters.ureports.nodes import Table
@@ -188,7 +189,7 @@ def _determine_function_name_type(node):
if (isinstance(decorator, astroid.Name) or
(isinstance(decorator, astroid.Attribute) and
decorator.attrname == 'abstractproperty')):
- infered = helpers.safe_infer(decorator)
+ infered = safe_infer(decorator)
if infered and infered.qname() in PROPERTY_CLASSES:
return 'attr'
# If the function is decorated using the prop_method.{setter,getter}
@@ -735,7 +736,7 @@ functions, methods
inferred = None
emit = isinstance(test, (astroid.Const, ) + structs + const_nodes)
if not isinstance(test, except_nodes):
- inferred = helpers.safe_infer(test)
+ inferred = safe_infer(test)
if emit or isinstance(inferred, const_nodes):
self.add_message('using-constant-test', node=node)
@@ -1032,7 +1033,7 @@ functions, methods
def _check_reversed(self, node):
""" check that the argument to `reversed` is a sequence """
try:
- argument = helpers.safe_infer(get_argument_from_call(node, position=0))
+ argument = safe_infer(get_argument_from_call(node, position=0))
except NoSuchArgumentError:
pass
else:
@@ -1230,7 +1231,7 @@ class NameChecker(_BasicChecker):
if node.is_method():
if overrides_a_method(node.parent.frame(), node.name):
return
- confidence = (INFERENCE if helpers.has_known_bases(node.parent.frame())
+ confidence = (INFERENCE if has_known_bases(node.parent.frame())
else INFERENCE_FAILURE)
self._check_name(_determine_function_name_type(node),
@@ -1254,7 +1255,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(helpers.safe_infer(ass_type.value), astroid.ClassDef):
+ if isinstance(safe_infer(ass_type.value), astroid.ClassDef):
self._check_name('class', node.name, node)
else:
if not _redefines_import(node):
@@ -1365,7 +1366,7 @@ class DocStringChecker(_BasicChecker):
ftype = node.is_method() and 'method' or 'function'
if isinstance(node.parent.frame(), astroid.ClassDef):
overridden = False
- confidence = (INFERENCE if helpers.has_known_bases(node.parent.frame())
+ confidence = (INFERENCE if 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():
@@ -1403,7 +1404,7 @@ class DocStringChecker(_BasicChecker):
if (node.body and isinstance(node.body[0], astroid.Expr) and
isinstance(node.body[0].value, astroid.Call)):
# Most likely a string with a format call. Let's see.
- func = helpers.safe_infer(node.body[0].value.func)
+ func = 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.
@@ -1456,7 +1457,7 @@ class LambdaForComprehensionChecker(_BasicChecker):
return
if not isinstance(node.args[0], astroid.Lambda):
return
- infered = helpers.safe_infer(node.func)
+ infered = safe_infer(node.func)
if (is_builtin_object(infered)
and infered.name in ['map', 'filter']):
self.add_message('deprecated-lambda', node=node)
@@ -1472,7 +1473,7 @@ class RecommandationChecker(_BasicChecker):
@staticmethod
def _is_builtin(node, function):
- inferred = helpers.safe_infer(node)
+ inferred = safe_infer(node)
if not inferred:
return False
return is_builtin_object(inferred) and inferred.name == function
@@ -1617,17 +1618,17 @@ class ComparisonChecker(_BasicChecker):
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)
+ left_func = 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)
+ right_func = 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])
+ right_arg = 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/classes.py b/pylint/checkers/classes.py
index 5e941c5..2dc45e1 100644
--- a/pylint/checkers/classes.py
+++ b/pylint/checkers/classes.py
@@ -25,7 +25,6 @@ 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
@@ -34,7 +33,8 @@ from pylint.checkers.utils import (
overrides_a_method, check_messages, is_attr_private,
is_attr_protected, node_frame_class, is_builtin_object,
decorated_with_property, unimplemented_abstract_methods,
- decorated_with, class_is_abstract)
+ decorated_with, class_is_abstract,
+ safe_infer, has_known_bases)
from pylint.utils import deprecated_option, get_global_option
import six
@@ -353,7 +353,7 @@ a metaclass class method.'}
self._accessed.append(defaultdict(list))
self._check_bases_classes(node)
# if not an exception or a metaclass
- if node.type == 'class' and helpers.has_known_bases(node):
+ if node.type == 'class' and has_known_bases(node):
try:
node.local_attr('__init__')
except astroid.NotFoundError:
@@ -382,7 +382,7 @@ a metaclass class method.'}
a class or a type.
"""
for base in node.bases:
- ancestor = helpers.safe_infer(base)
+ ancestor = safe_infer(base)
if ancestor in (astroid.YES, None):
continue
if (isinstance(ancestor, astroid.Instance) and
@@ -602,7 +602,7 @@ a metaclass class method.'}
""" Check that the given assattr node
is defined in the class slots.
"""
- infered = helpers.safe_infer(node.expr)
+ infered = safe_infer(node.expr)
if infered and isinstance(infered, astroid.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 c068c98..b66ff8d 100644
--- a/pylint/checkers/exceptions.py
+++ b/pylint/checkers/exceptions.py
@@ -18,7 +18,6 @@ import inspect
import sys
import astroid
-from astroid import helpers
from six.moves import builtins
import six
@@ -27,7 +26,9 @@ from pylint.checkers.utils import (
is_raising,
check_messages,
inherit_from_std_ex,
- EXCEPTIONS_MODULE)
+ EXCEPTIONS_MODULE,
+ safe_infer,
+ has_known_bases)
from pylint.interfaces import IAstroidChecker
@@ -48,7 +49,7 @@ def _annotated_unpack_infer(stmt, context=None):
"""
if isinstance(stmt, (astroid.List, astroid.Tuple)):
for elt in stmt.elts:
- inferred = helpers.safe_infer(elt)
+ inferred = safe_infer(elt)
if inferred and inferred is not astroid.YES:
yield elt, inferred
return
@@ -194,7 +195,7 @@ class ExceptionsChecker(BaseChecker):
An exception context can be only `None` or an exception.
"""
- cause = helpers.safe_infer(node.cause)
+ cause = safe_infer(node.cause)
if cause in (astroid.YES, None):
return
if isinstance(cause, astroid.Const):
@@ -230,7 +231,7 @@ class ExceptionsChecker(BaseChecker):
# Verifying the other arguments is not
# the scope of this check.
first = expr.elts[0]
- inferred = helpers.safe_infer(first)
+ inferred = safe_infer(first)
if isinstance(inferred, astroid.Instance):
# pylint: disable=protected-access
inferred = inferred._proxied
@@ -253,7 +254,7 @@ class ExceptionsChecker(BaseChecker):
expr = expr._proxied
if (isinstance(expr, astroid.ClassDef) and
not inherit_from_std_ex(expr) and
- helpers.has_known_bases(expr)):
+ has_known_bases(expr)):
if expr.newstyle:
self.add_message('raising-non-exception', node=node)
else:
@@ -267,7 +268,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 = [helpers.safe_infer(elt) for elt in exc.elts]
+ inferred = [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
@@ -299,7 +300,7 @@ class ExceptionsChecker(BaseChecker):
if (not inherit_from_std_ex(exc) and
exc.name not in self.builtin_exceptions):
- if helpers.has_known_bases(exc):
+ if 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 9ef85dd..a5b1edf 100644
--- a/pylint/checkers/logging.py
+++ b/pylint/checkers/logging.py
@@ -15,7 +15,6 @@
"""
import astroid
-from astroid import helpers
from pylint import checkers
from pylint import interfaces
@@ -80,7 +79,7 @@ def is_method_call(callfunc_node, types=(), methods=()):
"""
if not isinstance(callfunc_node, astroid.Call):
return False
- func = helpers.safe_infer(callfunc_node.func)
+ func = utils.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 fe8fa1b..30bc6a6 100644
--- a/pylint/checkers/newstyle.py
+++ b/pylint/checkers/newstyle.py
@@ -18,13 +18,14 @@
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,
node_frame_class,
+ safe_infer,
+ has_known_bases
)
MSGS = {
@@ -82,7 +83,7 @@ class NewStyleConflictChecker(BaseChecker):
style class definition.
"""
if '__slots__' in node and not node.newstyle:
- confidence = (INFERENCE if helpers.has_known_bases(node)
+ confidence = (INFERENCE if has_known_bases(node)
else INFERENCE_FAILURE)
self.add_message('slots-on-old-class', node=node,
confidence=confidence)
@@ -101,7 +102,7 @@ class NewStyleConflictChecker(BaseChecker):
if (isinstance(parent, astroid.ClassDef) and
not parent.newstyle and
isinstance(node.func, astroid.Name)):
- confidence = (INFERENCE if helpers.has_known_bases(parent)
+ confidence = (INFERENCE if has_known_bases(parent)
else INFERENCE_FAILURE)
name = node.func.name
if name == 'property':
@@ -128,7 +129,7 @@ class NewStyleConflictChecker(BaseChecker):
isinstance(call.func, astroid.Name) and
call.func.name == 'super'):
continue
- confidence = (INFERENCE if helpers.has_known_bases(klass)
+ confidence = (INFERENCE if 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 bc78892..038c2c2 100644
--- a/pylint/checkers/python3.py
+++ b/pylint/checkers/python3.py
@@ -19,7 +19,6 @@ import tokenize
import astroid
from astroid import bases
-from astroid import helpers
from pylint import checkers, interfaces
from pylint.utils import WarningScope
@@ -448,7 +447,7 @@ class Python3Checker(checkers.BaseChecker):
kwargs = []
if (isinstance(node.func, astroid.Attribute)
and node.func.attrname == 'sort'):
- inferred = helpers.safe_infer(node.func.expr)
+ inferred = utils.safe_infer(node.func.expr)
if not inferred:
return
@@ -459,7 +458,7 @@ class Python3Checker(checkers.BaseChecker):
elif (isinstance(node.func, astroid.Name)
and node.func.name == 'sorted'):
- inferred = helpers.safe_infer(node.func)
+ inferred = utils.safe_infer(node.func)
if not inferred:
return
diff --git a/pylint/checkers/stdlib.py b/pylint/checkers/stdlib.py
index f583215..61df660 100644
--- a/pylint/checkers/stdlib.py
+++ b/pylint/checkers/stdlib.py
@@ -20,7 +20,6 @@ import sys
import astroid
from astroid.bases import Instance
-from astroid import helpers
from pylint.interfaces import IAstroidChecker
from pylint.checkers import BaseChecker
@@ -263,7 +262,7 @@ class StdlibChecker(BaseChecker):
except utils.NoSuchArgumentError:
return
if mode_arg:
- mode_arg = helpers.safe_infer(mode_arg)
+ mode_arg = utils.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,
diff --git a/pylint/checkers/strings.py b/pylint/checkers/strings.py
index 5fb9a44..31f025d 100644
--- a/pylint/checkers/strings.py
+++ b/pylint/checkers/strings.py
@@ -24,7 +24,6 @@ import string
import numbers
import astroid
-from astroid import helpers
from pylint.interfaces import ITokenChecker, IAstroidChecker, IRawChecker
from pylint.checkers import BaseChecker, BaseTokenChecker
@@ -206,7 +205,7 @@ def get_args(callfunc):
is the keyword arguments in a dict.
"""
if callfunc.keywords:
- named = {arg.arg: helpers.safe_infer(arg.value)
+ named = {arg.arg: utils.safe_infer(arg.value)
for arg in callfunc.keywords}
else:
named = {}
@@ -333,12 +332,12 @@ class StringMethodsChecker(BaseChecker):
@check_messages(*(MSGS.keys()))
def visit_call(self, node):
- func = helpers.safe_infer(node.func)
+ func = utils.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 = helpers.safe_infer(node.args[0])
+ arg = utils.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 f8c75dd..0f5d7af 100644
--- a/pylint/checkers/typecheck.py
+++ b/pylint/checkers/typecheck.py
@@ -27,7 +27,6 @@ import astroid.context
import astroid.arguments
from astroid import exceptions
from astroid import objects
-from astroid import helpers
from astroid import node_classes
import six
@@ -38,7 +37,9 @@ from pylint.checkers.utils import (
decorated_with, node_ignores_exception,
is_iterable, is_mapping, supports_membership_test,
is_comprehension, is_inside_abstract_class,
- supports_subscript)
+ supports_subscript,
+ safe_infer,
+ has_known_bases)
from pylint import utils
@@ -189,7 +190,7 @@ def _emit_no_member(node, owner, owner_name, ignored_mixins):
if isinstance(owner, astroid.FunctionDef) and owner.decorators:
return False
if isinstance(owner, astroid.Instance):
- if owner.has_dynamic_getattr() or not helpers.has_known_bases(owner):
+ if owner.has_dynamic_getattr() or not has_known_bases(owner):
return False
if isinstance(owner, objects.Super):
# Verify if we are dealing with an invalid Super object.
@@ -200,7 +201,7 @@ def _emit_no_member(node, owner, owner_name, ignored_mixins):
owner.super_mro()
except (exceptions.MroError, exceptions.SuperError):
return False
- if not all(map(helpers.has_known_bases, owner.type.mro())):
+ if not all(map(has_known_bases, owner.type.mro())):
return False
return True
@@ -400,7 +401,7 @@ accessed. Python regular expressions are accepted.'}
"""
if not isinstance(node.value, astroid.Call):
return
- function_node = helpers.safe_infer(node.value.func)
+ function_node = safe_infer(node.value.func)
# skip class, generator and incomplete function definition
if not (isinstance(function_node, astroid.FunctionDef) and
function_node.root().fully_defined()):
@@ -438,7 +439,7 @@ accessed. Python regular expressions are accepted.'}
# we will not handle them here, right now.
expr = node.func.expr
- klass = helpers.safe_infer(expr)
+ klass = safe_infer(expr)
if (klass is None or klass is astroid.YES or
not isinstance(klass, astroid.Instance)):
return
@@ -477,7 +478,7 @@ accessed. Python regular expressions are accepted.'}
num_positional_args = len(call_site.positional_arguments)
keyword_args = list(call_site.keyword_arguments.keys())
- called = helpers.safe_infer(node.func)
+ called = 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,
@@ -629,7 +630,7 @@ accessed. Python regular expressions are accepted.'}
# Look for index operations where the parent is a sequence type.
# If the types can be determined, only allow indices to be int,
# slice or instances with __index__.
- parent_type = helpers.safe_infer(node.parent.value)
+ parent_type = safe_infer(node.parent.value)
if not isinstance(parent_type, (astroid.ClassDef, astroid.Instance)):
return
@@ -670,7 +671,7 @@ accessed. Python regular expressions are accepted.'}
if isinstance(node, astroid.ExtSlice):
index_type = node
else:
- index_type = helpers.safe_infer(node)
+ index_type = safe_infer(node)
if index_type is None or index_type is astroid.YES:
return
# Constants must be of type int
@@ -702,7 +703,7 @@ accessed. Python regular expressions are accepted.'}
if index is None:
continue
- index_type = helpers.safe_infer(index)
+ index_type = safe_infer(index)
if index_type is None or index_type is astroid.YES:
continue
@@ -730,7 +731,7 @@ accessed. Python regular expressions are accepted.'}
def visit_with(self, node):
for ctx_mgr, _ in node.items:
context = astroid.context.InferenceContext()
- infered = helpers.safe_infer(ctx_mgr, context=context)
+ infered = safe_infer(ctx_mgr, context=context)
if infered is None or infered is astroid.YES:
continue
@@ -766,7 +767,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 helpers.has_known_bases(infered):
+ if not has_known_bases(infered):
continue
# Just ignore mixin classes.
if self.config.ignore_mixin_members:
@@ -806,7 +807,7 @@ accessed. Python regular expressions are accepted.'}
return
if is_comprehension(node):
return
- infered = helpers.safe_infer(node)
+ infered = safe_infer(node)
if infered is None or infered is astroid.YES:
return
if not supports_membership_test(infered):
@@ -830,7 +831,7 @@ accessed. Python regular expressions are accepted.'}
self.add_message('unsubscriptable-object',
args=node.value.as_string(),
node=node.value)
- infered = helpers.safe_infer(node.value)
+ infered = safe_infer(node.value)
if infered is None or infered is astroid.YES:
return
if not supports_subscript(infered):
@@ -870,7 +871,7 @@ class IterableChecker(BaseChecker):
return
if is_comprehension(node):
return
- infered = helpers.safe_infer(node)
+ infered = safe_infer(node)
if infered is None or infered is astroid.YES:
return
if not is_iterable(infered):
@@ -883,7 +884,7 @@ class IterableChecker(BaseChecker):
return
if isinstance(node, astroid.DictComp):
return
- infered = helpers.safe_infer(node)
+ infered = safe_infer(node)
if infered is None or infered is astroid.YES:
return
if not is_mapping(infered):
diff --git a/pylint/checkers/utils.py b/pylint/checkers/utils.py
index a3c8c01..b85c237 100644
--- a/pylint/checkers/utils.py
+++ b/pylint/checkers/utils.py
@@ -24,7 +24,6 @@ import string
import warnings
import astroid
-from astroid import helpers
from astroid import scoped_nodes
import six
from six.moves import map, builtins # pylint: disable=redefined-builtin
@@ -644,7 +643,7 @@ def is_inside_abstract_class(node):
def is_iterable(value):
if isinstance(value, astroid.ClassDef):
- if not helpers.has_known_bases(value):
+ if not has_known_bases(value):
return True
# classobj can only be iterable if it has an iterable metaclass
meta = value.metaclass()
@@ -652,7 +651,7 @@ def is_iterable(value):
if _supports_iteration_protocol(meta):
return True
if isinstance(value, astroid.Instance):
- if not helpers.has_known_bases(value):
+ if not has_known_bases(value):
return True
if _supports_iteration_protocol(value):
return True
@@ -661,7 +660,7 @@ def is_iterable(value):
def is_mapping(value):
if isinstance(value, astroid.ClassDef):
- if not helpers.has_known_bases(value):
+ if not has_known_bases(value):
return True
# classobj can only be a mapping if it has a metaclass is mapping
meta = value.metaclass()
@@ -669,7 +668,7 @@ def is_mapping(value):
if _supports_mapping_protocol(meta):
return True
if isinstance(value, astroid.Instance):
- if not helpers.has_known_bases(value):
+ if not has_known_bases(value):
return True
if _supports_mapping_protocol(value):
return True
@@ -678,13 +677,13 @@ def is_mapping(value):
def supports_membership_test(value):
if isinstance(value, astroid.ClassDef):
- if not helpers.has_known_bases(value):
+ if not has_known_bases(value):
return True
meta = value.metaclass()
if meta is not None and _supports_membership_test_protocol(meta):
return True
if isinstance(value, astroid.Instance):
- if not helpers.has_known_bases(value):
+ if not has_known_bases(value):
return True
if _supports_membership_test_protocol(value):
return True
@@ -693,18 +692,52 @@ def supports_membership_test(value):
def supports_subscript(value):
if isinstance(value, astroid.ClassDef):
- if not helpers.has_known_bases(value):
+ if not has_known_bases(value):
return False
meta = value.metaclass()
if meta is not None and _supports_subscript_protocol(meta):
return True
if isinstance(value, astroid.Instance):
- if not helpers.has_known_bases(value):
+ if not has_known_bases(value):
return True
if _supports_subscript_protocol(value):
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
+def safe_infer(node, context=None):
+ """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(context=context)
+ 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 has_known_bases(klass, context=None):
+ """Return 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, context=context)
+ # TODO: check for A->B->A->B pattern in class structure too?
+ if (not isinstance(result, astroid.ClassDef) or
+ result is klass or
+ not has_known_bases(result, context=context)):
+ klass._all_bases_known = False
+ return False
+ klass._all_bases_known = True
+ return True
diff --git a/pylint/checkers/variables.py b/pylint/checkers/variables.py
index d813e1f..af87776 100644
--- a/pylint/checkers/variables.py
+++ b/pylint/checkers/variables.py
@@ -21,7 +21,6 @@ import re
from copy import copy
import astroid
-from astroid import helpers
from astroid import modutils
from pylint.interfaces import IAstroidChecker, INFERENCE, INFERENCE_FAILURE, HIGH
@@ -32,7 +31,8 @@ from pylint.checkers.utils import (
is_defined_before, is_error, is_func_default, is_func_decorator,
assign_parent, check_messages, is_inside_except, clobber_in_except,
get_all_elements, has_known_bases, node_ignores_exception,
- is_inside_abstract_class, is_comprehension, is_iterable)
+ is_inside_abstract_class, is_comprehension, is_iterable,
+ safe_infer, has_known_bases)
import six
SPECIAL_OBJ = re.compile("^_{2}[a-z]+_{2}$")
@@ -1034,7 +1034,7 @@ builtins. Remember that you should avoid to define new builtins when possible.'
targets = node.targets[0].itered()
try:
- infered = helpers.safe_infer(node.value)
+ infered = safe_infer(node.value)
if infered is not None:
self._check_unpacking(infered, node, targets)
except astroid.InferenceError: