@@ -2214,10 +2214,11 @@ def _setattr_with_converter(attr_name, value_var, has_on_setattr):
22142214 Use the cached object.setattr to set *attr_name* to *value_var*, but run
22152215 its converter first.
22162216 """
2217- return "_setattr('%s', %s(%s, self))" % (
2217+ return "_setattr('%s', %s(%s, self, attr_dict['%s'] ))" % (
22182218 attr_name ,
22192219 _INIT_CONVERTER_PAT % (attr_name ,),
22202220 value_var ,
2221+ attr_name ,
22212222 )
22222223
22232224
@@ -2240,10 +2241,11 @@ def _assign_with_converter(attr_name, value_var, has_on_setattr):
22402241 if has_on_setattr :
22412242 return _setattr_with_converter (attr_name , value_var , True )
22422243
2243- return "self.%s = %s(%s, self)" % (
2244+ return "self.%s = %s(%s, self, attr_dict['%s'] )" % (
22442245 attr_name ,
22452246 _INIT_CONVERTER_PAT % (attr_name ,),
22462247 value_var ,
2248+ attr_name ,
22472249 )
22482250
22492251
@@ -2273,10 +2275,11 @@ def fmt_setter_with_converter(attr_name, value_var, has_on_setattr):
22732275 attr_name , value_var , has_on_setattr
22742276 )
22752277
2276- return "_inst_dict['%s'] = %s(%s, self)" % (
2278+ return "_inst_dict['%s'] = %s(%s, self, attr_dict['%s'] )" % (
22772279 attr_name ,
22782280 _INIT_CONVERTER_PAT % (attr_name ,),
22792281 value_var ,
2282+ attr_name ,
22802283 )
22812284
22822285 return (
@@ -2351,7 +2354,7 @@ def _attrs_to_init_script(
23512354 maybe_self = "self" if has_factory and a .default .takes_self else ""
23522355
23532356 if a .converter and not isinstance (a .converter , Converter ):
2354- converter = Converter (a .converter , takes_self = False )
2357+ converter = Converter (a .converter )
23552358 else :
23562359 converter = a .converter
23572360
@@ -2989,44 +2992,61 @@ class Converter:
29892992 """
29902993 Stores a converter callable.
29912994
2992- Allows for the wrapped converter to take additional arguments.
2995+ Allows for the wrapped converter to take additional arguments. The
2996+ arguments are passed in the order they are documented.
29932997
29942998 :param Callable converter: A callable that converts a value.
29952999 :param bool takes_self: Pass the partially initialized instance that is
2996- being initialized as a positional argument. (default: `True`)
3000+ being initialized as a positional argument. (default: `False`)
3001+ :param bool takes_field: Pass the field definition (an `Attribute`) into
3002+ the converter as a positional argument. (default: `False`)
29973003
29983004 .. versionadded:: 24.1.0
29993005 """
30003006
3001- __slots__ = ("converter" , "takes_self" , "_first_param_type" , "__call__" )
3007+ __slots__ = (
3008+ "converter" ,
3009+ "takes_self" ,
3010+ "takes_field" ,
3011+ "_first_param_type" ,
3012+ "__call__" ,
3013+ )
30023014
3003- def __init__ (self , converter , * , takes_self = True ):
3015+ def __init__ (self , converter , * , takes_self = False , takes_field = False ):
30043016 self .converter = converter
30053017 self .takes_self = takes_self
3006-
3007- ann = _AnnotationExtractor (converter )
3008-
3009- self ._first_param_type = ann .get_first_param_type ()
3018+ self .takes_field = takes_field
30103019
30113020 # Defining __call__ as a regular method leads to __annotations__ being
30123021 # overwritten at a class level.
3013- def __call__ (value , inst ):
3014- if not self .takes_self :
3015- return self .converter (value )
3016-
3017- return self .converter (value , inst )
3022+ def __call__ (value , inst , field ):
3023+ return self .converter (
3024+ * {
3025+ (False , False ): (value ,),
3026+ (True , False ): (value , inst ),
3027+ (False , True ): (value , field ),
3028+ (True , True ): (value , inst , field ),
3029+ }[(takes_self , takes_field )]
3030+ )
30183031
3032+ ann = _AnnotationExtractor (converter )
30193033 __call__ .__annotations__ .update (
30203034 ann .get_annotations_for_converter_callable ()
30213035 )
30223036 self .__call__ = __call__
30233037
3038+ self ._first_param_type = ann .get_first_param_type ()
3039+
30243040 def __getstate__ (self ):
30253041 """
30263042 Return a dict containing only converter and takes_self -- the rest gets
30273043 computed when loading.
30283044 """
3029- return {"converter" : self .converter , "takes_self" : self .takes_self }
3045+ return {
3046+ "converter" : self .converter ,
3047+ "takes_self" : self .takes_self ,
3048+ "takes_field" : self .takes_field ,
3049+ }
30303050
30313051 def __setstate__ (self , state ):
30323052 """
@@ -3048,7 +3068,7 @@ def __setstate__(self, state):
30483068 init = True ,
30493069 inherited = False ,
30503070 )
3051- for name in ("converter" , "takes_self" )
3071+ for name in ("converter" , "takes_self" , "takes_field" )
30523072]
30533073
30543074Converter = _add_hash (
@@ -3188,10 +3208,10 @@ def pipe(*converters):
31883208 .. versionadded:: 20.1.0
31893209 """
31903210
3191- def pipe_converter (val , inst ):
3211+ def pipe_converter (val , inst , field ):
31923212 for converter in converters :
31933213 if isinstance (converter , Converter ):
3194- val = converter (val , inst )
3214+ val = converter (val , inst , field )
31953215 else :
31963216 val = converter (val )
31973217
@@ -3212,4 +3232,4 @@ def pipe_converter(val, inst):
32123232 if rt :
32133233 pipe_converter .__annotations__ ["return" ] = rt
32143234
3215- return Converter (pipe_converter , takes_self = True )
3235+ return Converter (pipe_converter , takes_self = True , takes_field = True )
0 commit comments