def _check_use_implicit_booleaness_not_comparison( self, node: nodes.Compare) -> None: """Check for left side and right side of the node for empty literals.""" is_left_empty_literal = utils.is_base_container( node.left) or utils.is_empty_dict_literal(node.left) # Check both left-hand side and right-hand side for literals for operator, comparator in node.ops: is_right_empty_literal = utils.is_base_container( comparator) or utils.is_empty_dict_literal(comparator) # Using Exclusive OR (XOR) to compare between two side. # If two sides are both literal, it should be different error. if is_right_empty_literal ^ is_left_empty_literal: # set target_node to opposite side of literal target_node = node.left if is_right_empty_literal else comparator literal_node = comparator if is_right_empty_literal else node.left # Infer node to check target_instance = utils.safe_infer(target_node) if target_instance is None: continue mother_classes = self.base_names_of_instance(target_instance) is_base_comprehension_type = any(t in mother_classes for t in ("tuple", "list", "dict", "set")) # Only time we bypass check is when target_node is not inherited by # collection literals and have its own __bool__ implementation. if not is_base_comprehension_type and self.instance_has_bool( target_instance): continue # No need to check for operator when visiting compare node if operator in {"==", "!=", ">=", ">", "<=", "<"}: collection_literal = "{}" if isinstance(literal_node, nodes.List): collection_literal = "[]" if isinstance(literal_node, nodes.Tuple): collection_literal = "()" instance_name = "x" if isinstance(target_node, nodes.Call) and target_node.func: instance_name = f"{target_node.func.as_string()}(...)" elif isinstance(target_node, (nodes.Attribute, nodes.Name)): instance_name = target_node.as_string() original_comparison = ( f"{instance_name} {operator} {collection_literal}") suggestion = (f"{instance_name}" if operator == "!=" else f"not {instance_name}") self.add_message( "use-implicit-booleaness-not-comparison", args=( original_comparison, suggestion, ), node=node, )
def test_is_empty_literal() -> None: list_node = astroid.extract_node("a = []") assert utils.is_base_container(list_node.value) not_empty_list_node = astroid.extract_node("a = [1,2,3]") assert not utils.is_base_container(not_empty_list_node.value) tuple_node = astroid.extract_node("a = ()") assert utils.is_base_container(tuple_node.value) not_empty_tuple_node = astroid.extract_node("a = (1,2)") assert not utils.is_base_container(not_empty_tuple_node.value) dict_node = astroid.extract_node("a = {}") assert utils.is_empty_dict_literal(dict_node.value) not_empty_dict_node = astroid.extract_node("a = {1:1}") assert not utils.is_empty_dict_literal(not_empty_dict_node.value) string_node = astroid.extract_node("a = ''") assert utils.is_empty_str_literal(string_node.value) not_empty_string_node = astroid.extract_node("a = 'hello'") assert not utils.is_empty_str_literal(not_empty_string_node.value)