@@ -1117,48 +1117,78 @@ def no_variant_matches_arguments(
11171117 unexpected_kwargs .append ((arg_name , arg_types [i ]))
11181118
11191119 if unexpected_kwargs :
1120+ all_kwargs_confident = True
1121+ kwargs_with_suggestions : list [tuple [str , list [str ]]] = []
1122+ kwargs_without_suggestions : list [str ] = []
1123+
1124+ # Find suggestions for each unexpected kwarg, prioritizing type-matching args
11201125 for kwarg_name , kwarg_type in unexpected_kwargs :
11211126 matching_type_args : list [str ] = []
11221127 not_matching_type_args : list [str ] = []
1123- matching_variant : CallableType | None = None
1128+ has_matching_variant = False
11241129
11251130 for item in overload .items :
1126- has_type_match = False
1131+ item_has_type_match = False
11271132 for i , formal_type in enumerate (item .arg_types ):
11281133 formal_name = item .arg_names [i ]
11291134 if formal_name is not None and item .arg_kinds [i ] != ARG_STAR :
11301135 if is_subtype (kwarg_type , formal_type ):
11311136 if formal_name not in matching_type_args :
11321137 matching_type_args .append (formal_name )
1133- has_type_match = True
1134- else :
1135- if formal_name not in not_matching_type_args :
1136- not_matching_type_args .append (formal_name )
1137- if has_type_match and matching_variant is None :
1138- matching_variant = item
1138+ item_has_type_match = True
1139+ elif formal_name not in not_matching_type_args :
1140+ not_matching_type_args .append (formal_name )
1141+ if item_has_type_match :
1142+ has_matching_variant = True
11391143
11401144 matches = best_matches (kwarg_name , matching_type_args , n = 3 )
11411145 if not matches :
11421146 matches = best_matches (kwarg_name , not_matching_type_args , n = 3 )
11431147
1144- msg = f'Unexpected keyword argument "{ kwarg_name } "' + for_func
1145-
11461148 if matches :
1147- msg += f"; did you mean { pretty_seq (matches , 'or' )} ?"
1148- self .fail (msg , context , code = code )
1149+ kwargs_with_suggestions .append ((kwarg_name , matches ))
1150+ else :
1151+ kwargs_without_suggestions .append (kwarg_name )
11491152
1150- if matching_variant is None :
1151- self .note (
1152- f"Possible overload variant{ plural_s (len (overload .items ))} :" ,
1153+ if not has_matching_variant :
1154+ all_kwargs_confident = False
1155+
1156+ for kwarg_name , matches in kwargs_with_suggestions :
1157+ self .fail (
1158+ f'Unexpected keyword argument "{ kwarg_name } "'
1159+ f"{ for_func } ; did you mean { pretty_seq (matches , 'or' )} ?" ,
1160+ context ,
1161+ code = code ,
1162+ )
1163+
1164+ if kwargs_without_suggestions :
1165+ if len (kwargs_without_suggestions ) == 1 :
1166+ self .fail (
1167+ f'Unexpected keyword argument "{ kwargs_without_suggestions [0 ]} "{ for_func } ' ,
1168+ context ,
1169+ code = code ,
1170+ )
1171+ else :
1172+ quoted_names = ", " .join (f'"{ n } "' for n in kwargs_without_suggestions )
1173+ self .fail (
1174+ f"Unexpected keyword arguments { quoted_names } { for_func } " ,
11531175 context ,
11541176 code = code ,
11551177 )
1156- for item in overload .items :
1157- self .note (
1158- pretty_callable (item , self .options ), context , offset = 4 , code = code
1159- )
11601178
1161- return
1179+ if not all_kwargs_confident :
1180+ self .note (
1181+ f"Possible overload variant{ plural_s (len (overload .items ))} :" ,
1182+ context ,
1183+ code = code ,
1184+ )
1185+ for item in overload .items :
1186+ self .note (
1187+ pretty_callable (item , self .options ), context , offset = 4 , code = code
1188+ )
1189+
1190+ if all_kwargs_confident and len (unexpected_kwargs ) == len (arg_types ):
1191+ return
11621192
11631193 arg_types_str = ", " .join (format_type (arg , self .options ) for arg in arg_types )
11641194 num_args = len (arg_types )
0 commit comments