コード例 #1
0
 def _ensure_super_context(self, node: ast.Call) -> None:
     parent_context = nodes.get_context(node)
     if isinstance(parent_context, FunctionNodes):
         grand_context = nodes.get_context(parent_context)
         if isinstance(grand_context, ast.ClassDef):
             return
     self.add_violation(
         WrongSuperCallViolation(node, text='not inside method'), )
コード例 #2
0
 def _ensure_super_context(self, node: ast.Call) -> None:
     parent_context = nodes.get_context(node)
     if isinstance(parent_context, (ast.FunctionDef, ast.AsyncFunctionDef)):
         grand_context = nodes.get_context(parent_context)
         if isinstance(grand_context, ast.ClassDef):
             return
     self.add_violation(
         IncorrectSuperCallViolation(node, text='not inside method'),
     )
コード例 #3
0
    def _check_bound_methods(self, node: types.AnyFunctionDef) -> None:
        node_context = nodes.get_context(node)
        if not isinstance(node_context, ast.ClassDef):
            return

        if not functions.get_all_arguments(node):
            self.add_violation(
                oop.MethodWithoutArgumentsViolation(node, text=node.name),
            )

        if node.name in constants.MAGIC_METHODS_BLACKLIST:
            self.add_violation(
                oop.BadMagicMethodViolation(node, text=node.name),
            )

        is_async = isinstance(node, ast.AsyncFunctionDef)
        if is_async and access.is_magic(node.name):
            if node.name in constants.ASYNC_MAGIC_METHODS_BLACKLIST:
                self.add_violation(
                    oop.AsyncMagicMethodViolation(node, text=node.name),
                )

        self._check_useless_overwritten_methods(
            node,
            class_name=node_context.name,
        )
コード例 #4
0
    def _ensure_super_context(self, node: ast.Call) -> None:
        parent_context = nodes.get_context(node)
        parent_node = nodes.get_parent(node)

        attr = getattr(parent_node, 'attr', None)
        parent_name = getattr(parent_context, 'name', None)

        if attr and parent_name and attr != parent_name:
            self.add_violation(oop.WrongSuperCallAccessViolation(node), )

        if isinstance(parent_context, FunctionNodes):
            grand_context = nodes.get_context(parent_context)
            if isinstance(grand_context, ast.ClassDef):
                return
        self.add_violation(
            oop.WrongSuperCallViolation(node, text='not inside method'), )
コード例 #5
0
ファイル: classes.py プロジェクト: Silentsoul04/wps-light
def find_getters_and_setters(node: ast.ClassDef) -> Iterable[AnyFunctionDef]:
    """Returns nodes of all getter or setter methods."""
    for sub in ast.walk(node):
        is_correct_context = nodes.get_context(sub) is node
        if isinstance(sub, FunctionNodes) and is_correct_context:
            if sub.name[:GETTER_LENGTH] in _GetterSetterPrefixes:
                yield sub
コード例 #6
0
    def _check_variable_usage(self, node: ast.Name) -> None:
        context = cast(ast.AST, get_context(node))
        blocks = self._block_variables[context][node.id]
        if all(is_contained_by(node, block) for block in blocks):
            return

        self.add_violation(
            ControlVarUsedAfterBlockViolation(node, text=node.id), )
コード例 #7
0
def _get_annotated_class_attribute(
    node: ast.ClassDef,
    subnode: ast.AST,
) -> Optional[AnyAssign]:
    return subnode if (
        nodes.get_context(subnode) is node and
        (getattr(subnode, 'value', None) and isinstance(subnode, AssignNodes))
        or isinstance(subnode, ast.AnnAssign)) else None
コード例 #8
0
 def _is_correct_return_node(
     self,
     node: AnyFunctionDef,
     sub_node: ast.AST,
 ) -> bool:
     if get_context(sub_node) != node:
         return False
     return isinstance(sub_node, self._checking_nodes)
コード例 #9
0
    def _check_magic_module_functions(self, node: ast.FunctionDef) -> None:
        if self.options.i_control_code:
            if not isinstance(get_context(node), ast.Module):
                return

            if node.name in constants.MAGIC_MODULE_NAMES_BLACKLIST:
                self.add_violation(
                    BadMagicModuleFunctionViolation(node, text=node.name), )
コード例 #10
0
    def _check_nested_function(self, node: AnyFunctionDef) -> None:
        is_inside_function = isinstance(get_context(node), FunctionNodes)

        is_direct = isinstance(get_parent(node), FunctionNodes)
        is_bad = is_direct and node.name not in NESTED_FUNCTIONS_WHITELIST

        if is_bad or (is_inside_function and not is_direct):
            self.add_violation(NestedFunctionViolation(node, text=node.name))
コード例 #11
0
def _get_class_attribute(
    node: ast.ClassDef, subnode: ast.AST,
) -> Optional[AnyAssign]:
    return subnode if (
        isinstance(subnode, AssignNodes) and
        nodes.get_context(subnode) == node and
        getattr(subnode, 'value', None)
    ) else None
コード例 #12
0
def has_recursive_calls(func: AnyFunctionDef) -> bool:
    """
    Determines whether function has recursive calls or not.

    Does not work for methods.
    """
    if isinstance(get_context(func), ClassDef):
        return _check_method_recursion(func)
    return _check_function_recursion(func)
コード例 #13
0
def is_class_context(node: ast.AST) -> bool:
    """
    Detects if a node is inside a class context.

    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.
    """
    return isinstance(nodes.get_context(node), ast.ClassDef)
コード例 #14
0
    def _is_reassignment_edge_case(self, node: AnyAssign) -> bool:
        # This is not a variable, but a class property
        if isinstance(nodes.get_context(node), ast.ClassDef):
            return True

        # It means that someone probably modifies original value
        # of the variable using some unary operation, e.g. `a = not a`
        # See #2189
        return isinstance(node.value, ast.UnaryOp)
コード例 #15
0
    def check_attribute_name(self, node: ast.ClassDef) -> None:
        top_level_assigns = [
            sub for sub in ast.walk(node)
            if isinstance(sub, AssignNodes) and nodes.get_context(sub) is node
        ]

        for assignment in top_level_assigns:
            for target in get_assign_targets(assignment):
                self._ensure_case(target)
コード例 #16
0
 def _check_implicit_yield_from(self, node: AnyFor) -> None:
     if isinstance(nodes.get_context(node), ast.AsyncFunctionDef):
         # Python does not support 'yield from' inside async functions
         return
     is_implicit_yield_from = (len(node.body) == 1
                               and isinstance(node.body[0], ast.Expr) and
                               isinstance(node.body[0].value, ast.Yield))
     if is_implicit_yield_from:
         self.add_violation(ImplicitYieldFromViolation(node))
コード例 #17
0
    def _check_nested_classes(self, node: ast.ClassDef) -> None:
        parent_context = get_context(node)

        is_inside_class = isinstance(parent_context, ast.ClassDef)
        is_bad = is_inside_class and node.name not in NESTED_CLASSES_WHITELIST

        is_inside_function = isinstance(parent_context, FunctionNodes)

        if is_bad or is_inside_function:
            self.add_violation(NestedClassViolation(node, text=node.name))
コード例 #18
0
    def _check_bound_methods(self, node: types.AnyFunctionDef) -> None:
        node_context = get_context(node)
        if not isinstance(node_context, ast.ClassDef):
            return

        if not get_all_arguments(node):
            self.add_violation(
                MethodWithoutArgumentsViolation(node, text=node.name), )

        if node.name in constants.MAGIC_METHODS_BLACKLIST:
            self.add_violation(BadMagicMethodViolation(node, text=node.name))
コード例 #19
0
    def _check_if_needs_except(self, node: ast.Try) -> None:
        if not node.finalbody or node.handlers:
            return

        context = nodes.get_context(node)
        if isinstance(context, FunctionNodes) and context.decorator_list:
            # This is used inside a decorated function, it might be the only
            # way to handle this situation. Eg: ``@contextmanager``
            return

        self.add_violation(UselessFinallyViolation(node))
コード例 #20
0
    def _build_outer_context(self) -> Set[str]:
        outer_names: Set[str] = set()
        context = self._context

        while True:
            context = cast(ContextNodes, get_context(context))
            outer_names = outer_names.union(self._scopes[context])
            if not context:
                break

        return outer_names
コード例 #21
0
    def _check_nested_classes(self, node: ast.ClassDef) -> None:
        parent_context = get_context(node)

        is_inside_class = isinstance(parent_context, ast.ClassDef)
        is_whitelisted = node.name in self.options.nested_classes_whitelist

        is_bad = is_inside_class and not is_whitelisted

        is_inside_function = isinstance(parent_context, FunctionNodes)

        if is_bad or is_inside_function:
            self.add_violation(NestedClassViolation(node, text=node.name))
コード例 #22
0
    def _check_method_order(self, node: ast.ClassDef) -> None:
        method_nodes: List[str] = []

        for subnode in ast.walk(node):
            if isinstance(subnode, FunctionNodes):
                if nodes.get_context(subnode) == node:
                    method_nodes.append(subnode.name)

        ideal = sorted(method_nodes, key=self._ideal_order, reverse=True)
        for existing_order, ideal_order in zip(method_nodes, ideal):
            if existing_order != ideal_order:
                self.add_violation(consistency.WrongMethodOrderViolation(node))
                return
コード例 #23
0
    def _check_slots(self, node: types.AnyAssign) -> None:
        if not isinstance(nodes.get_context(node), ast.ClassDef):
            return

        if not self._contains_slots_assign(node):
            return

        if not isinstance(node.value, self._whitelisted_slots_nodes):
            self.add_violation(oop.WrongSlotsViolation(node))
            return

        if isinstance(node.value, ast.Tuple):
            self._count_slots_items(node, node.value)
コード例 #24
0
    def _check_slots(self, node: AnyAssign) -> None:
        if not isinstance(get_context(node), ast.ClassDef):
            return

        if not self._contains_slots_assign(node):
            return

        if isinstance(node.value, self._blacklisted_slots_nodes):
            self.add_violation(IncorrectSlotsViolation(node))
            return

        if isinstance(node.value, ast.Tuple):
            self._count_slots_items(node, node.value)
コード例 #25
0
    def _check_mutable_constant(self, node: AnyAssign) -> None:
        if not isinstance(get_context(node), ast.Module):
            return

        targets = ([node.target]
                   if isinstance(node, ast.AnnAssign) else node.targets)

        for target in targets:
            if not isinstance(target, ast.Name) or not is_constant(target.id):
                continue

            if isinstance(node.value, self._mutable_nodes):
                self.add_violation(MutableModuleConstantViolation(target))
コード例 #26
0
def does_shadow_builtin(node: ast.AST) -> bool:
    """
    We allow attributes and class-level builtin overrides.

    Like: ``self.list = []`` or ``def map(self, function):``

    Why?
    Because they cannot harm you since they do not shadow the real builtin.
    """
    return (
        not isinstance(node, ast.Attribute) and
        not isinstance(nodes.get_context(node), ast.ClassDef)
    )
コード例 #27
0
def returning_nodes(
    node: ast.AST,
    returning_type: Union[Type[ast.Return], Type[ast.Yield]],
) -> Tuple[_ReturningNodes, bool]:
    """Returns ``return`` or ``yield`` nodes with values."""
    returns: _ReturningNodes = []
    has_values = False
    for sub_node in ast.walk(node):
        context_node = get_context(sub_node)
        if isinstance(sub_node, returning_type) and context_node == node:
            if sub_node.value:  # type: ignore
                has_values = True
            returns.append(sub_node)  # type: ignore
    return returns, has_values
コード例 #28
0
def returning_nodes(
    node: ast.AST,
    returning_type,
) -> Tuple[List[ast.Return], bool]:
    """Returns ``return`` or ``yield`` nodes with values."""
    returns: List[ast.Return] = []
    has_values = False
    for sub_node in ast.walk(node):
        context_node = get_context(sub_node)
        if isinstance(sub_node, returning_type) and context_node == node:
            if sub_node.value:
                has_values = True
            returns.append(sub_node)
    return returns, has_values
コード例 #29
0
    def _get_attributes(
        self,
        node: ast.ClassDef,
    ) -> Tuple[List[AnyAssign], List[ast.Attribute]]:
        class_attributes = []
        instance_attributes = []

        for child in ast.walk(node):
            if isinstance(child, ast.Attribute):
                if isinstance(child.ctx, ast.Store):
                    instance_attributes.append(child)
            if isinstance(child, AssignNodes) and get_context(child) == node:
                if child.value is not None:  # Not: `a: int`
                    class_attributes.append(child)
        return class_attributes, instance_attributes
コード例 #30
0
    def _check_variable_usage(self, node: ast.Name) -> None:
        context = cast(ast.AST, get_context(node))
        blocks = self._block_variables[context][node.id]
        is_contained_block_var = any(
            is_contained_by(node, block) for block in blocks)
        # Restrict the use of block variables with the same name to
        # the same type of block - either `for` or `with`.
        is_same_type_block = all(
            isinstance(block, ForNodes) for block in blocks) or all(
                isinstance(block, WithNodes) for block in blocks)
        # Return if not a block variable or a contained block variable.
        if not blocks or (is_contained_block_var and is_same_type_block):
            return

        self.add_violation(
            ControlVarUsedAfterBlockViolation(node, text=node.id), )