@@ -871,16 +871,32 @@ def visit_if(self, node: nodes.If) -> None:
871
871
self ._check_consider_get (node )
872
872
self ._check_consider_using_min_max_builtin (node )
873
873
874
- # pylint: disable = too-many-branches
875
874
def _check_consider_using_min_max_builtin (self , node : nodes .If ) -> None :
876
875
"""Check if the given if node can be refactored as a min/max python builtin."""
876
+ # This function is written expecting a test condition of form:
877
+ # if a < b: # [consider-using-max-builtin]
878
+ # a = b
879
+ # if a > b: # [consider-using-min-builtin]
880
+ # a = b
877
881
if self ._is_actual_elif (node ) or node .orelse :
878
882
# Not interested in if statements with multiple branches.
879
883
return
880
884
881
885
if len (node .body ) != 1 :
882
886
return
883
887
888
+ def get_node_name (node : nodes .NodeNG ) -> str :
889
+ """Obtain simplest representation of a node as a string."""
890
+ if isinstance (node , nodes .Name ):
891
+ return node .name # type: ignore[no-any-return]
892
+ if isinstance (node , nodes .Attribute ):
893
+ return node .attrname # type: ignore[no-any-return]
894
+ if isinstance (node , nodes .Const ):
895
+ return str (node .value )
896
+ # this is a catch-all for nodes that are not of type Name or Attribute
897
+ # extremely helpful for Call or BinOp
898
+ return node .as_string () # type: ignore[no-any-return]
899
+
884
900
body = node .body [0 ]
885
901
# Check if condition can be reduced.
886
902
if not hasattr (body , "targets" ) or len (body .targets ) != 1 :
@@ -894,14 +910,9 @@ def _check_consider_using_min_max_builtin(self, node: nodes.If) -> None:
894
910
and isinstance (body , nodes .Assign )
895
911
):
896
912
return
897
-
898
- # Check that the assignation is on the same variable.
899
- if hasattr (node .test .left , "name" ):
900
- left_operand = node .test .left .name
901
- elif hasattr (node .test .left , "attrname" ):
902
- left_operand = node .test .left .attrname
903
- else :
904
- return
913
+ # Assign body line has one requirement and that is the assign target
914
+ # is of type name or attribute. Attribute referring to NamedTuple.x perse.
915
+ # So we have to check that target is of these types
905
916
906
917
if hasattr (target , "name" ):
907
918
target_assignation = target .name
@@ -910,30 +921,24 @@ def _check_consider_using_min_max_builtin(self, node: nodes.If) -> None:
910
921
else :
911
922
return
912
923
913
- if not (left_operand == target_assignation ):
914
- return
915
-
916
924
if len (node .test .ops ) > 1 :
917
925
return
918
-
919
- if not isinstance (body .value , (nodes .Name , nodes .Const )):
920
- return
921
-
922
926
operator , right_statement = node .test .ops [0 ]
923
- if isinstance (body .value , nodes .Name ):
924
- body_value = body .value .name
925
- else :
926
- body_value = body .value .value
927
927
928
- if isinstance (right_statement , nodes .Name ):
929
- right_statement_value = right_statement .name
930
- elif isinstance (right_statement , nodes .Const ):
931
- right_statement_value = right_statement .value
928
+ body_value = get_node_name (body .value )
929
+ left_operand = get_node_name (node .test .left )
930
+ right_statement_value = get_node_name (right_statement )
931
+
932
+ if left_operand == target_assignation :
933
+ # statement is in expected form
934
+ pass
935
+ elif right_statement_value == target_assignation :
936
+ # statement is in reverse form
937
+ operator = utils .get_inverse_comparator (operator )
932
938
else :
933
939
return
934
940
935
- # Verify the right part of the statement is the same.
936
- if right_statement_value != body_value :
941
+ if body_value not in (right_statement_value , left_operand ):
937
942
return
938
943
939
944
if operator in {"<" , "<=" }:
0 commit comments