Exemple #1
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, astroid.AsyncFunctionDef):
                # Check if we are dealing with a function decorated
                # with contextlib.asynccontextmanager.
                if decorated_with(inferred, self._async_generators):
                    continue
            elif 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, ))
Exemple #2
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, ))
Exemple #3
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, ))
Exemple #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,)
            )
Exemple #5
0
    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, ))
Exemple #6
0
    def _check_unexpected_method_signature(self, node):
        expected_params = SPECIAL_METHODS_PARAMS[node.name]

        if expected_params is None:
            # This can support a variable number of parameters.
            return
        if not node.args.args and not node.args.vararg:
            # Method has no parameter, will be caught
            # by no-method-argument.
            return

        if decorated_with(node, ["builtins.staticmethod"]):
            # We expect to not take in consideration self.
            all_args = node.args.args
        else:
            all_args = node.args.args[1:]
        mandatory = len(all_args) - len(node.args.defaults)
        optional = len(node.args.defaults)
        current_params = mandatory + optional

        emit = False  # If we don't know we choose a false negative
        if isinstance(expected_params, tuple):
            # The expected number of parameters can be any value from this
            # tuple, although the user should implement the method
            # to take all of them in consideration.
            emit = mandatory not in expected_params
            # pylint: disable-next=consider-using-f-string
            expected_params = "between %d or %d" % expected_params
        else:
            # If the number of mandatory parameters doesn't
            # suffice, the expected parameters for this
            # function will be deduced from the optional
            # parameters.
            rest = expected_params - mandatory
            if rest == 0:
                emit = False
            elif rest < 0:
                emit = True
            elif rest > 0:
                emit = not ((optional - rest) >= 0 or node.args.vararg)

        if emit:
            verb = "was" if current_params <= 1 else "were"
            self.add_message(
                "unexpected-special-method-signature",
                args=(node.name, expected_params, current_params, verb),
                node=node,
            )
Exemple #7
0
    def _check_unexpected_method_signature(self, node):
        expected_params = SPECIAL_METHODS_PARAMS[node.name]

        if expected_params is None:
            # This can support a variable number of parameters.
            return
        if not len(node.args.args) and not node.args.vararg:
            # Method has no parameter, will be catched
            # by no-method-argument.
            return

        if decorated_with(node, [BUILTINS + ".staticmethod"]):
            # We expect to not take in consideration self.
            all_args = node.args.args
        else:
            all_args = node.args.args[1:]
        mandatory = len(all_args) - len(node.args.defaults)
        optional = len(node.args.defaults)
        current_params = mandatory + optional

        if isinstance(expected_params, tuple):
            # The expected number of parameters can be any value from this
            # tuple, although the user should implement the method
            # to take all of them in consideration.
            emit = mandatory not in expected_params
            expected_params = "between %d or %d" % expected_params
        else:
            # If the number of mandatory parameters doesn't
            # suffice, the expected parameters for this
            # function will be deduced from the optional
            # parameters.
            rest = expected_params - mandatory
            if rest == 0:
                emit = False
            elif rest < 0:
                emit = True
            elif rest > 0:
                emit = not ((optional - rest) >= 0 or node.args.vararg)

        if emit:
            verb = "was" if current_params <= 1 else "were"
            self.add_message('unexpected-special-method-signature',
                             args=(node.name, expected_params, current_params, verb),
                             node=node)
Exemple #8
0
 def visit_functiondef(self, node):
     if node.is_method():
         if node.name in self._unused_magic_methods:
             method_name = node.name
             if node.name.startswith('__'):
                 method_name = node.name[2:-2]
             self.add_message(method_name + '-method', node=node)
         elif node.name == 'next':
             # If there is a method named `next` declared, if it is invokable
             # with zero arguments then it implements the Iterator protocol.
             # This means if the method is an instance method or a
             # classmethod 1 argument should cause a failure, if it is a
             # staticmethod 0 arguments should cause a failure.
             failing_arg_count = 1
             if utils.decorated_with(node,
                                     [bases.BUILTINS + ".staticmethod"]):
                 failing_arg_count = 0
             if len(node.args.args) == failing_arg_count:
                 self.add_message('next-method-defined', node=node)
Exemple #9
0
 def visit_functiondef(self, node):
     if node.is_method():
         if node.name in self._unused_magic_methods:
             method_name = node.name
             if node.name.startswith('__'):
                 method_name = node.name[2:-2]
             self.add_message(method_name + '-method', node=node)
         elif node.name == 'next':
             # If there is a method named `next` declared, if it is invokable
             # with zero arguments then it implements the Iterator protocol.
             # This means if the method is a instance method or a
             # classmethod 1 argument should cause a failure, if it is a
             # staticmethod 0 arguments should cause a failure.
             failing_arg_count = 1
             if utils.decorated_with(node,
                                     [bases.BUILTINS + ".staticmethod"]):
                 failing_arg_count = 0
             if len(node.args.args) == failing_arg_count:
                 self.add_message('next-method-defined', node=node)
    def visit_with(self, node):
        for ctx_mgr, _ in node.items:
            infered = safe_infer(ctx_mgr)
            if infered is None or infered is astroid.YES:
                continue

            # Check if we are dealing with a function decorated
            # with contextlib.contextmanager.
            if isinstance(infered, astroid.bases.Generator):
                func = infered.parent
                if not decorated_with(func, ['contextlib.contextmanager']):
                    self.add_message('not-context-manager',
                                     node=node, args=(infered.name, ))
            else:
                try:
                    infered.getattr('__enter__')
                    infered.getattr('__exit__')
                except astroid.NotFoundError:
                    self.add_message('not-context-manager',
                                     node=node, args=(infered.name, ))