Skip to content

Commit dad4124

Browse files
Use match statement in checkers (4) (#10531)
Co-authored-by: Pierre Sassoulas <[email protected]>
1 parent 95cf36e commit dad4124

16 files changed

+215
-312
lines changed

pylint/checkers/base/basic_checker.py

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -537,12 +537,11 @@ def visit_lambda(self, node: nodes.Lambda) -> None:
537537
# The body of the lambda must be a function call expression
538538
# for the lambda to be unnecessary.
539539
return
540-
if isinstance(node.body.func, nodes.Attribute) and isinstance(
541-
node.body.func.expr, nodes.Call
542-
):
543-
# Chained call, the intermediate call might
544-
# return something else (but we don't check that, yet).
545-
return
540+
match call.func:
541+
case nodes.Attribute(expr=nodes.Call()):
542+
# Chained call, the intermediate call might
543+
# return something else (but we don't check that, yet).
544+
return
546545

547546
ordinary_args = list(node.args.args)
548547
new_call_args = list(self._filter_vararg(node, call.args))
@@ -683,14 +682,9 @@ def _check_misplaced_format_function(self, call_node: nodes.Call) -> None:
683682
if not expr:
684683
# we are doubtful on inferred type of node, so here just check if format
685684
# was called on print()
686-
call_expr = call_node.func.expr
687-
if not isinstance(call_expr, nodes.Call):
688-
return
689-
if (
690-
isinstance(call_expr.func, nodes.Name)
691-
and call_expr.func.name == "print"
692-
):
693-
self.add_message("misplaced-format-function", node=call_node)
685+
match call_node.func.expr:
686+
case nodes.Call(func=nodes.Name(name="print")):
687+
self.add_message("misplaced-format-function", node=call_node)
694688

695689
@utils.only_required_for_messages(
696690
"eval-used",

pylint/checkers/base/comparison_checker.py

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -185,36 +185,37 @@ def _check_literal_comparison(
185185
self, literal: nodes.NodeNG, node: nodes.Compare
186186
) -> None:
187187
"""Check if we compare to a literal, which is usually what we do not want to do."""
188-
is_other_literal = isinstance(literal, (nodes.List, nodes.Dict, nodes.Set))
189-
is_const = False
190-
if isinstance(literal, nodes.Const):
191-
if isinstance(literal.value, bool) or literal.value is None:
188+
match literal:
189+
case nodes.Const(value=bool() | None):
192190
# Not interested in these values.
193191
return
194-
is_const = isinstance(literal.value, (bytes, str, int, float))
195-
196-
if is_const or is_other_literal:
197-
incorrect_node_str = node.as_string()
198-
if "is not" in incorrect_node_str:
199-
equal_or_not_equal = "!="
200-
is_or_is_not = "is not"
201-
else:
202-
equal_or_not_equal = "=="
203-
is_or_is_not = "is"
204-
fixed_node_str = incorrect_node_str.replace(
205-
is_or_is_not, equal_or_not_equal
206-
)
207-
self.add_message(
208-
"literal-comparison",
209-
args=(
210-
incorrect_node_str,
211-
equal_or_not_equal,
212-
is_or_is_not,
213-
fixed_node_str,
214-
),
215-
node=node,
216-
confidence=HIGH,
217-
)
192+
case nodes.Const(value=bytes() | str() | int() | float()):
193+
pass
194+
case nodes.List() | nodes.Dict() | nodes.Set():
195+
# Inline list, dict and set nodes
196+
pass
197+
case _:
198+
return
199+
200+
incorrect_node_str = node.as_string()
201+
if "is not" in incorrect_node_str:
202+
equal_or_not_equal = "!="
203+
is_or_is_not = "is not"
204+
else:
205+
equal_or_not_equal = "=="
206+
is_or_is_not = "is"
207+
fixed_node_str = incorrect_node_str.replace(is_or_is_not, equal_or_not_equal)
208+
self.add_message(
209+
"literal-comparison",
210+
args=(
211+
incorrect_node_str,
212+
equal_or_not_equal,
213+
is_or_is_not,
214+
fixed_node_str,
215+
),
216+
node=node,
217+
confidence=HIGH,
218+
)
218219

219220
def _check_logical_tautology(self, node: nodes.Compare) -> None:
220221
"""Check if identifier is compared against itself.

pylint/checkers/classes/class_checker.py

Lines changed: 46 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -914,17 +914,16 @@ def _check_declare_non_slot(self, node: nodes.ClassDef) -> None:
914914
# Every class in bases has __slots__, our __slots__ is non-empty and there is no __dict__
915915

916916
for child in node.body:
917-
if isinstance(child, nodes.AnnAssign):
918-
if child.value is not None:
919-
continue
920-
if isinstance(child.target, nodes.AssignName):
921-
if child.target.name not in slot_names:
922-
self.add_message(
923-
"declare-non-slot",
924-
args=child.target.name,
925-
node=child.target,
926-
confidence=INFERENCE,
927-
)
917+
match child:
918+
case nodes.AnnAssign(
919+
target=nodes.AssignName(name=name), value=None
920+
) if (name not in slot_names):
921+
self.add_message(
922+
"declare-non-slot",
923+
args=child.target.name,
924+
node=child.target,
925+
confidence=INFERENCE,
926+
)
928927

929928
def _check_consistent_mro(self, node: nodes.ClassDef) -> None:
930929
"""Detect that a class has a consistent mro or duplicate bases."""
@@ -936,31 +935,30 @@ def _check_consistent_mro(self, node: nodes.ClassDef) -> None:
936935
self.add_message("duplicate-bases", args=node.name, node=node)
937936

938937
def _check_enum_base(self, node: nodes.ClassDef, ancestor: nodes.ClassDef) -> None:
939-
members = ancestor.getattr("__members__")
940-
if members and isinstance(members[0], nodes.Dict) and members[0].items:
941-
for _, name_node in members[0].items:
942-
# Exempt type annotations without value assignments
943-
if all(
944-
isinstance(item.parent, nodes.AnnAssign)
945-
and item.parent.value is None
946-
for item in ancestor.getattr(name_node.name)
947-
):
948-
continue
949-
self.add_message(
950-
"invalid-enum-extension",
951-
args=ancestor.name,
952-
node=node,
953-
confidence=INFERENCE,
954-
)
955-
break
938+
match ancestor.getattr("__members__"):
939+
case [nodes.Dict(items=items), *_] if items:
940+
for _, name_node in items:
941+
# Exempt type annotations without value assignments
942+
if all(
943+
isinstance(item.parent, nodes.AnnAssign)
944+
and item.parent.value is None
945+
for item in ancestor.getattr(name_node.name)
946+
):
947+
continue
948+
self.add_message(
949+
"invalid-enum-extension",
950+
args=ancestor.name,
951+
node=node,
952+
confidence=INFERENCE,
953+
)
954+
break
956955

957956
if ancestor.is_subtype_of("enum.IntFlag"):
958957
# Collect integer flag assignments present on the class
959958
assignments = defaultdict(list)
960959
for assign_name in node.nodes_of_class(nodes.AssignName):
961-
if isinstance(assign_name.parent, nodes.Assign):
962-
value = getattr(assign_name.parent.value, "value", None)
963-
if isinstance(value, int):
960+
match assign_name.parent:
961+
case nodes.Assign(value=object(value=int() as value)):
964962
assignments[value].append(assign_name)
965963

966964
# For each bit position, collect all the flags that set the bit
@@ -1336,11 +1334,9 @@ def visit_functiondef(self, node: nodes.FunctionDef) -> None:
13361334
try:
13371335
overridden = klass.instance_attr(node.name)[0]
13381336
overridden_frame = overridden.frame()
1339-
if (
1340-
isinstance(overridden_frame, nodes.FunctionDef)
1341-
and overridden_frame.type == "method"
1342-
):
1343-
overridden_frame = overridden_frame.parent.frame()
1337+
match overridden_frame:
1338+
case nodes.FunctionDef(type="method"):
1339+
overridden_frame = overridden_frame.parent.frame()
13441340
if not (
13451341
isinstance(overridden_frame, nodes.ClassDef)
13461342
and klass.is_subtype_of(overridden_frame.qname())
@@ -1740,12 +1736,10 @@ def _check_invalid_class_object(self, node: nodes.AssignAttr) -> None:
17401736
inferred = safe_infer(node.parent.parent.value.elts[class_index])
17411737
else:
17421738
inferred = safe_infer(node.parent.value)
1743-
if (
1744-
isinstance(inferred, (nodes.ClassDef, util.UninferableBase))
1745-
or inferred is None
1746-
):
1747-
# If is uninferable, we allow it to prevent false positives
1748-
return
1739+
match inferred:
1740+
case nodes.ClassDef() | util.UninferableBase() | None:
1741+
# If uninferable, we allow it to prevent false positives
1742+
return
17491743
self.add_message(
17501744
"invalid-class-object",
17511745
node=node,
@@ -1926,12 +1920,9 @@ def _check_protected_attribute_access(
19261920
# through the class object or through super
19271921

19281922
# If the expression begins with a call to super, that's ok.
1929-
if (
1930-
isinstance(node.expr, nodes.Call)
1931-
and isinstance(node.expr.func, nodes.Name)
1932-
and node.expr.func.name == "super"
1933-
):
1934-
return
1923+
match node.expr:
1924+
case nodes.Call(func=nodes.Name(name="super")):
1925+
return
19351926

19361927
# If the expression begins with a call to type(self), that's ok.
19371928
if self._is_type_self_call(node.expr):
@@ -1960,14 +1951,10 @@ def _check_protected_attribute_access(
19601951
# class A:
19611952
# b = property(lambda: self._b)
19621953

1963-
stmt = node.parent.statement()
1964-
if (
1965-
isinstance(stmt, nodes.Assign)
1966-
and len(stmt.targets) == 1
1967-
and isinstance(stmt.targets[0], nodes.AssignName)
1968-
):
1969-
name = stmt.targets[0].name
1970-
if _is_attribute_property(name, klass):
1954+
match node.parent.statement():
1955+
case nodes.Assign(
1956+
targets=[nodes.AssignName(name=name)]
1957+
) if _is_attribute_property(name, klass):
19711958
return
19721959

19731960
if (
@@ -2241,12 +2228,9 @@ def _check_init(self, node: nodes.FunctionDef, klass_node: nodes.ClassDef) -> No
22412228
if not isinstance(expr, nodes.Attribute) or expr.attrname != "__init__":
22422229
continue
22432230
# skip the test if using super
2244-
if (
2245-
isinstance(expr.expr, nodes.Call)
2246-
and isinstance(expr.expr.func, nodes.Name)
2247-
and expr.expr.func.name == "super"
2248-
):
2249-
return
2231+
match expr.expr:
2232+
case nodes.Call(func=nodes.Name(name="super")):
2233+
return
22502234
# pylint: disable = too-many-try-statements
22512235
try:
22522236
for klass in expr.expr.infer():

pylint/checkers/deprecated.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -290,9 +290,6 @@ def check_deprecated_class(
290290

291291
def check_deprecated_class_in_call(self, node: nodes.Call) -> None:
292292
"""Checks if call the deprecated class."""
293-
if isinstance(node.func, nodes.Attribute) and isinstance(
294-
node.func.expr, nodes.Name
295-
):
296-
mod_name = node.func.expr.name
297-
class_name = node.func.attrname
298-
self.check_deprecated_class(node, mod_name, (class_name,))
293+
match node.func:
294+
case nodes.Attribute(expr=nodes.Name(name=mod_name), attrname=class_name):
295+
self.check_deprecated_class(node, mod_name, (class_name,))

pylint/checkers/exceptions.py

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -229,16 +229,12 @@ def visit_name(self, node: nodes.Name) -> None:
229229
def visit_call(self, node: nodes.Call) -> None:
230230
if isinstance(node.func, nodes.Name):
231231
self.visit_name(node.func)
232-
if (
233-
len(node.args) > 1
234-
and isinstance(node.args[0], nodes.Const)
235-
and isinstance(node.args[0].value, str)
236-
):
237-
msg = node.args[0].value
238-
if "%" in msg or ("{" in msg and "}" in msg):
239-
self._checker.add_message(
240-
"raising-format-tuple", node=self._node, confidence=HIGH
241-
)
232+
match node.args:
233+
case [nodes.Const(value=str() as msg), _, *_]:
234+
if "%" in msg or ("{" in msg and "}" in msg):
235+
self._checker.add_message(
236+
"raising-format-tuple", node=self._node, confidence=HIGH
237+
)
242238

243239

244240
class ExceptionRaiseLeafVisitor(BaseVisitor):

pylint/checkers/lambda_expressions.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -70,14 +70,15 @@ def visit_assign(self, node: nodes.Assign) -> None:
7070
)
7171

7272
def visit_namedexpr(self, node: nodes.NamedExpr) -> None:
73-
if isinstance(node.target, nodes.AssignName) and isinstance(
74-
node.value, nodes.Lambda
75-
):
76-
self.add_message(
77-
"unnecessary-lambda-assignment",
78-
node=node.value,
79-
confidence=HIGH,
80-
)
73+
match node:
74+
case nodes.NamedExpr(
75+
target=nodes.AssignName(), value=nodes.Lambda() as value
76+
):
77+
self.add_message(
78+
"unnecessary-lambda-assignment",
79+
node=value,
80+
confidence=HIGH,
81+
)
8182

8283
def visit_call(self, node: nodes.Call) -> None:
8384
"""Check if lambda expression is called directly."""

pylint/checkers/newstyle.py

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -74,26 +74,23 @@ def visit_functiondef(self, node: nodes.FunctionDef) -> None:
7474

7575
# calling super(type(self), self) can lead to recursion loop
7676
# in derived classes
77-
arg0 = call.args[0]
78-
if (
79-
isinstance(arg0, nodes.Call)
80-
and isinstance(arg0.func, nodes.Name)
81-
and arg0.func.name == "type"
82-
):
83-
self.add_message("bad-super-call", node=call, args=("type",))
84-
continue
77+
match call.args[0]:
78+
case nodes.Call(func=nodes.Name(name="type")):
79+
self.add_message("bad-super-call", node=call, args=("type",))
80+
continue
8581

8682
# calling super(self.__class__, self) can lead to recursion loop
8783
# in derived classes
88-
if (
89-
len(call.args) >= 2
90-
and isinstance(call.args[1], nodes.Name)
91-
and call.args[1].name == "self"
92-
and isinstance(arg0, nodes.Attribute)
93-
and arg0.attrname == "__class__"
94-
):
95-
self.add_message("bad-super-call", node=call, args=("self.__class__",))
96-
continue
84+
match call.args:
85+
case [
86+
nodes.Attribute(attrname="__class__"),
87+
nodes.Name(name="self"),
88+
*_,
89+
]:
90+
self.add_message(
91+
"bad-super-call", node=call, args=("self.__class__",)
92+
)
93+
continue
9794

9895
try:
9996
supcls = call.args and next(call.args[0].infer(), None)

0 commit comments

Comments
 (0)