@@ -283,11 +283,12 @@ class Field:
283283 'compare' ,
284284 'metadata' ,
285285 'kw_only' ,
286+ 'doc' ,
286287 '_field_type' , # Private: not to be used by user code.
287288 )
288289
289290 def __init__ (self , default , default_factory , init , repr , hash , compare ,
290- metadata , kw_only ):
291+ metadata , kw_only , doc ):
291292 self .name = None
292293 self .type = None
293294 self .default = default
@@ -300,6 +301,7 @@ def __init__(self, default, default_factory, init, repr, hash, compare,
300301 if metadata is None else
301302 types .MappingProxyType (metadata ))
302303 self .kw_only = kw_only
304+ self .doc = doc
303305 self ._field_type = None
304306
305307 @recursive_repr ()
@@ -315,6 +317,7 @@ def __repr__(self):
315317 f'compare={ self .compare !r} ,'
316318 f'metadata={ self .metadata !r} ,'
317319 f'kw_only={ self .kw_only !r} ,'
320+ f'doc={ self .doc !r} ,'
318321 f'_field_type={ self ._field_type } '
319322 ')' )
320323
@@ -382,7 +385,7 @@ def __repr__(self):
382385# so that a type checker can be told (via overloads) that this is a
383386# function whose type depends on its parameters.
384387def field (* , default = MISSING , default_factory = MISSING , init = True , repr = True ,
385- hash = None , compare = True , metadata = None , kw_only = MISSING ):
388+ hash = None , compare = True , metadata = None , kw_only = MISSING , doc = None ):
386389 """Return an object to identify dataclass fields.
387390
388391 default is the default value of the field. default_factory is a
@@ -394,15 +397,15 @@ def field(*, default=MISSING, default_factory=MISSING, init=True, repr=True,
394397 comparison functions. metadata, if specified, must be a mapping
395398 which is stored but not otherwise examined by dataclass. If kw_only
396399 is true, the field will become a keyword-only parameter to
397- __init__().
400+ __init__(). doc is an optional docstring for this field.
398401
399402 It is an error to specify both default and default_factory.
400403 """
401404
402405 if default is not MISSING and default_factory is not MISSING :
403406 raise ValueError ('cannot specify both default and default_factory' )
404407 return Field (default , default_factory , init , repr , hash , compare ,
405- metadata , kw_only )
408+ metadata , kw_only , doc )
406409
407410
408411def _fields_in_init_order (fields ):
@@ -1174,7 +1177,7 @@ def _process_class(cls, init, repr, eq, order, unsafe_hash, frozen,
11741177 if weakref_slot and not slots :
11751178 raise TypeError ('weakref_slot is True but slots is False' )
11761179 if slots :
1177- cls = _add_slots (cls , frozen , weakref_slot )
1180+ cls = _add_slots (cls , frozen , weakref_slot , fields )
11781181
11791182 abc .update_abstractmethods (cls )
11801183
@@ -1239,7 +1242,32 @@ def _update_func_cell_for__class__(f, oldcls, newcls):
12391242 return False
12401243
12411244
1242- def _add_slots (cls , is_frozen , weakref_slot ):
1245+ def _create_slots (defined_fields , inherited_slots , field_names , weakref_slot ):
1246+ # The slots for our class. Remove slots from our base classes. Add
1247+ # '__weakref__' if weakref_slot was given, unless it is already present.
1248+ seen_docs = False
1249+ slots = {}
1250+ for slot in itertools .filterfalse (
1251+ inherited_slots .__contains__ ,
1252+ itertools .chain (
1253+ # gh-93521: '__weakref__' also needs to be filtered out if
1254+ # already present in inherited_slots
1255+ field_names , ('__weakref__' ,) if weakref_slot else ()
1256+ )
1257+ ):
1258+ doc = getattr (defined_fields .get (slot ), 'doc' , None )
1259+ if doc is not None :
1260+ seen_docs = True
1261+ slots .update ({slot : doc })
1262+
1263+ # We only return dict if there's at least one doc member,
1264+ # otherwise we return tuple, which is the old default format.
1265+ if seen_docs :
1266+ return slots
1267+ return tuple (slots )
1268+
1269+
1270+ def _add_slots (cls , is_frozen , weakref_slot , defined_fields ):
12431271 # Need to create a new class, since we can't set __slots__ after a
12441272 # class has been created, and the @dataclass decorator is called
12451273 # after the class is created.
@@ -1255,17 +1283,9 @@ def _add_slots(cls, is_frozen, weakref_slot):
12551283 inherited_slots = set (
12561284 itertools .chain .from_iterable (map (_get_slots , cls .__mro__ [1 :- 1 ]))
12571285 )
1258- # The slots for our class. Remove slots from our base classes. Add
1259- # '__weakref__' if weakref_slot was given, unless it is already present.
1260- cls_dict ["__slots__" ] = tuple (
1261- itertools .filterfalse (
1262- inherited_slots .__contains__ ,
1263- itertools .chain (
1264- # gh-93521: '__weakref__' also needs to be filtered out if
1265- # already present in inherited_slots
1266- field_names , ('__weakref__' ,) if weakref_slot else ()
1267- )
1268- ),
1286+
1287+ cls_dict ["__slots__" ] = _create_slots (
1288+ defined_fields , inherited_slots , field_names , weakref_slot ,
12691289 )
12701290
12711291 for field_name in field_names :
0 commit comments