예제 #1
0
 def _is_decorator(
     self,
     node: ast.AST,
 ) -> bool:
     parent = walk.get_closest_parent(node, FunctionNodes)
     if isinstance(parent, FunctionNodes) and parent.decorator_list:
         return any(
             node == decorator or walk.is_contained_by(node, decorator)
             for decorator in parent.decorator_list)
     return False
예제 #2
0
    def _check_nested_ifexpr(self, node: AnyIf) -> None:
        is_nested_in_if = bool(
            isinstance(node, ast.If)
            and list(walk.get_subnodes_by_type(node.test, ast.IfExp)), )
        is_nested_poorly = walk.get_closest_parent(
            node,
            self._forbidden_expression_parents,
        )

        if is_nested_in_if or is_nested_poorly:
            self.add_violation(NestedTernaryViolation(node))
    def _add_expression(self, node: ast.AST) -> None:
        if any(ignore(node) for ignore in self._ignore_predicates):
            return

        source_code = source.node_to_string(node)
        self._module_expressions[source_code].append(node)

        maybe_function = walk.get_closest_parent(node, FunctionNodes)
        if maybe_function is not None:
            self._function_expressions[maybe_function][source_code].append(
                node, )
예제 #4
0
def is_decorator(node: ast.AST) -> bool:
    """
    Detects if node is used as a decorator.

    We use this predicates because decorators can be used miltiple times.
    Like ``@auth_required(login_url=LOGIN_URL)`` and similar.
    """
    parent = walk.get_closest_parent(node, FunctionNodes)
    if isinstance(parent, FunctionNodes) and parent.decorator_list:
        return any(node == decorator or walk.is_contained_by(node, decorator)
                   for decorator in parent.decorator_list)
    return False
예제 #5
0
    def _is_annotation(self, node: ast.AST) -> bool:
        typed_assign = walk.get_closest_parent(
            node,
            (ast.AnnAssign, ast.arg),
        )

        if isinstance(typed_assign, _AnnNodes) and typed_assign.annotation:
            is_same_node = node == typed_assign.annotation
            is_child_annotation = walk.is_contained_by(
                node, typed_assign.annotation,
            )
            return is_same_node or is_child_annotation
        return False
예제 #6
0
    def _add_expression(self, node: ast.AST) -> None:
        ignore_predicates = [
            self._is_decorator,
            self._is_self_method,
            self._is_annotation,

            # We use this predicate because classes have quite complex
            # DSL to be created: like django-orm, attrs, and dataclasses.
            # And these DSLs are built using attributes and calls.
            _is_class_context,
        ]
        if any(ignore(node) for ignore in ignore_predicates):
            return

        source_code = astor.to_source(node).strip()
        self._module_expressions[source_code].append(node)

        maybe_function = walk.get_closest_parent(node, FunctionNodes)
        if maybe_function is not None:
            self._function_expressions[maybe_function][source_code].append(
                node, )
예제 #7
0
def is_annotation(node: ast.AST) -> bool:
    """
    Detects if node is an annotation. Or a part of it.

    We use this predicate to allow all types of repetetive
    function and instance annotations.
    """
    if not isinstance(node, _AnnParts):
        return False

    annotated = walk.get_closest_parent(node, (*_AnnNodes, *FunctionNodes))
    if isinstance(annotated, FunctionNodes):
        contains_node = bool(
            annotated.returns
            and walk.is_contained_by(node, annotated.returns), )
        return node == annotated.returns or contains_node
    elif isinstance(annotated, _AnnNodes):
        contains_node = bool(
            annotated.annotation
            and walk.is_contained_by(node, annotated.annotation), )
        return node == annotated.annotation or contains_node
    return False
예제 #8
0
    def _check_bare_raise(self, node: ast.Raise) -> None:
        if node.exc is None:
            parent_except = walk.get_closest_parent(node, ast.ExceptHandler)

            if not parent_except:
                self.add_violation(BareRaiseViolation(node))
    def _check_nested_lambdas(self, node: ast.Lambda) -> None:
        is_direct = isinstance(get_context(node), ast.Lambda)
        is_deep = get_closest_parent(node, ast.Lambda)

        if is_direct or is_deep:
            self.add_violation(NestedFunctionViolation(node, text='lambda'))