diff options
author | Claudiu Popa <cpopa@cloudbasesolutions.com> | 2015-07-06 19:57:11 +0300 |
---|---|---|
committer | Claudiu Popa <cpopa@cloudbasesolutions.com> | 2015-07-06 19:57:11 +0300 |
commit | 3ba401db3bd21a91449159b97a438ee23625eadc (patch) | |
tree | 39e271d82e601af6275428f2c668e51ea11ffc9d | |
parent | 7596535e16a1e9cd861aecfb36131c43f0edfe12 (diff) | |
download | pylint-3ba401db3bd21a91449159b97a438ee23625eadc.tar.gz |
Use safe_infer and has_known_bases from astroid.helpers. Closes issue #593.
-rw-r--r-- | pylint/checkers/base.py | 19 | ||||
-rw-r--r-- | pylint/checkers/classes.py | 7 | ||||
-rw-r--r-- | pylint/checkers/exceptions.py | 17 | ||||
-rw-r--r-- | pylint/checkers/logging.py | 4 | ||||
-rw-r--r-- | pylint/checkers/newstyle.py | 8 | ||||
-rw-r--r-- | pylint/checkers/python3.py | 6 | ||||
-rw-r--r-- | pylint/checkers/stdlib.py | 11 | ||||
-rw-r--r-- | pylint/checkers/strings.py | 7 | ||||
-rw-r--r-- | pylint/checkers/typecheck.py | 27 | ||||
-rw-r--r-- | pylint/checkers/utils.py | 41 |
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 |