@@ -283,11 +283,12 @@ class Field:
283
283
'compare' ,
284
284
'metadata' ,
285
285
'kw_only' ,
286
+ 'doc' ,
286
287
'_field_type' , # Private: not to be used by user code.
287
288
)
288
289
289
290
def __init__ (self , default , default_factory , init , repr , hash , compare ,
290
- metadata , kw_only ):
291
+ metadata , kw_only , doc ):
291
292
self .name = None
292
293
self .type = None
293
294
self .default = default
@@ -300,6 +301,7 @@ def __init__(self, default, default_factory, init, repr, hash, compare,
300
301
if metadata is None else
301
302
types .MappingProxyType (metadata ))
302
303
self .kw_only = kw_only
304
+ self .doc = doc
303
305
self ._field_type = None
304
306
305
307
@recursive_repr ()
@@ -315,6 +317,7 @@ def __repr__(self):
315
317
f'compare={ self .compare !r} ,'
316
318
f'metadata={ self .metadata !r} ,'
317
319
f'kw_only={ self .kw_only !r} ,'
320
+ f'doc={ self .doc !r} ,'
318
321
f'_field_type={ self ._field_type } '
319
322
')' )
320
323
@@ -382,7 +385,7 @@ def __repr__(self):
382
385
# so that a type checker can be told (via overloads) that this is a
383
386
# function whose type depends on its parameters.
384
387
def 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 ):
386
389
"""Return an object to identify dataclass fields.
387
390
388
391
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,
394
397
comparison functions. metadata, if specified, must be a mapping
395
398
which is stored but not otherwise examined by dataclass. If kw_only
396
399
is true, the field will become a keyword-only parameter to
397
- __init__().
400
+ __init__(). doc is an optional docstring for this field.
398
401
399
402
It is an error to specify both default and default_factory.
400
403
"""
401
404
402
405
if default is not MISSING and default_factory is not MISSING :
403
406
raise ValueError ('cannot specify both default and default_factory' )
404
407
return Field (default , default_factory , init , repr , hash , compare ,
405
- metadata , kw_only )
408
+ metadata , kw_only , doc )
406
409
407
410
408
411
def _fields_in_init_order (fields ):
@@ -1174,7 +1177,7 @@ def _process_class(cls, init, repr, eq, order, unsafe_hash, frozen,
1174
1177
if weakref_slot and not slots :
1175
1178
raise TypeError ('weakref_slot is True but slots is False' )
1176
1179
if slots :
1177
- cls = _add_slots (cls , frozen , weakref_slot )
1180
+ cls = _add_slots (cls , frozen , weakref_slot , fields )
1178
1181
1179
1182
abc .update_abstractmethods (cls )
1180
1183
@@ -1239,7 +1242,32 @@ def _update_func_cell_for__class__(f, oldcls, newcls):
1239
1242
return False
1240
1243
1241
1244
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 ):
1243
1271
# Need to create a new class, since we can't set __slots__ after a
1244
1272
# class has been created, and the @dataclass decorator is called
1245
1273
# after the class is created.
@@ -1255,17 +1283,9 @@ def _add_slots(cls, is_frozen, weakref_slot):
1255
1283
inherited_slots = set (
1256
1284
itertools .chain .from_iterable (map (_get_slots , cls .__mro__ [1 :- 1 ]))
1257
1285
)
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 ,
1269
1289
)
1270
1290
1271
1291
for field_name in field_names :
0 commit comments