Exemple #1
0
    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))
Exemple #2
0
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
    def _check_last_return_in_function(self, node: ast.Return) -> None:
        parent = get_parent(node)
        if not isinstance(parent, FunctionNodes):
            return

        returns = len(tuple(filter(
            lambda return_node: return_node.value is not None,
            walk.get_subnodes_by_type(parent, ast.Return),
        )))

        last_value_return = (
            len(parent.body) > 1 and
            returns < 2 and
            isinstance(node.value, ast.NameConstant) and
            node.value.value is None
        )

        one_return_with_none = (
            returns == 1 and
            isinstance(node.value, ast.NameConstant) and
            node.value.value is None
        )

        if node.value is None or last_value_return or one_return_with_none:
            self.add_violation(InconsistentReturnViolation(node))
Exemple #4
0
    def _check_method(self, node: AnyFunctionDef) -> None:
        if decorators.has_overload_decorator(node):
            return  # we don't count `@overload` methods

        parent = get_parent(node)
        if isinstance(parent, ast.ClassDef):
            self._methods[parent] += 1
Exemple #5
0
    def _check_type_compare(self, node: ast.Call) -> None:
        function_name = functions.given_function_called(node, {'type'})
        if not function_name:
            return

        if isinstance(nodes.get_parent(node), ast.Compare):
            self.add_violation(TypeCompareViolation(node))
Exemple #6
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))
    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_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))
Exemple #9
0
 def visit_withitem(self, node: ast.withitem) -> None:
     """Visits ``with`` and ``async with`` declarations."""
     if node.optional_vars:
         parent = cast(AnyWith, get_parent(node))
         names = defs.extract_names(node.optional_vars)
         self._scope(parent, names, is_local=False)
         self._outer_scope(parent, names)
     self.generic_visit(node)
Exemple #10
0
 def visit_withitem(self, node: ast.withitem) -> None:
     """Visits ``with`` and ``async with`` declarations."""
     if node.optional_vars:
         self._add_to_scope(
             cast(AnyWith, get_parent(node)),
             defs.extract_names(node.optional_vars),
         )
     self.generic_visit(node)
 def visit_JoinedStr(self, node: ast.JoinedStr) -> None:
     """Forbids use of ``f`` strings and too complex ``f`` strings."""
     if not isinstance(nodes.get_parent(node), ast.FormattedValue):
         # We don't allow `f` strings by default,
         # But, we need this condition to make sure that this
         # is not a part of complex string format like `f"Count={count:,}"`:
         self._check_complex_formatted_string(node)
         self.add_violation(consistency.FormattedStringViolation(node))
     self.generic_visit(node)
Exemple #12
0
    def _check_string_constant(self, node: ast.Str) -> None:
        parent = nodes.get_parent(node)
        if isinstance(parent, _AnnNodes) and parent.annotation == node:
            return  # it is argument or variable annotation

        if isinstance(parent, FunctionNodes) and parent.returns == node:
            return  # it is return annotation

        self._string_constants[node.s] += 1
    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))
Exemple #14
0
 def visit_withitem(self, node: ast.withitem) -> None:
     """Checks that we cannot create explicit unused context variables."""
     if node.optional_vars:
         self._check_assign_unused(
             cast(ast.AST, nodes.get_parent(node)),
             name_nodes.get_variables_from_node(node.optional_vars),
             is_local=True,
         )
     self.generic_visit(node)
Exemple #15
0
    def _check_metadata(self, node: AnyAssign) -> None:
        if not isinstance(nodes.get_parent(node), ast.Module):
            return

        targets = get_assign_targets(node)
        for target_node in targets:
            target_node_id = _get_name_from_node(target_node)
            if target_node_id in MODULE_METADATA_VARIABLES_BLACKLIST:
                self.add_violation(
                    WrongModuleMetadataViolation(node, text=target_node_id), )
    def _check_simplifiable_returning_parent(self, node: ast.If) -> None:
        parent = get_parent(node)
        if isinstance(parent, _ELSE_NODES):
            body = parent.body + parent.orelse
        else:
            body = getattr(parent, 'body', [node])

        next_index_in_parent = body.index(node) + 1
        if keywords.next_node_returns_bool(body, next_index_in_parent):
            self.add_violation(SimplifiableReturningIfViolation(node))
def is_same_try_except_cases(node: ast.AST, names: Set[str]) -> bool:
    """Same names in different ``except`` blocks are not counted."""
    if not isinstance(node, ast.ExceptHandler):
        return False

    for except_handler in getattr(get_parent(node), 'handlers', []):
        if except_handler.name and except_handler.name == node.name:
            if except_handler is not node:
                return True
    return False
Exemple #18
0
    def _is_type_annotation(self, node: ast.BinOp) -> bool:
        parent_node = get_parent(node)

        if isinstance(parent_node, (ast.AnnAssign, ast.arg)):
            return node is parent_node.annotation

        if isinstance(parent_node, ast.FunctionDef):
            return node is parent_node.returns

        return False
Exemple #19
0
    def _check_open_call_context(self, node: ast.Call) -> None:
        function_name = functions.given_function_called(node, {'open'})
        if not function_name:
            return

        if isinstance(nodes.get_parent(node), ast.withitem):
            # We do not care about `with` or `async with` - both are fine.
            return

        self.add_violation(OpenWithoutContextManagerViolation(node))
    def _check_modulo_patterns(
        self,
        node: AnyText,
        text_data: Optional[str],
    ) -> None:
        parent = nodes.get_parent(node)
        if parent and strings.is_doc_string(parent):
            return  # we allow `%s` in docstrings: they cannot be formatted.

        if self._modulo_string_pattern.search(text_data):
            self.add_violation(consistency.ModuloStringFormatViolation(node))
Exemple #21
0
    def _check_members_count(self, node: _ModuleMembers) -> None:
        """This method increases the number of module members."""
        if functions.is_method(getattr(node, 'function_type', '')):
            return

        if isinstance(node, FunctionNodes):
            if decorators.has_overload_decorator(node):
                return  # We don't count `@overload` defs as real defs

        if isinstance(get_parent(node), ast.Module):
            self._public_items_count += 1
Exemple #22
0
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)
Exemple #23
0
    def _check_descriptor_decorators(self, node: AnyFunctionDef) -> None:
        if isinstance(nodes.get_parent(node), ast.ClassDef):
            return  # classes can contain descriptors

        descriptor_decorators = [
            decorator.id in self._descriptor_decorators
            for decorator in node.decorator_list
            if isinstance(decorator, ast.Name)
        ]

        if any(descriptor_decorators):
            self.add_violation(oop.WrongDescriptorDecoratorViolation(node), )
Exemple #24
0
    def visit_alias(self, node: ast.alias) -> None:
        """
        Visits aliases from ``import`` and ``from ... import`` block nodes.

        Raises:
            BlockAndLocalOverlapViolation

        """
        parent = cast(AnyImport, get_parent(node))
        import_name = {node.asname} if node.asname else {node.name}
        self._scope(parent, import_name, is_local=False)
        self._outer_scope(parent, import_name)
        self.generic_visit(node)
Exemple #25
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 strings.is_doc_string(node):
            if isinstance(nodes.get_parent(node), self._have_doc_strings):
                return

        self.add_violation(StatementHasNoEffectViolation(node))
Exemple #26
0
    def _post_visit(self) -> None:
        previous_line: Optional[int] = None
        previous_parent: Optional[ast.AST] = None

        for line, node in self._yield_locations.items():
            parent = get_parent(node)

            if previous_line is not None:
                if line - 1 == previous_line and previous_parent == parent:
                    self.add_violation(ConsecutiveYieldsViolation(node.value))
                    break

            previous_line = line
            previous_parent = parent
    def visit_alias(self, node: ast.alias) -> None:
        """
        Visits aliases from ``import`` and ``from ... import`` block nodes.

        Raises:
            BlockAndLocalOverlapViolation

        """
        import_name = node.asname if node.asname else node.name
        self._scope(
            cast(AnyImport, get_parent(node)),
            {import_name},
            is_local=False,
        )
        self.generic_visit(node)
    def visit_withitem(self, node: ast.withitem) -> None:
        """
        Visits ``with`` and ``async with`` declarations.

        Raises:
            BlockAndLocalOverlapViolation

        """
        if node.optional_vars:
            self._scope(
                cast(AnyWith, get_parent(node)),
                _extract_names(node.optional_vars),
                is_local=False,
            )
        self.generic_visit(node)
Exemple #29
0
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)
def _find_context(
    node: ast.AST,
    contexts: Tuple[Type[ast.AST], ...],
) -> Optional[ast.AST]:
    """
    We changed how we find and assign contexts in 0.8.1 version.

    It happened because of the bug #520
    See: https://github.com/wemake-services/wemake-python-styleguide/issues/520
    """
    parent = get_parent(node)
    if parent is None:
        return None
    elif isinstance(parent, contexts):
        return parent
    return _find_context(parent, contexts)