示例#1
0
    def _check_catching_non_exception(self, handler, exc, part):
        if isinstance(exc, astroid.Tuple):
            # Check if it is a tuple of exceptions.
            inferred = [utils.safe_infer(elt) for elt in exc.elts]
            if any(node is astroid.Uninferable for node in inferred):
                # Don't emit if we don't know every component.
                return
            if all(
                node
                and (utils.inherit_from_std_ex(node) or not utils.has_known_bases(node))
                for node in inferred
            ):
                return

        if not isinstance(exc, astroid.ClassDef):
            # Don't emit the warning if the inferred stmt
            # is None, but the exception handler is something else,
            # maybe it was redefined.
            if isinstance(exc, astroid.Const) and exc.value is None:
                if (
                    isinstance(handler.type, astroid.Const)
                    and handler.type.value is None
                ) or handler.type.parent_of(exc):
                    # If the exception handler catches None or
                    # the exception component, which is None, is
                    # defined by the entire exception handler, then
                    # emit a warning.
                    self.add_message(
                        "catching-non-exception",
                        node=handler.type,
                        args=(part.as_string(),),
                    )
            else:
                self.add_message(
                    "catching-non-exception",
                    node=handler.type,
                    args=(part.as_string(),),
                )
            return

        if (
            not utils.inherit_from_std_ex(exc)
            and exc.name not in self._builtin_exceptions
        ):
            if utils.has_known_bases(exc):
                self.add_message(
                    "catching-non-exception", node=handler.type, args=(exc.name,)
                )
示例#2
0
    def _check_catching_non_exception(self, handler, exc, part):
        if isinstance(exc, astroid.Tuple):
            # Check if it is a tuple of exceptions.
            inferred = [utils.safe_infer(elt) for elt in exc.elts]
            if any(node is astroid.Uninferable for node in inferred):
                # Don't emit if we don't know every component.
                return
            if all(
                node
                and (utils.inherit_from_std_ex(node) or not utils.has_known_bases(node))
                for node in inferred
            ):
                return

        if not isinstance(exc, astroid.ClassDef):
            # Don't emit the warning if the infered stmt
            # is None, but the exception handler is something else,
            # maybe it was redefined.
            if isinstance(exc, astroid.Const) and exc.value is None:
                if (
                    isinstance(handler.type, astroid.Const)
                    and handler.type.value is None
                ) or handler.type.parent_of(exc):
                    # If the exception handler catches None or
                    # the exception component, which is None, is
                    # defined by the entire exception handler, then
                    # emit a warning.
                    self.add_message(
                        "catching-non-exception",
                        node=handler.type,
                        args=(part.as_string(),),
                    )
            else:
                self.add_message(
                    "catching-non-exception",
                    node=handler.type,
                    args=(part.as_string(),),
                )
            return

        if (
            not utils.inherit_from_std_ex(exc)
            and exc.name not in self._builtin_exceptions
        ):
            if utils.has_known_bases(exc):
                self.add_message(
                    "catching-non-exception", node=handler.type, args=(exc.name,)
                )
示例#3
0
    def visit_asyncwith(self, node):
        for ctx_mgr, _ in node.items:
            infered = checker_utils.safe_infer(ctx_mgr)
            if infered is None or infered is astroid.YES:
                continue

            if isinstance(infered, astroid.Instance):
                try:
                    infered.getattr('__aenter__')
                    infered.getattr('__aexit__')
                except exceptions.NotFoundError:
                    if isinstance(infered, astroid.Instance):
                        # If we do not know the bases of this class,
                        # just skip it.
                        if not checker_utils.has_known_bases(infered):
                            continue
                        # Just ignore mixin classes.
                        if self._ignore_mixin_members:
                            if infered.name[-5:].lower() == 'mixin':
                                continue
                else:
                    continue

            self.add_message('not-async-context-manager',
                             node=node, args=(infered.name, ))
示例#4
0
    def visit_asyncwith(self, node):
        for ctx_mgr, _ in node.items:
            inferred = checker_utils.safe_infer(ctx_mgr)
            if inferred is None or inferred is astroid.Uninferable:
                continue

            if isinstance(inferred, bases.AsyncGenerator):
                # Check if we are dealing with a function decorated
                # with contextlib.asynccontextmanager.
                if decorated_with(inferred.parent, self._async_generators):
                    continue
            else:
                try:
                    inferred.getattr("__aenter__")
                    inferred.getattr("__aexit__")
                except exceptions.NotFoundError:
                    if isinstance(inferred, astroid.Instance):
                        # If we do not know the bases of this class,
                        # just skip it.
                        if not checker_utils.has_known_bases(inferred):
                            continue
                        # Just ignore mixin classes.
                        if self._ignore_mixin_members:
                            if inferred.name[-5:].lower() == "mixin":
                                continue
                else:
                    continue

            self.add_message("not-async-context-manager",
                             node=node,
                             args=(inferred.name, ))
示例#5
0
    def visit_asyncwith(self, node):
        for ctx_mgr, _ in node.items:
            infered = checker_utils.safe_infer(ctx_mgr)
            if infered is None or infered is astroid.YES:
                continue

            if isinstance(infered, astroid.Instance):
                try:
                    infered.getattr('__aenter__')
                    infered.getattr('__aexit__')
                except exceptions.NotFoundError:
                    if isinstance(infered, astroid.Instance):
                        # If we do not know the bases of this class,
                        # just skip it.
                        if not checker_utils.has_known_bases(infered):
                            continue
                        # Just ignore mixin classes.
                        if self._ignore_mixin_members:
                            if infered.name[-5:].lower() == 'mixin':
                                continue
                else:
                    continue

            self.add_message('not-async-context-manager',
                             node=node,
                             args=(infered.name, ))
示例#6
0
    def visit_functiondef(self, node: nodes.FunctionDef) -> None:
        if self.linter.namespace.no_docstring_rgx.match(node.name) is None:
            ftype = "method" if node.is_method() else "function"
            if (is_property_setter(node) or is_property_deleter(node)
                    or is_overload_stub(node)):
                return

            if isinstance(node.parent.frame(future=True), nodes.ClassDef):
                overridden = False
                confidence = (interfaces.INFERENCE if utils.has_known_bases(
                    node.parent.frame(
                        future=True)) else interfaces.INFERENCE_FAILURE)
                # check if node is from a method overridden by its ancestor
                for ancestor in node.parent.frame(future=True).ancestors():
                    if ancestor.qname() == "builtins.object":
                        continue
                    if node.name in ancestor and isinstance(
                            ancestor[node.name], nodes.FunctionDef):
                        overridden = True
                        break
                self._check_docstring(
                    ftype,
                    node,
                    report_missing=not overridden,
                    confidence=confidence  # type: ignore[arg-type]
                )
            elif isinstance(node.parent.frame(future=True), nodes.Module):
                self._check_docstring(ftype, node)  # type: ignore[arg-type]
            else:
                return
示例#7
0
 def visit_classdef(self, node: nodes.ClassDef) -> None:
     # TODO (Typing): This function can be called from visit_instance
     #  with the return type of instance._proxied (not typed right now)
     if not utils.inherit_from_std_ex(node) and utils.has_known_bases(node):
         if node.newstyle:
             self._checker.add_message("raising-non-exception",
                                       node=self._node)
示例#8
0
 def visit_classdef(self, cls):
     if (not utils.inherit_from_std_ex(cls) and
             utils.has_known_bases(cls)):
         if cls.newstyle:
             self._checker.add_message('raising-non-exception', node=self._node)
         else:
             self._checker.add_message('nonstandard-exception', node=self._node)
示例#9
0
    def visit_asyncwith(self, node):
        for ctx_mgr, _ in node.items:
            inferred = checker_utils.safe_infer(ctx_mgr)
            if inferred is None or inferred is astroid.Uninferable:
                continue

            if isinstance(inferred, bases.AsyncGenerator):
                # Check if we are dealing with a function decorated
                # with contextlib.asynccontextmanager.
                if decorated_with(inferred.parent, self._async_generators):
                    continue
            else:
                try:
                    inferred.getattr("__aenter__")
                    inferred.getattr("__aexit__")
                except exceptions.NotFoundError:
                    if isinstance(inferred, astroid.Instance):
                        # If we do not know the bases of this class,
                        # just skip it.
                        if not checker_utils.has_known_bases(inferred):
                            continue
                        # Just ignore mixin classes.
                        if self._ignore_mixin_members:
                            if inferred.name[-5:].lower() == "mixin":
                                continue
                else:
                    continue

            self.add_message(
                "not-async-context-manager", node=node, args=(inferred.name,)
            )
示例#10
0
 def visit_classdef(self, cls):
     if (not utils.inherit_from_std_ex(cls) and
             utils.has_known_bases(cls)):
         if cls.newstyle:
             self._checker.add_message('raising-non-exception', node=self._node)
         else:
             self._checker.add_message('nonstandard-exception', node=self._node)
示例#11
0
 def visit_callfunc(self, node):
     """check property usage"""
     parent = node.parent.frame()
     if isinstance(parent, astroid.Class) and not parent.newstyle and isinstance(node.func, astroid.Name):
         confidence = INFERENCE if has_known_bases(parent) else INFERENCE_FAILURE
         name = node.func.name
         if name == "property":
             self.add_message("property-on-old-class", node=node, confidence=confidence)
示例#12
0
 def _check_binop_errors(self, node):
     for error in node.type_errors():
         # Let the error customize its output.
         if any(isinstance(obj, astroid.ClassDef) and not has_known_bases(obj)
                for obj in (error.left_type, error.right_type)):
             continue
         self.add_message('unsupported-binary-operation',
                          args=str(error), node=node)
示例#13
0
 def _check_binop_errors(self, node):
     for error in node.type_errors():
         # Let the error customize its output.
         if any(isinstance(obj, astroid.ClassDef) and not has_known_bases(obj)
                for obj in (error.left_type, error.right_type)):
             continue
         self.add_message('unsupported-binary-operation',
                          args=str(error), node=node)
示例#14
0
    def visit_function(self, node):
        """check use of super"""
        # ignore actual functions or method within a new style class
        if not node.is_method():
            return
        klass = node.parent.frame()
        for stmt in node.nodes_of_class(astroid.CallFunc):
            if node_frame_class(stmt) != node_frame_class(node):
                # Don't look down in other scopes.
                continue
            expr = stmt.func
            if not isinstance(expr, astroid.Getattr):
                continue
            call = expr.expr
            # skip the test if using super
            if isinstance(call, astroid.CallFunc) and \
               isinstance(call.func, astroid.Name) and \
               call.func.name == 'super':
                confidence = (INFERENCE
                              if has_known_bases(klass) else INFERENCE_FAILURE)
                if not klass.newstyle:
                    # super should not be used on an old style class
                    self.add_message('super-on-old-class',
                                     node=node,
                                     confidence=confidence)
                else:
                    # super first arg should be the class
                    if not call.args and sys.version_info[0] == 3:
                        # unless Python 3
                        continue

                    try:
                        supcls = (call.args and next(call.args[0].infer())
                                  or None)
                    except astroid.InferenceError:
                        continue

                    if supcls is None:
                        self.add_message('missing-super-argument',
                                         node=call,
                                         confidence=confidence)
                        continue

                    if klass is not supcls:
                        name = None
                        # if supcls is not YES, then supcls was infered
                        # and use its name. Otherwise, try to look
                        # for call.args[0].name
                        if supcls is not astroid.YES:
                            name = supcls.name
                        else:
                            if hasattr(call.args[0], 'name'):
                                name = call.args[0].name
                        if name is not None:
                            self.add_message('bad-super-call',
                                             node=call,
                                             args=(name, ),
                                             confidence=confidence)
示例#15
0
 def _check_raise_value(self, node, expr):
     """check for bad values, string exception and class inheritance
     """
     value_found = True
     if isinstance(expr, astroid.Const):
         value = expr.value
         if not isinstance(value, str):
             # raising-string will be emitted from python3 porting checker.
             self.add_message('raising-bad-type', node=node,
                              args=value.__class__.__name__)
     elif ((isinstance(expr, astroid.Name) and
            expr.name in ('None', 'True', 'False')) or
           isinstance(expr, (astroid.List, astroid.Dict, astroid.Tuple,
                             astroid.Module, astroid.FunctionDef))):
         emit = True
         if not PY3K and isinstance(expr, astroid.Tuple) and expr.elts:
             # On Python 2, using the following is not an error:
             #    raise (ZeroDivisionError, None)
             #    raise (ZeroDivisionError, )
             # What's left to do is to check that the first
             # argument is indeed an exception.
             # Verifying the other arguments is not
             # the scope of this check.
             first = expr.elts[0]
             inferred = safe_infer(first)
             if isinstance(inferred, astroid.Instance):
                 # pylint: disable=protected-access
                 inferred = inferred._proxied
             if (inferred is astroid.YES or
                     isinstance(inferred, astroid.ClassDef)
                     and inherit_from_std_ex(inferred)):
                 emit = False
         if emit:
             self.add_message('raising-bad-type',
                              node=node,
                              args=expr.name)
     elif ((isinstance(expr, astroid.Name) and expr.name == 'NotImplemented')
           or (isinstance(expr, astroid.Call) and
               isinstance(expr.func, astroid.Name) and
               expr.func.name == 'NotImplemented')):
         self.add_message('notimplemented-raised', node=node)
     elif isinstance(expr, (astroid.Instance, astroid.ClassDef)):
         if isinstance(expr, astroid.Instance):
             # pylint: disable=protected-access
             expr = expr._proxied
         if (isinstance(expr, astroid.ClassDef) and
                 not inherit_from_std_ex(expr) and
                 has_known_bases(expr)):
             if expr.newstyle:
                 self.add_message('raising-non-exception', node=node)
             else:
                 self.add_message('nonstandard-exception', node=node)
         else:
             value_found = False
     else:
         value_found = False
     return value_found
示例#16
0
 def _check_raise_value(self, node, expr):
     """check for bad values, string exception and class inheritance
     """
     value_found = True
     if isinstance(expr, astroid.Const):
         value = expr.value
         if not isinstance(value, str):
             # raising-string will be emitted from python3 porting checker.
             self.add_message('raising-bad-type',
                              node=node,
                              args=value.__class__.__name__)
     elif ((isinstance(expr, astroid.Name)
            and expr.name in ('None', 'True', 'False'))
           or isinstance(expr, (astroid.List, astroid.Dict, astroid.Tuple,
                                astroid.Module, astroid.FunctionDef))):
         emit = True
         if not PY3K and isinstance(expr, astroid.Tuple) and expr.elts:
             # On Python 2, using the following is not an error:
             #    raise (ZeroDivisionError, None)
             #    raise (ZeroDivisionError, )
             # What's left to do is to check that the first
             # argument is indeed an exception.
             # Verifying the other arguments is not
             # the scope of this check.
             first = expr.elts[0]
             inferred = safe_infer(first)
             if isinstance(inferred, astroid.Instance):
                 # pylint: disable=protected-access
                 inferred = inferred._proxied
             if (inferred is astroid.YES
                     or isinstance(inferred, astroid.ClassDef)
                     and inherit_from_std_ex(inferred)):
                 emit = False
         if emit:
             self.add_message('raising-bad-type', node=node, args=expr.name)
     elif (
         (isinstance(expr, astroid.Name) and expr.name == 'NotImplemented')
             or (isinstance(expr, astroid.Call)
                 and isinstance(expr.func, astroid.Name)
                 and expr.func.name == 'NotImplemented')):
         self.add_message('notimplemented-raised', node=node)
     elif isinstance(expr, (astroid.Instance, astroid.ClassDef)):
         if isinstance(expr, astroid.Instance):
             # pylint: disable=protected-access
             expr = expr._proxied
         if (isinstance(expr, astroid.ClassDef)
                 and not inherit_from_std_ex(expr)
                 and has_known_bases(expr)):
             if expr.newstyle:
                 self.add_message('raising-non-exception', node=node)
             else:
                 self.add_message('nonstandard-exception', node=node)
         else:
             value_found = False
     else:
         value_found = False
     return value_found
示例#17
0
    def visit_functiondef(self, node):
        """check use of super"""
        # ignore actual functions or method within a new style class
        if not node.is_method():
            return
        klass = node.parent.frame()
        for stmt in node.nodes_of_class(astroid.Call):
            if node_frame_class(stmt) != node_frame_class(node):
                # Don't look down in other scopes.
                continue
            expr = stmt.func
            if not isinstance(expr, astroid.Attribute):
                continue
            call = expr.expr
            # skip the test if using super
            if not (isinstance(call, astroid.Call) and
                    isinstance(call.func, astroid.Name) and
                    call.func.name == 'super'):
                continue
            confidence = (INFERENCE if has_known_bases(klass)
                          else INFERENCE_FAILURE)
            if not klass.newstyle:
                # super should not be used on an old style class
                self.add_message('super-on-old-class', node=node,
                                 confidence=confidence)
            else:
                # super first arg should be the class
                if not call.args and sys.version_info[0] == 3:
                    # unless Python 3
                    continue

                try:
                    supcls = (call.args and next(call.args[0].infer())
                              or None)
                except astroid.InferenceError:
                    continue

                if supcls is None:
                    self.add_message('missing-super-argument', node=call,
                                     confidence=confidence)
                    continue

                if klass is not supcls:
                    name = None
                    # if supcls is not YES, then supcls was infered
                    # and use its name. Otherwise, try to look
                    # for call.args[0].name
                    if supcls is not astroid.YES:
                        name = supcls.name
                    else:
                        if hasattr(call.args[0], 'name'):
                            name = call.args[0].name
                    if name is not None:
                        self.add_message('bad-super-call', node=call, args=(name, ),
                                         confidence=confidence)
示例#18
0
 def visit_call(self, node):
     """check property usage"""
     parent = node.parent.frame()
     if (isinstance(parent, astroid.ClassDef) and
             not parent.newstyle and
             isinstance(node.func, astroid.Name)):
         confidence = (INFERENCE if has_known_bases(parent)
                       else INFERENCE_FAILURE)
         name = node.func.name
         if name == 'property':
             self.add_message('property-on-old-class', node=node,
                              confidence=confidence)
示例#19
0
    def visit_with(self, node):
        for ctx_mgr, _ in node.items:
            context = astroid.context.InferenceContext()
            infered = safe_infer(ctx_mgr, context=context)
            if infered is None or infered is astroid.YES:
                continue

            if isinstance(infered, bases.Generator):
                # Check if we are dealing with a function decorated
                # with contextlib.contextmanager.
                if decorated_with(infered.parent,
                                  self.config.contextmanager_decorators):
                    continue
                # If the parent of the generator is not the context manager itself,
                # that means that it could have been returned from another
                # function which was the real context manager.
                # The following approach is more of a hack rather than a real
                # solution: walk all the inferred statements for the
                # given *ctx_mgr* and if you find one function scope
                # which is decorated, consider it to be the real
                # manager and give up, otherwise emit not-context-manager.
                # See the test file for not_context_manager for a couple
                # of self explaining tests.
                for path in six.moves.filter(None, _unflatten(context.path)):
                    scope = path.scope()
                    if not isinstance(scope, astroid.FunctionDef):
                        continue
                    if decorated_with(scope,
                                      self.config.contextmanager_decorators):
                        break
                else:
                    self.add_message('not-context-manager',
                                     node=node,
                                     args=(infered.name, ))
            else:
                try:
                    infered.getattr('__enter__')
                    infered.getattr('__exit__')
                except exceptions.NotFoundError:
                    if isinstance(infered, astroid.Instance):
                        # If we do not know the bases of this class,
                        # just skip it.
                        if not has_known_bases(infered):
                            continue
                        # Just ignore mixin classes.
                        if self.config.ignore_mixin_members:
                            if infered.name[-5:].lower() == 'mixin':
                                continue

                    self.add_message('not-context-manager',
                                     node=node,
                                     args=(infered.name, ))
示例#20
0
文件: classes.py 项目: yannack/pylint
 def visit_classdef(self, node):
     """init visit variable _accessed
     """
     self._accessed.append(defaultdict(list))
     self._check_bases_classes(node)
     # if not an exception or a metaclass
     if node.type == 'class' and has_known_bases(node):
         try:
             node.local_attr('__init__')
         except astroid.NotFoundError:
             self.add_message('no-init', args=node, node=node)
     self._check_slots(node)
     self._check_proper_bases(node)
     self._check_consistent_mro(node)
示例#21
0
 def visit_class(self, node):
     """ Check __slots__ in old style classes and old
     style class definition.
     """
     if "__slots__" in node and not node.newstyle:
         confidence = INFERENCE if has_known_bases(node) else INFERENCE_FAILURE
         self.add_message("slots-on-old-class", node=node, confidence=confidence)
     # The node type could be class, exception, metaclass, or
     # interface.  Presumably, the non-class-type nodes would always
     # have an explicit base class anyway.
     if not node.bases and node.type == "class" and not node.metaclass():
         # We use confidence HIGH here because this message should only ever
         # be emitted for classes at the root of the inheritance hierarchyself.
         self.add_message("old-style-class", node=node, confidence=HIGH)
示例#22
0
 def visit_classdef(self, node):
     """init visit variable _accessed
     """
     self._accessed.append(defaultdict(list))
     self._check_bases_classes(node)
     # if not an exception or a metaclass
     if node.type == 'class' and has_known_bases(node):
         try:
             node.local_attr('__init__')
         except astroid.NotFoundError:
             self.add_message('no-init', args=node, node=node)
     self._check_slots(node)
     self._check_proper_bases(node)
     self._check_consistent_mro(node)
示例#23
0
    def visit_with(self, node):
        for ctx_mgr, _ in node.items:
            context = astroid.context.InferenceContext()
            infered = safe_infer(ctx_mgr, context=context)
            if infered is None or infered is astroid.YES:
                continue

            if isinstance(infered, bases.Generator):
                # Check if we are dealing with a function decorated
                # with contextlib.contextmanager.
                if decorated_with(infered.parent,
                                  self.config.contextmanager_decorators):
                    continue
                # If the parent of the generator is not the context manager itself,
                # that means that it could have been returned from another
                # function which was the real context manager.
                # The following approach is more of a hack rather than a real
                # solution: walk all the inferred statements for the
                # given *ctx_mgr* and if you find one function scope
                # which is decorated, consider it to be the real
                # manager and give up, otherwise emit not-context-manager.
                # See the test file for not_context_manager for a couple
                # of self explaining tests.
                for path in six.moves.filter(None, _unflatten(context.path)):
                    scope = path.scope()
                    if not isinstance(scope, astroid.FunctionDef):
                        continue
                    if decorated_with(scope,
                                      self.config.contextmanager_decorators):
                        break
                else:
                    self.add_message('not-context-manager',
                                     node=node, args=(infered.name, ))
            else:
                try:
                    infered.getattr('__enter__')
                    infered.getattr('__exit__')
                except exceptions.NotFoundError:
                    if isinstance(infered, astroid.Instance):
                        # If we do not know the bases of this class,
                        # just skip it.
                        if not has_known_bases(infered):
                            continue
                        # Just ignore mixin classes.
                        if self.config.ignore_mixin_members:
                            if infered.name[-5:].lower() == 'mixin':
                                continue

                    self.add_message('not-context-manager',
                                     node=node, args=(infered.name, ))
示例#24
0
 def visit_classdef(self, node):
     """ Check __slots__ in old style classes and old
     style class definition.
     """
     if '__slots__' in node and not node.newstyle:
         confidence = (INFERENCE if has_known_bases(node)
                       else INFERENCE_FAILURE)
         self.add_message('slots-on-old-class', node=node,
                          confidence=confidence)
     # The node type could be class, exception, metaclass, or
     # interface.  Presumably, the non-class-type nodes would always
     # have an explicit base class anyway.
     if not node.bases and node.type == 'class' and not node.metaclass():
         # We use confidence HIGH here because this message should only ever
         # be emitted for classes at the root of the inheritance hierarchyself.
         self.add_message('old-style-class', node=node, confidence=HIGH)
示例#25
0
 def _check_raise_value(self, node, expr):
     """check for bad values, string exception and class inheritance
     """
     value_found = True
     if isinstance(expr, astroid.Const):
         value = expr.value
         if isinstance(value, str):
             self.add_message('raising-string', node=node)
         else:
             self.add_message('raising-bad-type',
                              node=node,
                              args=value.__class__.__name__)
     elif (isinstance(expr, astroid.Name) and \
              expr.name in ('None', 'True', 'False')) or \
              isinstance(expr, (astroid.List, astroid.Dict, astroid.Tuple,
                                astroid.Module, astroid.Function)):
         self.add_message('raising-bad-type', node=node, args=expr.name)
     elif (
         (isinstance(expr, astroid.Name) and expr.name == 'NotImplemented')
             or (isinstance(expr, astroid.CallFunc)
                 and isinstance(expr.func, astroid.Name)
                 and expr.func.name == 'NotImplemented')):
         self.add_message('notimplemented-raised', node=node)
     elif isinstance(expr, astroid.BinOp) and expr.op == '%':
         self.add_message('raising-string', node=node)
     elif isinstance(expr, (Instance, astroid.Class)):
         if isinstance(expr, Instance):
             expr = expr._proxied
         if (isinstance(expr, astroid.Class)
                 and not inherit_from_std_ex(expr)
                 and expr.root().name != BUILTINS_NAME):
             if expr.newstyle:
                 self.add_message('raising-non-exception', node=node)
             else:
                 self.add_message(
                     'nonstandard-exception',
                     node=node,
                     confidence=INFERENCE
                     if has_known_bases(expr) else INFERENCE_FAILURE)
         else:
             value_found = False
     else:
         value_found = False
     return value_found
示例#26
0
def _emit_no_member(owner, owner_name, attrname,
                    ignored_modules, ignored_mixins, ignored_classes):
    """Try to see if no-member should be emitted for the given owner.

    The following cases are ignored:

        * the owner is a function and it has decorators.
        * the owner is an instance and it has __getattr__, __getattribute__ implemented
        * the module is explicitly ignored from no-member checks
        * the owner is a class and the name can be found in its metaclass.
    """
    if owner_name in ignored_classes:
        return False
    # skip None anyway
    if isinstance(owner, astroid.Const) and owner.value is None:
        return False
    # TODO(cpopa): This should be removed when we'll understand "super"
    if is_super(owner) or getattr(owner, 'type', None) == 'metaclass':
        return False
    if ignored_mixins and owner_name[-5:].lower() == 'mixin':
        return False
    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):
            return False
    # explicit skipping of module member access
    if owner.root().name in ignored_modules:
        return False
    if isinstance(owner, astroid.Class):
        # Look up in the metaclass only if the owner is itself
        # a class.
        # TODO: getattr doesn't return by default members
        # from the metaclass, because handling various cases
        # of methods accessible from the metaclass itself
        # and/or subclasses only is too complicated for little to
        # no benefit.
        metaclass = owner.metaclass() or owner.implicit_metaclass()
        try:
            if metaclass and metaclass.getattr(attrname):
                return False
        except NotFoundError:
            pass
    return True
示例#27
0
    def visit_functiondef(self, node):
        if self.config.no_docstring_rgx.match(node.name) is None:
            ftype = node.is_method() and 'method' or 'function'

            if isinstance(node.parent.frame(), astroid.ClassDef):
                overridden = False
                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():
                    if node.name in ancestor and \
                       isinstance(ancestor[node.name], astroid.FunctionDef):
                        overridden = True
                        break
                self._check_docstring(ftype, node,
                                      report_missing=not overridden,
                                      confidence=confidence)
            else:
                self._check_docstring(ftype, node)
示例#28
0
    def visit_functiondef(self, node):
        if self.config.no_docstring_rgx.match(node.name) is None:
            ftype = node.is_method() and 'method' or 'function'

            if isinstance(node.parent.frame(), astroid.ClassDef):
                overridden = False
                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():
                    if node.name in ancestor and \
                       isinstance(ancestor[node.name], astroid.FunctionDef):
                        overridden = True
                        break
                self._check_docstring(ftype, node,
                                      report_missing=not overridden,
                                      confidence=confidence)
            else:
                self._check_docstring(ftype, node)
示例#29
0
 def _check_raise_value(self, node, expr):
     """check for bad values, string exception and class inheritance
     """
     value_found = True
     if isinstance(expr, astroid.Const):
         value = expr.value
         if isinstance(value, str):
             # raising-string will be emitted from python3 porting checker.
             pass
         else:
             self.add_message('raising-bad-type', node=node,
                              args=value.__class__.__name__)
     elif (isinstance(expr, astroid.Name) and \
              expr.name in ('None', 'True', 'False')) or \
              isinstance(expr, (astroid.List, astroid.Dict, astroid.Tuple,
                                astroid.Module, astroid.Function)):
         self.add_message('raising-bad-type', node=node, args=expr.name)
     elif ((isinstance(expr, astroid.Name) and expr.name == 'NotImplemented')
           or (isinstance(expr, astroid.CallFunc) and
               isinstance(expr.func, astroid.Name) and
               expr.func.name == 'NotImplemented')):
         self.add_message('notimplemented-raised', node=node)
     elif isinstance(expr, (Instance, astroid.Class)):
         if isinstance(expr, Instance):
             expr = expr._proxied
         if (isinstance(expr, astroid.Class) and
                 not inherit_from_std_ex(expr) and
                 expr.root().name != BUILTINS_NAME):
             if expr.newstyle:
                 self.add_message('raising-non-exception', node=node)
             else:
                 self.add_message(
                     'nonstandard-exception', node=node,
                     confidence=INFERENCE if has_known_bases(expr) else INFERENCE_FAILURE)
         else:
             value_found = False
     else:
         value_found = False
     return value_found
示例#30
0
    def visit_functiondef(self, node: nodes.FunctionDef) -> None:
        # Do not emit any warnings if the method is just an implementation
        # of a base class method.
        confidence = interfaces.HIGH
        if node.is_method():
            if utils.overrides_a_method(node.parent.frame(future=True),
                                        node.name):
                return
            confidence = (interfaces.INFERENCE if utils.has_known_bases(
                node.parent.frame(
                    future=True)) else interfaces.INFERENCE_FAILURE)

        self._check_name(
            _determine_function_name_type(node, config=self.linter.config),
            node.name,
            node,
            confidence,
        )
        # Check argument names
        args = node.args.args
        if args is not None:
            self._recursive_check_names(args)
示例#31
0
def _emit_no_member(node, owner, owner_name, ignored_mixins):
    """Try to see if no-member should be emitted for the given owner.

    The following cases are ignored:

        * the owner is a function and it has decorators.
        * the owner is an instance and it has __getattr__, __getattribute__ implemented
        * the module is explicitly ignored from no-member checks
        * the owner is a class and the name can be found in its metaclass.
        * The access node is protected by an except handler, which handles
          AttributeError, Exception or bare except.
    """
    if node_ignores_exception(node, AttributeError):
        return False
    # skip None anyway
    if isinstance(owner, astroid.Const) and owner.value is None:
        return False
    if is_super(owner) or getattr(owner, "type", None) == "metaclass":
        return False
    if ignored_mixins and owner_name[-5:].lower() == "mixin":
        return False
    if isinstance(owner, astroid.FunctionDef) and owner.decorators:
        return False
    if isinstance(owner, astroid.Instance):
        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.
        # If it is invalid, then there's no point in checking that
        # it has the required attribute. Also, don't fail if the
        # MRO is invalid.
        try:
            owner.super_mro()
        except (exceptions.MroError, exceptions.SuperError):
            return False
        if not all(map(has_known_bases, owner.type.mro())):
            return False
    return True
示例#32
0
def _emit_no_member(node, owner, owner_name, ignored_mixins):
    """Try to see if no-member should be emitted for the given owner.

    The following cases are ignored:

        * the owner is a function and it has decorators.
        * the owner is an instance and it has __getattr__, __getattribute__ implemented
        * the module is explicitly ignored from no-member checks
        * the owner is a class and the name can be found in its metaclass.
        * The access node is protected by an except handler, which handles
          AttributeError, Exception or bare except.
    """
    if node_ignores_exception(node, AttributeError):
        return False
    # skip None anyway
    if isinstance(owner, astroid.Const) and owner.value is None:
        return False
    if is_super(owner) or getattr(owner, 'type', None) == 'metaclass':
        return False
    if ignored_mixins and owner_name[-5:].lower() == 'mixin':
        return False
    if isinstance(owner, astroid.FunctionDef) and owner.decorators:
        return False
    if isinstance(owner, astroid.Instance):
        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.
        # If it is invalid, then there's no point in checking that
        # it has the required attribute. Also, don't fail if the
        # MRO is invalid.
        try:
            owner.super_mro()
        except (exceptions.MroError, exceptions.SuperError):
            return False
        if not all(map(has_known_bases, owner.type.mro())):
            return False
    return True
示例#33
0
文件: async.py 项目: AWhetter/pylint
    def visit_asyncwith(self, node: nodes.AsyncWith) -> None:
        for ctx_mgr, _ in node.items:
            inferred = checker_utils.safe_infer(ctx_mgr)
            if inferred is None or inferred is astroid.Uninferable:
                continue

            if isinstance(inferred, nodes.AsyncFunctionDef):
                # Check if we are dealing with a function decorated
                # with contextlib.asynccontextmanager.
                if decorated_with(inferred, self._async_generators):
                    continue
            elif isinstance(inferred, astroid.bases.AsyncGenerator):
                # Check if we are dealing with a function decorated
                # with contextlib.asynccontextmanager.
                if decorated_with(inferred.parent, self._async_generators):
                    continue
            else:
                try:
                    inferred.getattr("__aenter__")
                    inferred.getattr("__aexit__")
                except astroid.exceptions.NotFoundError:
                    if isinstance(inferred, astroid.Instance):
                        # If we do not know the bases of this class,
                        # just skip it.
                        if not checker_utils.has_known_bases(inferred):
                            continue
                        # Ignore mixin classes if they match the rgx option.
                        if ("not-async-context-manager" in
                                self.linter.namespace.ignored_checks_for_mixins
                                and self._mixin_class_rgx.match(
                                    inferred.name)):
                            continue
                else:
                    continue
            self.add_message("not-async-context-manager",
                             node=node,
                             args=(inferred.name, ))
示例#34
0
    def leave_function(self, node):
        """leave function: check function's locals are consumed"""
        not_consumed = self._to_consume.pop()[0]
        if not (self.linter.is_message_enabled('unused-variable') or
                self.linter.is_message_enabled('unused-argument')):
            return
        # don't check arguments of function which are only raising an exception
        if is_error(node):
            return
        # don't check arguments of abstract methods or within an interface
        is_method = node.is_method()
        klass = node.parent.frame()
        if is_method and (klass.type == 'interface' or node.is_abstract()):
            return
        if is_method and isinstance(klass, astroid.Class):
            confidence = INFERENCE if has_known_bases(klass) else INFERENCE_FAILURE
        else:
            confidence = HIGH
        authorized_rgx = self.config.dummy_variables_rgx
        called_overridden = False
        argnames = node.argnames()
        global_names = set()
        nonlocal_names = set()
        for global_stmt in node.nodes_of_class(astroid.Global):
            global_names.update(set(global_stmt.names))
        for nonlocal_stmt in node.nodes_of_class(astroid.Nonlocal):
            nonlocal_names.update(set(nonlocal_stmt.names))

        for name, stmts in six.iteritems(not_consumed):
            # ignore some special names specified by user configuration
            if authorized_rgx.match(name):
                continue
            # ignore names imported by the global statement
            # FIXME: should only ignore them if it's assigned latter
            stmt = stmts[0]
            if isinstance(stmt, astroid.Global):
                continue
            if isinstance(stmt, (astroid.Import, astroid.From)):
                # Detect imports, assigned to global statements.
                if global_names:
                    skip = False
                    for import_name, import_alias in stmt.names:
                        # If the import uses an alias, check only that.
                        # Otherwise, check only the import name.
                        if import_alias:
                            if import_alias in global_names:
                                skip = True
                                break
                        elif import_name in global_names:
                            skip = True
                            break
                    if skip:
                        continue

            # care about functions with unknown argument (builtins)
            if name in argnames:
                if is_method:
                    # don't warn for the first argument of a (non static) method
                    if node.type != 'staticmethod' and name == argnames[0]:
                        continue
                    # don't warn for argument of an overridden method
                    if not called_overridden:
                        overridden = overridden_method(klass, node.name)
                        called_overridden = True
                    if overridden is not None and name in overridden.argnames():
                        continue
                    if node.name in PYMETHODS and node.name not in ('__init__', '__new__'):
                        continue
                # don't check callback arguments
                if any(node.name.startswith(cb) or node.name.endswith(cb)
                       for cb in self.config.callbacks):
                    continue
                self.add_message('unused-argument', args=name, node=stmt,
                                 confidence=confidence)
            else:
                if stmt.parent and isinstance(stmt.parent, astroid.Assign):
                    if name in nonlocal_names:
                        continue
                self.add_message('unused-variable', args=name, node=stmt)
示例#35
0
    def visit_call(self, node):
        """check that called functions/methods are inferred to callable objects,
        and that the arguments passed to the function match the parameters in
        the inferred function's definition
        """
        # Build the set of keyword arguments, checking for duplicate keywords,
        # and count the positional arguments.
        call_site = astroid.arguments.CallSite.from_call(node)
        num_positional_args = len(call_site.positional_arguments)
        keyword_args = list(call_site.keyword_arguments.keys())

        # Determine if we don't have a context for our call and we use variadics.
        if isinstance(node.scope(), astroid.FunctionDef):
            has_no_context_positional_variadic = _no_context_variadic_positional(node)
            has_no_context_keywords_variadic = _no_context_variadic_keywords(node)
        else:
            has_no_context_positional_variadic = has_no_context_keywords_variadic = False

        called = safe_infer(node.func)
        # only function, generator and object defining __call__ are allowed
        if called and not called.callable():
            if isinstance(called, astroid.Instance) and not has_known_bases(called):
                # Don't emit if we can't make sure this object is callable.
                pass
            else:
                self.add_message('not-callable', node=node,
                                 args=node.func.as_string())

        self._check_uninferable_callfunc(node)

        try:
            called, implicit_args, callable_name = _determine_callable(called)
        except ValueError:
            # Any error occurred during determining the function type, most of
            # those errors are handled by different warnings.
            return

        num_positional_args += implicit_args
        if called.args.args is None:
            # Built-in functions have no argument information.
            return

        if len(called.argnames()) != len(set(called.argnames())):
            # Duplicate parameter name (see duplicate-argument).  We can't really
            # make sense of the function call in this case, so just return.
            return

        # Warn about duplicated keyword arguments, such as `f=24, **{'f': 24}`
        for keyword in call_site.duplicated_keywords:
            self.add_message('repeated-keyword',
                             node=node, args=(keyword, ))

        if call_site.has_invalid_arguments() or call_site.has_invalid_keywords():
            # Can't make sense of this.
            return

        # Analyze the list of formal parameters.
        num_mandatory_parameters = len(called.args.args) - len(called.args.defaults)
        parameters = []
        parameter_name_to_index = {}
        for i, arg in enumerate(called.args.args):
            if isinstance(arg, astroid.Tuple):
                name = None
                # Don't store any parameter names within the tuple, since those
                # are not assignable from keyword arguments.
            else:
                assert isinstance(arg, astroid.AssignName)
                # This occurs with:
                #    def f( (a), (b) ): pass
                name = arg.name
                parameter_name_to_index[name] = i
            if i >= num_mandatory_parameters:
                defval = called.args.defaults[i - num_mandatory_parameters]
            else:
                defval = None
            parameters.append([(name, defval), False])

        kwparams = {}
        for i, arg in enumerate(called.args.kwonlyargs):
            if isinstance(arg, astroid.Keyword):
                name = arg.arg
            else:
                assert isinstance(arg, astroid.AssignName)
                name = arg.name
            kwparams[name] = [called.args.kw_defaults[i], False]

        # Match the supplied arguments against the function parameters.

        # 1. Match the positional arguments.
        for i in range(num_positional_args):
            if i < len(parameters):
                parameters[i][1] = True
            elif called.args.vararg is not None:
                # The remaining positional arguments get assigned to the *args
                # parameter.
                break
            else:
                # Too many positional arguments.
                self.add_message('too-many-function-args',
                                 node=node, args=(callable_name,))
                break

        # 2. Match the keyword arguments.
        for keyword in keyword_args:
            if keyword in parameter_name_to_index:
                i = parameter_name_to_index[keyword]
                if parameters[i][1]:
                    # Duplicate definition of function parameter.

                    # Might be too hardcoded, but this can actually
                    # happen when using str.format and `self` is passed
                    # by keyword argument, as in `.format(self=self)`.
                    # It's perfectly valid to so, so we're just skipping
                    # it if that's the case.
                    if not (keyword == 'self' and called.qname() == STR_FORMAT):
                        self.add_message('redundant-keyword-arg',
                                         node=node, args=(keyword, callable_name))
                else:
                    parameters[i][1] = True
            elif keyword in kwparams:
                if kwparams[keyword][1]:  # XXX is that even possible?
                    # Duplicate definition of function parameter.
                    self.add_message('redundant-keyword-arg', node=node,
                                     args=(keyword, callable_name))
                else:
                    kwparams[keyword][1] = True
            elif called.args.kwarg is not None:
                # The keyword argument gets assigned to the **kwargs parameter.
                pass
            else:
                # Unexpected keyword argument.
                self.add_message('unexpected-keyword-arg', node=node,
                                 args=(keyword, callable_name))

        # 3. Match the **kwargs, if any.
        if node.kwargs:
            for i, [(name, defval), assigned] in enumerate(parameters):
                # Assume that *kwargs provides values for all remaining
                # unassigned named parameters.
                if name is not None:
                    parameters[i][1] = True
                else:
                    # **kwargs can't assign to tuples.
                    pass

        # Check that any parameters without a default have been assigned
        # values.
        for [(name, defval), assigned] in parameters:
            if (defval is None) and not assigned:
                if name is None:
                    display_name = '<tuple>'
                else:
                    display_name = repr(name)
                # TODO(cpopa): this should be removed after PyCQA/astroid/issues/177
                if not has_no_context_positional_variadic:
                    self.add_message('no-value-for-parameter', node=node,
                                     args=(display_name, callable_name))

        for name in kwparams:
            defval, assigned = kwparams[name]
            if defval is None and not assigned and not has_no_context_keywords_variadic:
                self.add_message('missing-kwoa', node=node,
                                 args=(name, callable_name))
示例#36
0
    def visit_tryexcept(self, node):
        """check for empty except"""
        exceptions_classes = []
        nb_handlers = len(node.handlers)
        for index, handler in enumerate(node.handlers):
            # single except doing nothing but "pass" without else clause
            if is_empty(handler.body) and not node.orelse:
                self.add_message('pointless-except',
                                 node=handler.type or handler.body[0])
            if handler.type is None:
                if not is_raising(handler.body):
                    self.add_message('bare-except', node=handler)
                # check if a "except:" is followed by some other
                # except
                if index < (nb_handlers - 1):
                    msg = 'empty except clause should always appear last'
                    self.add_message('bad-except-order', node=node, args=msg)

            elif isinstance(handler.type, astroid.BoolOp):
                self.add_message('binary-op-exception',
                                 node=handler, args=handler.type.op)
            else:
                try:
                    excs = list(_annotated_unpack_infer(handler.type))
                except astroid.InferenceError:
                    continue
                for part, exc in excs:
                    if exc is YES:
                        continue
                    if isinstance(exc, astroid.Instance) and inherit_from_std_ex(exc):
                        exc = exc._proxied
                    if not isinstance(exc, astroid.Class):
                        # Don't emit the warning if the infered stmt
                        # is None, but the exception handler is something else,
                        # maybe it was redefined.
                        if (isinstance(exc, astroid.Const) and
                                exc.value is None):
                            if ((isinstance(handler.type, astroid.Const) and
                                 handler.type.value is None) or
                                    handler.type.parent_of(exc)):
                                # If the exception handler catches None or
                                # the exception component, which is None, is
                                # defined by the entire exception handler, then
                                # emit a warning.
                                self.add_message('catching-non-exception',
                                                 node=handler.type,
                                                 args=(part.as_string(), ))
                        else:
                            self.add_message('catching-non-exception',
                                             node=handler.type,
                                             args=(part.as_string(), ))
                        continue

                    exc_ancestors = [anc for anc in exc.ancestors()
                                     if isinstance(anc, astroid.Class)]
                    for previous_exc in exceptions_classes:
                        if previous_exc in exc_ancestors:
                            msg = '%s is an ancestor class of %s' % (
                                previous_exc.name, exc.name)
                            self.add_message('bad-except-order',
                                             node=handler.type, args=msg)
                    if (exc.name in self.config.overgeneral_exceptions
                            and exc.root().name == EXCEPTIONS_MODULE
                            and not is_raising(handler.body)):
                        self.add_message('broad-except',
                                         args=exc.name, node=handler.type)

                    if (not inherit_from_std_ex(exc) and
                            exc.root().name != BUILTINS_NAME):
                        if has_known_bases(exc):
                            self.add_message('catching-non-exception',
                                             node=handler.type,
                                             args=(exc.name, ))

                exceptions_classes += [exc for _, exc in excs]
示例#37
0
    def visit_functiondef(self, node):
        """check use of super"""
        # ignore actual functions or method within a new style class
        if not node.is_method():
            return
        klass = node.parent.frame()
        for stmt in node.nodes_of_class(astroid.Call):
            if node_frame_class(stmt) != node_frame_class(node):
                # Don't look down in other scopes.
                continue

            expr = stmt.func
            if not isinstance(expr, astroid.Attribute):
                continue

            call = expr.expr
            # skip the test if using super
            if not (isinstance(call, astroid.Call) and
                    isinstance(call.func, astroid.Name) and
                    call.func.name == 'super'):
                continue

            if not klass.newstyle and has_known_bases(klass):
                # super should not be used on an old style class
                self.add_message('super-on-old-class', node=node)
            else:
                # super first arg should be the class
                if not call.args:
                    if sys.version_info[0] == 3:
                        # unless Python 3
                        continue
                    else:
                        self.add_message('missing-super-argument', node=call)
                        continue

                # calling super(type(self), self) can lead to recursion loop
                # in derived classes
                arg0 = call.args[0]
                if isinstance(arg0, astroid.Call) and \
                   isinstance(arg0.func, astroid.Name) and \
                   arg0.func.name == 'type':
                    self.add_message('bad-super-call', node=call, args=('type', ))
                    continue

                # calling super(self.__class__, self) can lead to recursion loop
                # in derived classes
                if len(call.args) >= 2 and \
                   isinstance(call.args[1], astroid.Name) and \
                   call.args[1].name == 'self' and \
                   isinstance(arg0, astroid.Attribute) and \
                   arg0.attrname == '__class__':
                    self.add_message('bad-super-call', node=call, args=('self.__class__', ))
                    continue

                try:
                    supcls = call.args and next(call.args[0].infer(), None)
                except astroid.InferenceError:
                    continue

                if klass is not supcls:
                    name = None
                    # if supcls is not Uninferable, then supcls was infered
                    # and use its name. Otherwise, try to look
                    # for call.args[0].name
                    if supcls:
                        name = supcls.name
                    elif call.args and hasattr(call.args[0], 'name'):
                        name = call.args[0].name
                    if name:
                        self.add_message('bad-super-call', node=call, args=(name, ))
示例#38
0
    def visit_functiondef(self, node: nodes.FunctionDef) -> None:
        """check use of super"""
        # ignore actual functions or method within a new style class
        if not node.is_method():
            return
        klass = node.parent.frame()
        for stmt in node.nodes_of_class(nodes.Call):
            if node_frame_class(stmt) != node_frame_class(node):
                # Don't look down in other scopes.
                continue

            expr = stmt.func
            if not isinstance(expr, nodes.Attribute):
                continue

            call = expr.expr
            # skip the test if using super
            if not (isinstance(call, nodes.Call) and isinstance(
                    call.func, nodes.Name) and call.func.name == "super"):
                continue

            # super should not be used on an old style class
            if klass.newstyle or not has_known_bases(klass):
                # super first arg should not be the class
                if not call.args:
                    continue

                # calling super(type(self), self) can lead to recursion loop
                # in derived classes
                arg0 = call.args[0]
                if (isinstance(arg0, nodes.Call)
                        and isinstance(arg0.func, nodes.Name)
                        and arg0.func.name == "type"):
                    self.add_message("bad-super-call",
                                     node=call,
                                     args=("type", ))
                    continue

                # calling super(self.__class__, self) can lead to recursion loop
                # in derived classes
                if (len(call.args) >= 2
                        and isinstance(call.args[1], nodes.Name)
                        and call.args[1].name == "self"
                        and isinstance(arg0, nodes.Attribute)
                        and arg0.attrname == "__class__"):
                    self.add_message("bad-super-call",
                                     node=call,
                                     args=("self.__class__", ))
                    continue

                try:
                    supcls = call.args and next(call.args[0].infer(), None)
                except astroid.InferenceError:
                    continue

                if klass is not supcls:
                    name = None
                    # if supcls is not Uninferable, then supcls was inferred
                    # and use its name. Otherwise, try to look
                    # for call.args[0].name
                    if supcls:
                        name = supcls.name
                    elif call.args and hasattr(call.args[0], "name"):
                        name = call.args[0].name
                    if name:
                        self.add_message("bad-super-call",
                                         node=call,
                                         args=(name, ))
示例#39
0
 def visit_classdef(self, cls):
     if not utils.inherit_from_std_ex(cls) and utils.has_known_bases(cls):
         if cls.newstyle:
             self._checker.add_message("raising-non-exception",
                                       node=self._node)
示例#40
0
    def visit_index(self, node):
        if not node.parent or not hasattr(node.parent, "value"):
            return
        # 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 = safe_infer(node.parent.value)
        if not isinstance(parent_type, (astroid.ClassDef, astroid.Instance)):
            return
        if not has_known_bases(parent_type):
            return

        # Determine what method on the parent this index will use
        # The parent of this node will be a Subscript, and the parent of that
        # node determines if the Subscript is a get, set, or delete operation.
        if node.parent.ctx is astroid.Store:
            methodname = "__setitem__"
        elif node.parent.ctx is astroid.Del:
            methodname = "__delitem__"
        else:
            methodname = "__getitem__"

        # Check if this instance's __getitem__, __setitem__, or __delitem__, as
        # appropriate to the statement, is implemented in a builtin sequence
        # type. This way we catch subclasses of sequence types but skip classes
        # that override __getitem__ and which may allow non-integer indices.
        try:
            methods = parent_type.getattr(methodname)
            if methods is astroid.YES:
                return
            itemmethod = methods[0]
        except (exceptions.NotFoundError, IndexError):
            return
        if not isinstance(itemmethod, astroid.FunctionDef):
            return
        if itemmethod.root().name != BUILTINS:
            return
        if not itemmethod.parent:
            return
        if itemmethod.parent.name not in SEQUENCE_TYPES:
            return

        # For ExtSlice objects coming from visit_extslice, no further
        # inference is necessary, since if we got this far the ExtSlice
        # is an error.
        if isinstance(node, astroid.ExtSlice):
            index_type = node
        else:
            index_type = safe_infer(node)
        if index_type is None or index_type is astroid.YES:
            return
        # Constants must be of type int
        if isinstance(index_type, astroid.Const):
            if isinstance(index_type.value, int):
                return
        # Instance values must be int, slice, or have an __index__ method
        elif isinstance(index_type, astroid.Instance):
            if index_type.pytype() in (BUILTINS + ".int", BUILTINS + ".slice"):
                return
            try:
                index_type.getattr("__index__")
                return
            except exceptions.NotFoundError:
                pass
        elif isinstance(index_type, astroid.Slice):
            # Delegate to visit_slice. A slice can be present
            # here after inferring the index node, which could
            # be a `slice(...)` call for instance.
            return self.visit_slice(index_type)

        # Anything else is an error
        self.add_message("invalid-sequence-index", node=node)
示例#41
0
 def visit_classdef(self, node: nodes.ClassDef) -> None:
     if not utils.inherit_from_std_ex(node) and utils.has_known_bases(node):
         if node.newstyle:
             self._checker.add_message("raising-non-exception", node=self._node)
示例#42
0
    def leave_function(self, node):
        """leave function: check function's locals are consumed"""
        not_consumed = self._to_consume.pop()[0]
        if not (self.linter.is_message_enabled('unused-variable')
                or self.linter.is_message_enabled('unused-argument')):
            return
        # don't check arguments of function which are only raising an exception
        if is_error(node):
            return
        # don't check arguments of abstract methods or within an interface
        is_method = node.is_method()
        klass = node.parent.frame()
        if is_method and (klass.type == 'interface' or node.is_abstract()):
            return
        if is_method and isinstance(klass, astroid.Class):
            confidence = INFERENCE if has_known_bases(
                klass) else INFERENCE_FAILURE
        else:
            confidence = HIGH
        authorized_rgx = self.config.dummy_variables_rgx
        called_overridden = False
        argnames = node.argnames()
        global_names = set()
        nonlocal_names = set()
        for global_stmt in node.nodes_of_class(astroid.Global):
            global_names.update(set(global_stmt.names))
        for nonlocal_stmt in node.nodes_of_class(astroid.Nonlocal):
            nonlocal_names.update(set(nonlocal_stmt.names))

        for name, stmts in six.iteritems(not_consumed):
            # ignore some special names specified by user configuration
            if authorized_rgx.match(name):
                continue
            # ignore names imported by the global statement
            # FIXME: should only ignore them if it's assigned latter
            stmt = stmts[0]
            if isinstance(stmt, astroid.Global):
                continue
            if isinstance(stmt, (astroid.Import, astroid.From)):
                # Detect imports, assigned to global statements.
                if global_names:
                    skip = False
                    for import_name, import_alias in stmt.names:
                        # If the import uses an alias, check only that.
                        # Otherwise, check only the import name.
                        if import_alias:
                            if import_alias in global_names:
                                skip = True
                                break
                        elif import_name in global_names:
                            skip = True
                            break
                    if skip:
                        continue

            # care about functions with unknown argument (builtins)
            if name in argnames:
                if is_method:
                    # don't warn for the first argument of a (non static) method
                    if node.type != 'staticmethod' and name == argnames[0]:
                        continue
                    # don't warn for argument of an overridden method
                    if not called_overridden:
                        overridden = overridden_method(klass, node.name)
                        called_overridden = True
                    if overridden is not None and name in overridden.argnames(
                    ):
                        continue
                    if node.name in PYMETHODS and node.name not in ('__init__',
                                                                    '__new__'):
                        continue
                # don't check callback arguments XXX should be configurable
                if node.name.startswith('cb_') or node.name.endswith('_cb'):
                    continue
                self.add_message('unused-argument',
                                 args=name,
                                 node=stmt,
                                 confidence=confidence)
            else:
                if stmt.parent and isinstance(stmt.parent, astroid.Assign):
                    if name in nonlocal_names:
                        continue
                self.add_message('unused-variable', args=name, node=stmt)
示例#43
0
    def visit_index(self, node):
        if not node.parent or not hasattr(node.parent, "value"):
            return
        # 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 = safe_infer(node.parent.value)
        if not isinstance(parent_type, (astroid.ClassDef, astroid.Instance)):
            return
        if not has_known_bases(parent_type):
            return

        # Determine what method on the parent this index will use
        # The parent of this node will be a Subscript, and the parent of that
        # node determines if the Subscript is a get, set, or delete operation.
        if node.parent.ctx is astroid.Store:
            methodname = '__setitem__'
        elif node.parent.ctx is astroid.Del:
            methodname = '__delitem__'
        else:
            methodname = '__getitem__'

        # Check if this instance's __getitem__, __setitem__, or __delitem__, as
        # appropriate to the statement, is implemented in a builtin sequence
        # type. This way we catch subclasses of sequence types but skip classes
        # that override __getitem__ and which may allow non-integer indices.
        try:
            methods = parent_type.getattr(methodname)
            if methods is astroid.YES:
                return
            itemmethod = methods[0]
        except (exceptions.NotFoundError, IndexError):
            return
        if not isinstance(itemmethod, astroid.FunctionDef):
            return
        if itemmethod.root().name != BUILTINS:
            return
        if not itemmethod.parent:
            return
        if itemmethod.parent.name not in SEQUENCE_TYPES:
            return

        # For ExtSlice objects coming from visit_extslice, no further
        # inference is necessary, since if we got this far the ExtSlice
        # is an error.
        if isinstance(node, astroid.ExtSlice):
            index_type = node
        else:
            index_type = safe_infer(node)
        if index_type is None or index_type is astroid.YES:
            return
        # Constants must be of type int
        if isinstance(index_type, astroid.Const):
            if isinstance(index_type.value, int):
                return
        # Instance values must be int, slice, or have an __index__ method
        elif isinstance(index_type, astroid.Instance):
            if index_type.pytype() in (BUILTINS + '.int', BUILTINS + '.slice'):
                return
            try:
                index_type.getattr('__index__')
                return
            except exceptions.NotFoundError:
                pass
        elif isinstance(index_type, astroid.Slice):
            # Delegate to visit_slice. A slice can be present
            # here after inferring the index node, which could
            # be a `slice(...)` call for instance.
            return self.visit_slice(index_type)

        # Anything else is an error
        self.add_message('invalid-sequence-index', node=node)