def fix_line_number(tree: ast.AST) -> ast.AST:
    """
    Adjusts line number for some nodes.

    They are set incorrectly for some collections.
    It might be either a bug or a feature.

    We do several checks here, to be sure that we won't get
    an incorrect line number. But, we basically check if there's
    a parent, so we can compare and adjust.

    Example::

        print((  # should start from here
            1, 2, 3,  # actually starts from here
        ))

    """
    affected = (ast.Tuple, )
    for node in ast.walk(tree):
        if isinstance(node, affected):
            parent_lineno = getattr(get_parent(node), 'lineno', None)
            if parent_lineno and parent_lineno < node.lineno:
                node.lineno = node.lineno - 1
    return tree
示例#2
0
    def _check_last_return_in_function(self, node: ast.Return) -> None:
        parent = get_parent(node)
        if not isinstance(parent, (ast.FunctionDef, ast.AsyncFunctionDef)):
            return

        if node is parent.body[-1] and node.value is None:
            self.add_violation(InconsistentReturnViolation(node))
示例#3
0
    def _check_variable_definitions(self, node: ast.withitem) -> None:
        if node.optional_vars is None:
            return

        if not is_valid_block_variable_definition(node.optional_vars):
            self.add_violation(
                ContextManagerVariableDefinitionViolation(get_parent(node)), )
    def _check_nested_classes(self, node: ast.ClassDef) -> None:
        parent = get_parent(node)
        is_inside_class = isinstance(parent, ast.ClassDef)
        is_inside_function = isinstance(parent, self._function_nodes)

        if is_inside_class and node.name not in NESTED_CLASSES_WHITELIST:
            self.add_violation(NestedClassViolation(node, text=node.name))
        elif is_inside_function:
            self.add_violation(NestedClassViolation(node, text=node.name))
示例#5
0
    def _check_metadata(self, node: ast.Assign) -> None:
        if not isinstance(nodes.get_parent(node), ast.Module):
            return

        for target_node in node.targets:
            target_node_id = getattr(target_node, 'id', None)
            if target_node_id in MODULE_METADATA_VARIABLES_BLACKLIST:
                self.add_violation(
                    WrongModuleMetadataViolation(node, text=target_node_id), )
def count_unary_operator(
    node: ast.AST,
    operator: AnyUnaryOp,
    amount: int = 0,
) -> int:
    """Returns amount of unary operators matching input."""
    parent = get_parent(node)
    if parent is None or not isinstance(parent, ast.UnaryOp):
        return amount
    if isinstance(parent.op, (operator, )):
        return count_unary_operator(parent, operator, amount + 1)
    return count_unary_operator(parent, operator, amount)
示例#7
0
    def _check_expression(
        self,
        node: ast.Expr,
        is_first: bool = False,
    ) -> None:
        if isinstance(node.value, self._have_effect):
            return

        if is_first and is_doc_string(node):
            if isinstance(get_parent(node), self._have_doc_strings):
                return

        self.add_violation(StatementHasNoEffectViolation(node))
def get_parent_ignoring_unary(node: ast.AST) -> Optional[ast.AST]:
    """
    Returns real parent ignoring proxy unary parent level.

    What can go wrong?

    1. Number can be negative: ``x = -1``,
       so ``1`` has ``UnaryOp`` as parent, but should return ``Assign``
    2. Some values can be negated: ``x = --some``,
       so ``some`` has ``UnaryOp`` as parent, but should return ``Assign``

    """
    parent = get_parent(node)
    if parent is None or not isinstance(parent, ast.UnaryOp):
        return parent
    return get_parent_ignoring_unary(parent)
示例#9
0
    def _update_variables(
        self,
        function: AnyFunctionDef,
        variable_def: ast.Name,
    ) -> None:
        """
        Increases the counter of local variables.

        What is treated as a local variable?
        Check ``TooManyLocalsViolation`` documentation.
        """
        function_variables = self.variables[function]
        if variable_def.id not in function_variables:
            if variable_def.id == UNUSED_VARIABLE:
                return

            if isinstance(get_parent(variable_def), self._not_contain_locals):
                return

            function_variables.append(variable_def.id)
示例#10
0
    def _check_members_count(self, node: ModuleMembers) -> None:
        """This method increases the number of module members."""
        is_real_method = is_method(getattr(node, 'function_type', None))

        if isinstance(get_parent(node), ast.Module) and not is_real_method:
            self._public_items_count += 1
示例#11
0
 def _check_method(self, node: AnyFunctionDef) -> None:
     parent = get_parent(node)
     if isinstance(parent, ast.ClassDef):
         self._methods[parent] += 1
示例#12
0
 def _check_fors(self, node: ast.comprehension) -> None:
     parent = get_parent(node)
     self._fors[parent] = len(parent.generators)  # type: ignore
示例#13
0
 def _check_ifs(self, node: ast.comprehension) -> None:
     if len(node.ifs) > self._max_ifs:
         # We are trying to fix line number in the report,
         # since `comprehension` does not have this property.
         parent = get_parent(node) or node
         self.add_violation(MultipleIfsInComprehensionViolation(parent))
示例#14
0
 def check_nested_import(self, node: AnyImport) -> None:
     parent = nodes.get_parent(node)
     if parent is not None and not isinstance(parent, ast.Module):
         self._error_callback(NestedImportViolation(node))
 def _check_nested_lambdas(self, node: ast.Lambda) -> None:
     if isinstance(get_parent(node), ast.Lambda):
         self.add_violation(NestedFunctionViolation(node, text='lambda'))
    def _check_nested_function(self, node: AnyFunctionDef) -> None:
        is_inside_function = isinstance(get_parent(node), self._function_nodes)

        if is_inside_function and node.name not in NESTED_FUNCTIONS_WHITELIST:
            self.add_violation(NestedFunctionViolation(node, text=node.name))