@@ -234,6 +234,7 @@ def optional(validator):
234234@attrs (repr = False , slots = True , hash = True )
235235class _InValidator :
236236 options = attrib ()
237+ _original_options = attrib (hash = False )
237238
238239 def __call__ (self , inst , attr , value ):
239240 try :
@@ -242,23 +243,28 @@ def __call__(self, inst, attr, value):
242243 in_options = False
243244
244245 if not in_options :
245- msg = f"'{ attr .name } ' must be in { self .options !r} (got { value !r} )"
246+ msg = f"'{ attr .name } ' must be in { self ._original_options !r} (got { value !r} )"
246247 raise ValueError (
247248 msg ,
248249 attr ,
249- self .options ,
250+ self ._original_options ,
250251 value ,
251252 )
252253
253254 def __repr__ (self ):
254- return f"<in_ validator with options { self .options !r} >"
255+ return f"<in_ validator with options { self ._original_options !r} >"
255256
256257
257258def in_ (options ):
258259 """
259260 A validator that raises a `ValueError` if the initializer is called with a
260- value that does not belong in the options provided. The check is performed
261- using ``value in options``, so *options* has to support that operation.
261+ value that does not belong in the *options* provided.
262+
263+ The check is performed using ``value in options``, so *options* has to
264+ support that operation.
265+
266+ To keep the validator hashable, dicts, lists, and sets are transparently
267+ transformed into a `tuple`.
262268
263269 Args:
264270 options: Allowed options.
@@ -273,8 +279,15 @@ def in_(options):
273279 The ValueError was incomplete until now and only contained the human
274280 readable error message. Now it contains all the information that has
275281 been promised since 17.1.0.
282+ .. versionchanged:: 24.1.0
283+ *options* that are a list, dict, or a set are now transformed into a
284+ tuple to keep the validator hashable.
276285 """
277- return _InValidator (options )
286+ repr_options = options
287+ if isinstance (options , (list , dict , set )):
288+ options = tuple (options )
289+
290+ return _InValidator (options , repr_options )
278291
279292
280293@attrs (repr = False , slots = False , hash = True )
0 commit comments