Example #1
0
 def visit_call(self, node):
     # a len(S) call is used inside a test condition
     # could be if, while, assert or if expression statement
     # e.g. `if len(S):`
     if not utils.is_call_of_name(node, "len"):
         return
     # the len() call could also be nested together with other
     # boolean operations, e.g. `if z or len(x):`
     parent = node.parent
     while isinstance(parent, astroid.BoolOp):
         parent = parent.parent
     # we're finally out of any nested boolean operations so check if
     # this len() call is part of a test condition
     if not utils.is_test_condition(node, parent):
         return
     len_arg = node.args[0]
     generator_or_comprehension = (ListComp, SetComp, DictComp, GeneratorExp)
     if isinstance(len_arg, generator_or_comprehension):
         # The node is a generator or comprehension as in len([x for x in ...])
         self.add_message("len-as-condition", node=node)
         return
     instance = next(len_arg.infer())
     mother_classes = self.base_classes_of_node(instance)
     affected_by_pep8 = any(
         t in mother_classes for t in ["str", "tuple", "list", "set"]
     )
     if "range" in mother_classes or (
         affected_by_pep8 and not self.instance_has_bool(instance)
     ):
         self.add_message("len-as-condition", node=node)
Example #2
0
    def _check_singleton_comparison(self,
                                    left_value,
                                    right_value,
                                    root_node,
                                    checking_for_absence: bool = False):
        """Check if == or != is being used to compare a singleton value."""
        singleton_values = (True, False, None)

        def _is_singleton_const(node) -> bool:
            return isinstance(node, nodes.Const) and any(
                node.value is value for value in singleton_values)

        if _is_singleton_const(left_value):
            singleton, other_value = left_value.value, right_value
        elif _is_singleton_const(right_value):
            singleton, other_value = right_value.value, left_value
        else:
            return

        singleton_comparison_example = {
            False: "'{} is {}'",
            True: "'{} is not {}'"
        }

        # True/False singletons have a special-cased message in case the user is
        # mistakenly using == or != to check for truthiness
        if singleton in {True, False}:
            suggestion_template = (
                "{} if checking for the singleton value {}, or {} if testing for {}"
            )
            truthiness_example = {False: "not {}", True: "{}"}
            truthiness_phrase = {True: "truthiness", False: "falsiness"}

            # Looks for comparisons like x == True or x != False
            checking_truthiness = singleton is not checking_for_absence

            suggestion = suggestion_template.format(
                singleton_comparison_example[checking_for_absence].format(
                    left_value.as_string(), right_value.as_string()),
                singleton,
                ("'bool({})'" if not utils.is_test_condition(root_node)
                 and checking_truthiness else "'{}'").format(
                     truthiness_example[checking_truthiness].format(
                         other_value.as_string())),
                truthiness_phrase[checking_truthiness],
            )
        else:
            suggestion = singleton_comparison_example[
                checking_for_absence].format(left_value.as_string(),
                                             right_value.as_string())
        self.add_message(
            "singleton-comparison",
            node=root_node,
            args=(f"'{root_node.as_string()}'", suggestion),
        )
Example #3
0
    def visit_call(self, node):
        # a len(S) call is used inside a test condition
        # could be if, while, assert or if expression statement
        # e.g. `if len(S):`
        if utils.is_call_of_name(node, "len"):
            # the len() call could also be nested together with other
            # boolean operations, e.g. `if z or len(x):`
            parent = node.parent
            while isinstance(parent, astroid.BoolOp):
                parent = parent.parent

            # we're finally out of any nested boolean operations so check if
            # this len() call is part of a test condition
            if utils.is_test_condition(node, parent):
                self.add_message("len-as-condition", node=node)
Example #4
0
 def visit_call(self, node: nodes.Call) -> None:
     # a len(S) call is used inside a test condition
     # could be if, while, assert or if expression statement
     # e.g. `if len(S):`
     if not utils.is_call_of_name(node, "len"):
         return
     # the len() call could also be nested together with other
     # boolean operations, e.g. `if z or len(x):`
     parent = node.parent
     while isinstance(parent, nodes.BoolOp):
         parent = parent.parent
     # we're finally out of any nested boolean operations so check if
     # this len() call is part of a test condition
     if not utils.is_test_condition(node, parent):
         return
     len_arg = node.args[0]
     generator_or_comprehension = (
         nodes.ListComp,
         nodes.SetComp,
         nodes.DictComp,
         nodes.GeneratorExp,
     )
     if isinstance(len_arg, generator_or_comprehension):
         # The node is a generator or comprehension as in len([x for x in ...])
         self.add_message("use-implicit-booleaness-not-len", node=node)
         return
     try:
         instance = next(len_arg.infer())
     except astroid.InferenceError:
         # Probably undefined-variable, abort check
         return
     mother_classes = self.base_classes_of_node(instance)
     affected_by_pep8 = any(
         t in mother_classes for t in ("str", "tuple", "list", "set")
     )
     if "range" in mother_classes or (
         affected_by_pep8 and not self.instance_has_bool(instance)
     ):
         self.add_message("use-implicit-booleaness-not-len", node=node)