@@ -1123,48 +1123,78 @@ def no_variant_matches_arguments(
11231123 unexpected_kwargs .append ((arg_name , arg_types [i ]))
11241124
11251125 if unexpected_kwargs :
1126+ all_kwargs_confident = True
1127+ kwargs_with_suggestions : list [tuple [str , list [str ]]] = []
1128+ kwargs_without_suggestions : list [str ] = []
1129+
1130+ # Find suggestions for each unexpected kwarg, prioritizing type-matching args
11261131 for kwarg_name , kwarg_type in unexpected_kwargs :
11271132 matching_type_args : list [str ] = []
11281133 not_matching_type_args : list [str ] = []
1129- matching_variant : CallableType | None = None
1134+ has_matching_variant = False
11301135
11311136 for item in overload .items :
1132- has_type_match = False
1137+ item_has_type_match = False
11331138 for i , formal_type in enumerate (item .arg_types ):
11341139 formal_name = item .arg_names [i ]
11351140 if formal_name is not None and item .arg_kinds [i ] != ARG_STAR :
11361141 if is_subtype (kwarg_type , formal_type ):
11371142 if formal_name not in matching_type_args :
11381143 matching_type_args .append (formal_name )
1139- has_type_match = True
1140- else :
1141- if formal_name not in not_matching_type_args :
1142- not_matching_type_args .append (formal_name )
1143- if has_type_match and matching_variant is None :
1144- matching_variant = item
1144+ item_has_type_match = True
1145+ elif formal_name not in not_matching_type_args :
1146+ not_matching_type_args .append (formal_name )
1147+ if item_has_type_match :
1148+ has_matching_variant = True
11451149
11461150 matches = best_matches (kwarg_name , matching_type_args , n = 3 )
11471151 if not matches :
11481152 matches = best_matches (kwarg_name , not_matching_type_args , n = 3 )
11491153
1150- msg = f'Unexpected keyword argument "{ kwarg_name } "' + for_func
1151-
11521154 if matches :
1153- msg += f"; did you mean { pretty_seq (matches , 'or' )} ?"
1154- self .fail (msg , context , code = code )
1155+ kwargs_with_suggestions .append ((kwarg_name , matches ))
1156+ else :
1157+ kwargs_without_suggestions .append (kwarg_name )
11551158
1156- if matching_variant is None :
1157- self .note (
1158- f"Possible overload variant{ plural_s (len (overload .items ))} :" ,
1159+ if not has_matching_variant :
1160+ all_kwargs_confident = False
1161+
1162+ for kwarg_name , matches in kwargs_with_suggestions :
1163+ self .fail (
1164+ f'Unexpected keyword argument "{ kwarg_name } "'
1165+ f"{ for_func } ; did you mean { pretty_seq (matches , 'or' )} ?" ,
1166+ context ,
1167+ code = code ,
1168+ )
1169+
1170+ if kwargs_without_suggestions :
1171+ if len (kwargs_without_suggestions ) == 1 :
1172+ self .fail (
1173+ f'Unexpected keyword argument "{ kwargs_without_suggestions [0 ]} "{ for_func } ' ,
1174+ context ,
1175+ code = code ,
1176+ )
1177+ else :
1178+ quoted_names = ", " .join (f'"{ n } "' for n in kwargs_without_suggestions )
1179+ self .fail (
1180+ f"Unexpected keyword arguments { quoted_names } { for_func } " ,
11591181 context ,
11601182 code = code ,
11611183 )
1162- for item in overload .items :
1163- self .note (
1164- pretty_callable (item , self .options ), context , offset = 4 , code = code
1165- )
11661184
1167- return
1185+ if not all_kwargs_confident :
1186+ self .note (
1187+ f"Possible overload variant{ plural_s (len (overload .items ))} :" ,
1188+ context ,
1189+ code = code ,
1190+ )
1191+ for item in overload .items :
1192+ self .note (
1193+ pretty_callable (item , self .options ), context , offset = 4 , code = code
1194+ )
1195+
1196+ if all_kwargs_confident and len (unexpected_kwargs ) == len (arg_types ):
1197+ return
11681198
11691199 arg_types_str = ", " .join (format_type (arg , self .options ) for arg in arg_types )
11701200 num_args = len (arg_types )
0 commit comments