@@ -940,14 +940,17 @@ class IdMaker:
940940 # ParameterSet.
941941 idfn : Optional [Callable [[Any ], Optional [object ]]]
942942 # Optionally, explicit IDs for ParameterSets by index.
943- ids : Optional [Sequence [Union [ None , str ]]]
943+ ids : Optional [Sequence [Optional [ object ]]]
944944 # Optionally, the pytest config.
945945 # Used for controlling ASCII escaping, and for calling the
946946 # :hook:`pytest_make_parametrize_id` hook.
947947 config : Optional [Config ]
948948 # Optionally, the ID of the node being parametrized.
949949 # Used only for clearer error messages.
950950 nodeid : Optional [str ]
951+ # Optionally, the ID of the function being parametrized.
952+ # Used only for clearer error messages.
953+ func_name : Optional [str ]
951954
952955 def make_unique_parameterset_ids (self ) -> List [str ]:
953956 """Make a unique identifier for each ParameterSet, that may be used to
@@ -982,9 +985,7 @@ def _resolve_ids(self) -> Iterable[str]:
982985 yield parameterset .id
983986 elif self .ids and idx < len (self .ids ) and self .ids [idx ] is not None :
984987 # ID provided in the IDs list - parametrize(..., ids=[...]).
985- id = self .ids [idx ]
986- assert id is not None
987- yield _ascii_escaped_by_config (id , self .config )
988+ yield self ._idval_from_value_required (self .ids [idx ], idx )
988989 else :
989990 # ID not provided - generate it.
990991 yield "-" .join (
@@ -1053,6 +1054,25 @@ def _idval_from_value(self, val: object) -> Optional[str]:
10531054 return name
10541055 return None
10551056
1057+ def _idval_from_value_required (self , val : object , idx : int ) -> str :
1058+ """Like _idval_from_value(), but fails if the type is not supported."""
1059+ id = self ._idval_from_value (val )
1060+ if id is not None :
1061+ return id
1062+
1063+ # Fail.
1064+ if self .func_name is not None :
1065+ prefix = f"In { self .func_name } : "
1066+ elif self .nodeid is not None :
1067+ prefix = f"In { self .nodeid } : "
1068+ else :
1069+ prefix = ""
1070+ msg = (
1071+ f"{ prefix } ids contains unsupported value { saferepr (val )} (type: { type (val )!r} ) at index { idx } . "
1072+ "Supported types are: str, bytes, int, float, complex, bool, enum, regex or anything with a __name__."
1073+ )
1074+ fail (msg , pytrace = False )
1075+
10561076 @staticmethod
10571077 def _idval_from_argname (argname : str , idx : int ) -> str :
10581078 """Make an ID for a parameter in a ParameterSet from the argument name
@@ -1182,10 +1202,7 @@ def parametrize(
11821202 argvalues : Iterable [Union [ParameterSet , Sequence [object ], object ]],
11831203 indirect : Union [bool , Sequence [str ]] = False ,
11841204 ids : Optional [
1185- Union [
1186- Iterable [Union [None , str , float , int , bool ]],
1187- Callable [[Any ], Optional [object ]],
1188- ]
1205+ Union [Iterable [Optional [object ]], Callable [[Any ], Optional [object ]]]
11891206 ] = None ,
11901207 scope : "Optional[_ScopeName]" = None ,
11911208 * ,
@@ -1316,10 +1333,7 @@ def _resolve_parameter_set_ids(
13161333 self ,
13171334 argnames : Sequence [str ],
13181335 ids : Optional [
1319- Union [
1320- Iterable [Union [None , str , float , int , bool ]],
1321- Callable [[Any ], Optional [object ]],
1322- ]
1336+ Union [Iterable [Optional [object ]], Callable [[Any ], Optional [object ]]]
13231337 ],
13241338 parametersets : Sequence [ParameterSet ],
13251339 nodeid : str ,
@@ -1349,16 +1363,22 @@ def _resolve_parameter_set_ids(
13491363 idfn = None
13501364 ids_ = self ._validate_ids (ids , parametersets , self .function .__name__ )
13511365 id_maker = IdMaker (
1352- argnames , parametersets , idfn , ids_ , self .config , nodeid = nodeid
1366+ argnames ,
1367+ parametersets ,
1368+ idfn ,
1369+ ids_ ,
1370+ self .config ,
1371+ nodeid = nodeid ,
1372+ func_name = self .function .__name__ ,
13531373 )
13541374 return id_maker .make_unique_parameterset_ids ()
13551375
13561376 def _validate_ids (
13571377 self ,
1358- ids : Iterable [Union [ None , str , float , int , bool ]],
1378+ ids : Iterable [Optional [ object ]],
13591379 parametersets : Sequence [ParameterSet ],
13601380 func_name : str ,
1361- ) -> List [Union [ None , str ]]:
1381+ ) -> List [Optional [ object ]]:
13621382 try :
13631383 num_ids = len (ids ) # type: ignore[arg-type]
13641384 except TypeError :
@@ -1373,22 +1393,7 @@ def _validate_ids(
13731393 msg = "In {}: {} parameter sets specified, with different number of ids: {}"
13741394 fail (msg .format (func_name , len (parametersets ), num_ids ), pytrace = False )
13751395
1376- new_ids = []
1377- for idx , id_value in enumerate (itertools .islice (ids , num_ids )):
1378- if id_value is None or isinstance (id_value , str ):
1379- new_ids .append (id_value )
1380- elif isinstance (id_value , (float , int , bool )):
1381- new_ids .append (str (id_value ))
1382- else :
1383- msg = ( # type: ignore[unreachable]
1384- "In {}: ids must be list of string/float/int/bool, "
1385- "found: {} (type: {!r}) at index {}"
1386- )
1387- fail (
1388- msg .format (func_name , saferepr (id_value ), type (id_value ), idx ),
1389- pytrace = False ,
1390- )
1391- return new_ids
1396+ return list (itertools .islice (ids , num_ids ))
13921397
13931398 def _resolve_arg_value_types (
13941399 self ,
0 commit comments