Module rulebook-pylint.rulebook_pylint.nested_if_else

Functions

def register(linter: PyLinter)
Expand source code
def register(linter: 'PyLinter') -> None:
    linter.register_checker(NestedIfElseChecker(linter))

Classes

class NestedIfElseChecker (linter: PyLinter)
Expand source code
class NestedIfElseChecker(RulebookChecker):
    """See detail: https://hanggrian.github.io/rulebook/rules/#nested-if-else"""
    MSG_INVERT: str = 'nested-if-else-invert'
    MSG_LIFT: str = 'nested-if-else-lift'

    name: str = 'nested-if-else'
    msgs: dict[str, MessageDefinitionTuple] = Messages.of(MSG_INVERT, MSG_LIFT)

    def visit_for(self, node: For) -> None:
        self._process(node.body)

    def visit_while(self, node: While) -> None:
        self._process(node.body)

    def visit_functiondef(self, node: FunctionDef) -> None:
        self._process(node.body)

    def _process(self, body: list[NodeNG]) -> None:
        # get last if
        if2: If | None = None
        children: list[NodeNG] = body.copy()
        children.reverse()
        for child in children:
            if isinstance(child, If):
                if2 = child
                break
            return
        if not if2:
            return

        # checks for violation
        else2: list[NodeNG] = if2.orelse

        if len(else2) > 0:
            else_first_child: NodeNG = else2[0]
            if self._else_has_if(else2):
                return
            if self._has_multiple_lines(else2):
                self.add_message(self.MSG_LIFT, node=else_first_child)
            return
        if has_jump_statement(if2):
            return
        if self._has_multiple_lines(if2.body):
            self.add_message(self.MSG_INVERT, node=if2)

    @staticmethod
    def _else_has_if(nodes: list[NodeNG]) -> bool:
        return any(isinstance(node, If) for node in nodes)

    @staticmethod
    def _has_multiple_lines(nodes: list[NodeNG]) -> bool:
        length: int = len(nodes)
        if length == 1:
            return is_multiline(nodes[0])
        return length > 1

See detail: https://hanggrian.github.io/rulebook/rules/#nested-if-else

Checker instances should have the linter as argument.

Ancestors

  • rulebook_pylint.checkers.RulebookChecker
  • pylint.checkers.base_checker.BaseChecker
  • pylint.config.arguments_provider._ArgumentsProvider

Class variables

var MSG_INVERT : str

The type of the None singleton.

var MSG_LIFT : str

The type of the None singleton.

var msgs : dict[str, tuple[str, str, str] | tuple[str, str, str, pylint.typing.ExtraMessageOptions]]

The type of the None singleton.

var name : str

The type of the None singleton.

Methods

def visit_for(self, node: astroid.nodes.node_classes.For) ‑> None
Expand source code
def visit_for(self, node: For) -> None:
    self._process(node.body)
def visit_functiondef(self, node: astroid.nodes.scoped_nodes.scoped_nodes.FunctionDef) ‑> None
Expand source code
def visit_functiondef(self, node: FunctionDef) -> None:
    self._process(node.body)
def visit_while(self, node: astroid.nodes.node_classes.While) ‑> None
Expand source code
def visit_while(self, node: While) -> None:
    self._process(node.body)