PHP 8.2.31
Preview: nested_min_max.py Size: 3.63 KB
/opt/cloudlinux/venv/lib/python3.11/site-packages/pylint/checkers/nested_min_max.py

# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
# For details: https://github.com/PyCQA/pylint/blob/main/LICENSE
# Copyright (c) https://github.com/PyCQA/pylint/blob/main/CONTRIBUTORS.txt

"""Check for use of nested min/max functions."""

from __future__ import annotations

import copy
from typing import TYPE_CHECKING

from astroid import nodes, objects

from pylint.checkers import BaseChecker
from pylint.checkers.utils import only_required_for_messages, safe_infer
from pylint.interfaces import INFERENCE

if TYPE_CHECKING:
    from pylint.lint import PyLinter

DICT_TYPES = (
    objects.DictValues,
    objects.DictKeys,
    objects.DictItems,
    nodes.node_classes.Dict,
)


class NestedMinMaxChecker(BaseChecker):
    """Multiple nested min/max calls on the same line will raise multiple messages.

    This behaviour is intended as it would slow down the checker to check
    for nested call with minimal benefits.
    """

    FUNC_NAMES = ("builtins.min", "builtins.max")

    name = "nested_min_max"
    msgs = {
        "W3301": (
            "Do not use nested call of '%s'; it's possible to do '%s' instead",
            "nested-min-max",
            "Nested calls ``min(1, min(2, 3))`` can be rewritten as ``min(1, 2, 3)``.",
        )
    }

    @classmethod
    def is_min_max_call(cls, node: nodes.NodeNG) -> bool:
        if not isinstance(node, nodes.Call):
            return False

        inferred = safe_infer(node.func)
        return (
            isinstance(inferred, nodes.FunctionDef)
            and inferred.qname() in cls.FUNC_NAMES
        )

    @classmethod
    def get_redundant_calls(cls, node: nodes.Call) -> list[nodes.Call]:
        return [
            arg
            for arg in node.args
            if cls.is_min_max_call(arg) and arg.func.name == node.func.name
        ]

    @only_required_for_messages("nested-min-max")
    def visit_call(self, node: nodes.Call) -> None:
        if not self.is_min_max_call(node):
            return

        redundant_calls = self.get_redundant_calls(node)
        if not redundant_calls:
            return

        fixed_node = copy.copy(node)
        while len(redundant_calls) > 0:
            for i, arg in enumerate(fixed_node.args):
                # Exclude any calls with generator expressions as there is no
                # clear better suggestion for them.
                if isinstance(arg, nodes.Call) and any(
                    isinstance(a, nodes.GeneratorExp) for a in arg.args
                ):
                    return

                if arg in redundant_calls:
                    fixed_node.args = (
                        fixed_node.args[:i] + arg.args + fixed_node.args[i + 1 :]
                    )
                    break

            redundant_calls = self.get_redundant_calls(fixed_node)

        for idx, arg in enumerate(fixed_node.args):
            if not isinstance(arg, nodes.Const):
                inferred = safe_infer(arg)
                if isinstance(
                    inferred, (nodes.List, nodes.Tuple, nodes.Set, *DICT_TYPES)
                ):
                    splat_node = nodes.Starred(lineno=inferred.lineno)
                    splat_node.value = arg
                    fixed_node.args = (
                        fixed_node.args[:idx]
                        + [splat_node]
                        + fixed_node.args[idx + 1 : idx]
                    )

        self.add_message(
            "nested-min-max",
            node=node,
            args=(node.func.name, fixed_node.as_string()),
            confidence=INFERENCE,
        )


def register(linter: PyLinter) -> None:
    linter.register_checker(NestedMinMaxChecker(linter))

Directory Contents

Dirs: 4 × Files: 31

Name Size Perms Modified Actions
base DIR
- drwxr-xr-x 2026-02-05 08:01:15
Edit Download
classes DIR
- drwxr-xr-x 2026-02-05 08:01:15
Edit Download
- drwxr-xr-x 2026-02-05 08:01:15
Edit Download
- drwxr-xr-x 2026-02-05 08:01:15
Edit Download
3.83 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
2.18 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
10.67 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
9.43 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
21.62 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
3.43 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
1.97 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
26.05 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
26.91 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
41.31 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
3.38 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
15.84 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
1.08 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
4.68 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
4.87 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
7.67 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
3.63 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
4.46 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
6.98 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
3.81 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
33.29 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
16.17 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
31.28 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
40.28 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
1.90 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
86.83 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
18.05 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
2.93 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
77.26 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
126.57 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download
4.26 KB lrw-r--r-- 2026-01-20 13:01:48
Edit Download

If ZipArchive is unavailable, a .tar will be created (no compression).