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)
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), )
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)
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)