def _check_set_elements( self, node: Union[ast.Set, ast.Dict], keys_or_elts: _HashItems, ) -> None: elements: List[str] = [] element_values = [] for set_item in keys_or_elts: if set_item is None: continue # happens for `{**a}` real_item = operators.unwrap_unary_node(set_item) if isinstance(real_item, self._elements_in_sets): # Similar look: node_repr = source.node_to_string(set_item) elements.append(node_repr.strip().strip('(').strip(')')) real_item = operators.unwrap_starred_node(real_item) # Non-constant nodes raise ValueError, # unhashables raise TypeError: with suppress(ValueError, TypeError): # Similar value: element_values.append( safe_eval.literal_eval_with_names(real_item, ) if isinstance( real_item, self._elements_to_eval, ) else set_item, ) self._report_set_elements(node, elements, element_values)
def _check_range_len(self, node: ast.Call) -> None: if not isinstance(nodes.get_parent(node), ForNodes): return if not functions.given_function_called(node, {'range'}): return args_len = len(node.args) is_one_arg_range = ( args_len == 1 and isinstance(node.args[0], ast.Call) and functions.given_function_called(node.args[0], {'len'}) ) is_two_args_range = ( self._is_multiple_args_range_with_len(node) and args_len == 2 ) # for three args add violation # only if `step` arg do not equals 1 or -1 step_arg = args_len == 3 and operators.unwrap_unary_node(node.args[2]) is_three_args_range = ( self._is_multiple_args_range_with_len(node) and args_len == 3 and isinstance(step_arg, ast.Num) and abs(step_arg.n) == 1 ) if any([is_one_arg_range, is_two_args_range, is_three_args_range]): self.add_violation(ImplicitEnumerateViolation(node))
def _check_zero_division(self, op: ast.operator, number: ast.AST) -> None: number = unwrap_unary_node(number) is_zero_division = (isinstance(op, self._zero_divisors) and isinstance(number, ast.Num) and number.n == 0) if is_zero_division: self.add_violation(consistency.ZeroDivisionViolation(number))
def _check_constant_condition(self, node: ast.AST) -> None: if isinstance(node, ast.BoolOp): for condition in node.values: self._check_constant_condition(condition) else: real_node = operators.unwrap_unary_node(get_assigned_expr(node)) if isinstance(real_node, self._forbidden_nodes): self.add_violation(ConstantConditionViolation(node))
def _check_condition(self, node: ast.AST, cond: ast.AST) -> None: if isinstance(cond, ast.NameConstant) and cond.value is True: if isinstance(node, ast.While): return # We should allow plain `while True:` real_node = operators.unwrap_unary_node(walrus.get_assigned_expr(cond)) if isinstance(real_node, self._forbidden_nodes): self.add_violation(WrongKeywordConditionViolation(cond))
def _check_condition(self, node: ast.AST, condition: ast.AST) -> None: real_node = operators.unwrap_unary_node(condition) if isinstance(real_node, ast.NameConstant) and real_node.value is True: if isinstance(node, ast.While): return # We should allow `while True:` if isinstance(real_node, self._forbidden_nodes): self.add_violation(WrongKeywordConditionViolation(condition))
def _check_infinite_while_loop(self, node: AnyLoop) -> None: if not isinstance(node, ast.While): return real_node = operators.unwrap_unary_node(node.test) if isinstance(real_node, ast.NameConstant) and real_node.value is True: if not loops.has_break(node, break_nodes=self._breaks): self.add_violation(InfiniteWhileLoopViolation(node))
def _is_correct_len(self, sign: ast.cmpop, comparator: ast.AST) -> bool: """Helper function which tells what calls to ``len()`` are valid.""" if isinstance(operators.unwrap_unary_node(comparator), ast.Num): numeric_value = ast.literal_eval(comparator) if numeric_value == 0: return False if numeric_value == 1: return not isinstance(sign, (ast.GtE, ast.Lt)) return True
def _check_explicit_iter_type( self, node: Union[AnyFor, ast.comprehension], ) -> None: node_iter = operators.unwrap_unary_node(node.iter) is_wrong = isinstance(node_iter, self._forbidden_for_iters) is_empty = isinstance(node_iter, ast.Tuple) and not node_iter.elts if is_wrong or is_empty: self.add_violation(WrongLoopIterTypeViolation(node_iter))
def _check_float_keys(self, keys: _HashItems) -> None: for dict_key in keys: if dict_key is None: continue real_key = operators.unwrap_unary_node(dict_key) is_float_key = (isinstance(real_key, ast.Num) and isinstance(real_key.n, float)) if is_float_key: self.add_violation(best_practices.FloatKeyViolation(dict_key))
def _check_is_constant_comprare( self, op: ast.cmpop, comparator: ast.expr, ) -> None: if not isinstance(op, (ast.Is, ast.IsNot)): return unwrapped = operators.unwrap_unary_node(comparator) if isinstance(unwrapped, self._forbidden_for_is): self.add_violation(WrongIsCompareViolation(comparator))
def _check_argument_default_values(self, node: AnyFunctionDef) -> None: for arg in node.args.defaults: real_arg = operators.unwrap_unary_node(arg) parts = attributes.parts(real_arg) if isinstance( real_arg, ast.Attribute, ) else [real_arg] for part in parts: if not isinstance(part, self._allowed_default_value_types): self.add_violation(ComplexDefaultValueViolation(arg)) return
def _get_non_negative_nodes( self, left: Optional[ast.AST], right: Optional[ast.AST] = None, ): non_negative_numbers = [] for node in filter(None, (left, right)): real_node = unwrap_unary_node(node) correct_node = (isinstance(real_node, ast.Num) and real_node.n in self._meaningless_operations and not (real_node.n == 1 and walk.is_contained(node, ast.USub))) if correct_node: non_negative_numbers.append(real_node) return non_negative_numbers
def _check_float_keys(self, keys: _HashItems) -> None: for dict_key in keys: if dict_key is None: continue evaluates_to_float = False if isinstance(dict_key, ast.BinOp): evaluated_key = getattr(dict_key, 'wps_op_eval', None) evaluates_to_float = isinstance(evaluated_key, float) real_key = operators.unwrap_unary_node(dict_key) is_float_key = (isinstance(real_key, ast.Num) and isinstance(real_key.n, float)) if is_float_key or evaluates_to_float: self.add_violation(best_practices.FloatKeyViolation(dict_key))
def _get_all_names( self, node: ast.BoolOp, ) -> List[str]: # We need to make sure that we do not visit # one chained `BoolOp` elements twice: self._same_nodes.append(node) names = [] for operand in node.values: if isinstance(operand, ast.BoolOp): names.extend(self._get_all_names(operand)) else: names.append( source.node_to_string( operators.unwrap_unary_node(operand), ), ) return names
def _check_complex_argument_defaults( self, node: AnyFunctionDefAndLambda, ) -> None: all_defaults = filter(None, ( *node.args.defaults, *node.args.kw_defaults, )) for arg in all_defaults: real_arg = operators.unwrap_unary_node(arg) parts = attributes.parts(real_arg) if isinstance( real_arg, ast.Attribute, ) else [real_arg] has_incorrect_part = any( not isinstance(part, self._allowed_default_value_types) for part in parts) if has_incorrect_part: self.add_violation(ComplexDefaultValueViolation(arg))
def _check_constant_condition(self, node: AnyIf) -> None: real_node = operators.unwrap_unary_node(get_assigned_expr(node.test), ) if isinstance(real_node, self._forbidden_nodes): self.add_violation(ConstantConditionViolation(node))
def _is_float_key(self, node: ast.expr) -> bool: real_node = operators.unwrap_unary_node(node) return (isinstance(real_node, ast.Num) and isinstance(real_node.n, float))
def _is_float_or_complex(self, node: ast.AST) -> bool: node = operators.unwrap_unary_node(node) return (isinstance(node, ast.Num) and isinstance(node.n, (float, complex)))