Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions doc/whatsnew/fragments/8168.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Fix ``nested-min-max`` suggestion message to indicate it's possible to splat iterable objects.

Closes #8168
23 changes: 22 additions & 1 deletion pylint/checkers/nested_min_max.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import copy
from typing import TYPE_CHECKING

from astroid import nodes
from astroid import nodes, objects

from pylint.checkers import BaseChecker
from pylint.checkers.utils import only_required_for_messages, safe_infer
Expand All @@ -18,6 +18,13 @@
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.
Expand Down Expand Up @@ -83,6 +90,20 @@ def visit_call(self, node: nodes.Call) -> None:

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,
Expand Down
23 changes: 23 additions & 0 deletions tests/functional/n/nested_min_max.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,26 @@
# This is too complicated (for now) as there is no clear better way to write it
max(max(i for i in range(10)), 0)
max(max(max(i for i in range(10)), 0), 1)

# These examples can be improved by splicing
lst = [1, 2]
max(3, max(lst)) # [nested-min-max]
max(3, *lst)

nums = (1, 2,)
max(3, max(nums)) # [nested-min-max]
max(3, *nums)

nums = {1, 2}
max(3, max(nums)) # [nested-min-max]
max(3, *nums)

nums = {1: 2, 7: 10}
max(3, max(nums)) # [nested-min-max]
max(3, *nums)

max(3, max(nums.values())) # [nested-min-max]
max(3, *nums.values())

lst2 = [3, 7, 10]
max(3, max(nums), max(lst2)) # [nested-min-max]
6 changes: 6 additions & 0 deletions tests/functional/n/nested_min_max.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,9 @@ nested-min-max:8:0:8:25::Do not use nested call of 'min'; it's possible to do 'm
nested-min-max:11:0:11:25::Do not use nested call of 'min'; it's possible to do 'min(1, 2, 3, 4)' instead:INFERENCE
nested-min-max:12:0:12:40::Do not use nested call of 'min'; it's possible to do 'min(len([]), len([1]), len([1, 2]))' instead:INFERENCE
nested-min-max:17:0:17:27::Do not use nested call of 'orig_min'; it's possible to do 'orig_min(1, 2, 3)' instead:INFERENCE
nested-min-max:25:0:25:16::Do not use nested call of 'max'; it's possible to do 'max(3, *lst)' instead:INFERENCE
nested-min-max:29:0:29:17::Do not use nested call of 'max'; it's possible to do 'max(3, *nums)' instead:INFERENCE
nested-min-max:33:0:33:17::Do not use nested call of 'max'; it's possible to do 'max(3, *nums)' instead:INFERENCE
nested-min-max:37:0:37:17::Do not use nested call of 'max'; it's possible to do 'max(3, *nums)' instead:INFERENCE
nested-min-max:40:0:40:26::Do not use nested call of 'max'; it's possible to do 'max(3, *nums.values())' instead:INFERENCE
nested-min-max:44:0:44:28::Do not use nested call of 'max'; it's possible to do 'max(3, *nums, *lst2)' instead:INFERENCE