@@ -871,16 +871,32 @@ def visit_if(self, node: nodes.If) -> None:
871871 self ._check_consider_get (node )
872872 self ._check_consider_using_min_max_builtin (node )
873873
874- # pylint: disable = too-many-branches
875874 def _check_consider_using_min_max_builtin (self , node : nodes .If ) -> None :
876875 """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
877881 if self ._is_actual_elif (node ) or node .orelse :
878882 # Not interested in if statements with multiple branches.
879883 return
880884
881885 if len (node .body ) != 1 :
882886 return
883887
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+
884900 body = node .body [0 ]
885901 # Check if condition can be reduced.
886902 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:
894910 and isinstance (body , nodes .Assign )
895911 ):
896912 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
905916
906917 if hasattr (target , "name" ):
907918 target_assignation = target .name
@@ -910,30 +921,24 @@ def _check_consider_using_min_max_builtin(self, node: nodes.If) -> None:
910921 else :
911922 return
912923
913- if not (left_operand == target_assignation ):
914- return
915-
916924 if len (node .test .ops ) > 1 :
917925 return
918-
919- if not isinstance (body .value , (nodes .Name , nodes .Const )):
920- return
921-
922926 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
927927
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 )
932938 else :
933939 return
934940
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 ):
937942 return
938943
939944 if operator in {"<" , "<=" }:
0 commit comments