16
16
'Field' ,
17
17
'FrozenInstanceError' ,
18
18
'InitVar' ,
19
+ 'KW_ONLY' ,
19
20
'MISSING' ,
20
21
21
22
# Helper functions.
163
164
# +-------+-------+-------+
164
165
# | True | add | | <- the default
165
166
# +=======+=======+=======+
166
- # __match_args__ is a tuple of __init__ parameter names; non-init fields must
167
- # be matched by keyword.
167
+ # __match_args__ is always added unless the class already defines it. It is a
168
+ # tuple of __init__ parameter names; non-init fields must be matched by keyword.
168
169
169
170
170
171
# Raised when an attempt is made to modify a frozen class.
@@ -184,6 +185,12 @@ class _MISSING_TYPE:
184
185
pass
185
186
MISSING = _MISSING_TYPE ()
186
187
188
+ # A sentinel object to indicate that following fields are keyword-only by
189
+ # default. Use a class to give it a better repr.
190
+ class _KW_ONLY_TYPE :
191
+ pass
192
+ KW_ONLY = _KW_ONLY_TYPE ()
193
+
187
194
# Since most per-field metadata will be unused, create an empty
188
195
# read-only proxy that can be shared among all fields.
189
196
_EMPTY_METADATA = types .MappingProxyType ({})
@@ -232,7 +239,6 @@ def __repr__(self):
232
239
def __class_getitem__ (cls , type ):
233
240
return InitVar (type )
234
241
235
-
236
242
# Instances of Field are only ever created from within this module,
237
243
# and only from the field() function, although Field instances are
238
244
# exposed externally as (conceptually) read-only objects.
@@ -253,11 +259,12 @@ class Field:
253
259
'init' ,
254
260
'compare' ,
255
261
'metadata' ,
262
+ 'kw_only' ,
256
263
'_field_type' , # Private: not to be used by user code.
257
264
)
258
265
259
266
def __init__ (self , default , default_factory , init , repr , hash , compare ,
260
- metadata ):
267
+ metadata , kw_only ):
261
268
self .name = None
262
269
self .type = None
263
270
self .default = default
@@ -269,6 +276,7 @@ def __init__(self, default, default_factory, init, repr, hash, compare,
269
276
self .metadata = (_EMPTY_METADATA
270
277
if metadata is None else
271
278
types .MappingProxyType (metadata ))
279
+ self .kw_only = kw_only
272
280
self ._field_type = None
273
281
274
282
def __repr__ (self ):
@@ -282,6 +290,7 @@ def __repr__(self):
282
290
f'hash={ self .hash !r} ,'
283
291
f'compare={ self .compare !r} ,'
284
292
f'metadata={ self .metadata !r} ,'
293
+ f'kw_only={ self .kw_only !r} ,'
285
294
f'_field_type={ self ._field_type } '
286
295
')' )
287
296
@@ -335,25 +344,36 @@ def __repr__(self):
335
344
# so that a type checker can be told (via overloads) that this is a
336
345
# function whose type depends on its parameters.
337
346
def field (* , default = MISSING , default_factory = MISSING , init = True , repr = True ,
338
- hash = None , compare = True , metadata = None ):
347
+ hash = None , compare = True , metadata = None , kw_only = MISSING ):
339
348
"""Return an object to identify dataclass fields.
340
349
341
350
default is the default value of the field. default_factory is a
342
351
0-argument function called to initialize a field's value. If init
343
- is True, the field will be a parameter to the class's __init__()
344
- function. If repr is True, the field will be included in the
345
- object's repr(). If hash is True, the field will be included in
346
- the object's hash(). If compare is True, the field will be used
347
- in comparison functions. metadata, if specified, must be a
348
- mapping which is stored but not otherwise examined by dataclass.
352
+ is true, the field will be a parameter to the class's __init__()
353
+ function. If repr is true, the field will be included in the
354
+ object's repr(). If hash is true, the field will be included in the
355
+ object's hash(). If compare is true, the field will be used in
356
+ comparison functions. metadata, if specified, must be a mapping
357
+ which is stored but not otherwise examined by dataclass. If kw_only
358
+ is true, the field will become a keyword-only parameter to
359
+ __init__().
349
360
350
361
It is an error to specify both default and default_factory.
351
362
"""
352
363
353
364
if default is not MISSING and default_factory is not MISSING :
354
365
raise ValueError ('cannot specify both default and default_factory' )
355
366
return Field (default , default_factory , init , repr , hash , compare ,
356
- metadata )
367
+ metadata , kw_only )
368
+
369
+
370
+ def _fields_in_init_order (fields ):
371
+ # Returns the fields as __init__ will output them. It returns 2 tuples:
372
+ # the first for normal args, and the second for keyword args.
373
+
374
+ return (tuple (f for f in fields if f .init and not f .kw_only ),
375
+ tuple (f for f in fields if f .init and f .kw_only )
376
+ )
357
377
358
378
359
379
def _tuple_str (obj_name , fields ):
@@ -410,7 +430,6 @@ def _create_fn(name, args, body, *, globals=None, locals=None,
410
430
411
431
local_vars = ', ' .join (locals .keys ())
412
432
txt = f"def __create_fn__({ local_vars } ):\n { txt } \n return { name } "
413
-
414
433
ns = {}
415
434
exec (txt , globals , ns )
416
435
return ns ['__create_fn__' ](** locals )
@@ -501,17 +520,19 @@ def _init_param(f):
501
520
return f'{ f .name } :_type_{ f .name } { default } '
502
521
503
522
504
- def _init_fn (fields , frozen , has_post_init , self_name , globals ):
523
+ def _init_fn (fields , std_fields , kw_only_fields , frozen , has_post_init ,
524
+ self_name , globals ):
505
525
# fields contains both real fields and InitVar pseudo-fields.
506
526
507
527
# Make sure we don't have fields without defaults following fields
508
528
# with defaults. This actually would be caught when exec-ing the
509
529
# function source code, but catching it here gives a better error
510
530
# message, and future-proofs us in case we build up the function
511
531
# using ast.
532
+
512
533
seen_default = False
513
- for f in fields :
514
- # Only consider fields in the __init__ call.
534
+ for f in std_fields :
535
+ # Only consider the non-kw-only fields in the __init__ call.
515
536
if f .init :
516
537
if not (f .default is MISSING and f .default_factory is MISSING ):
517
538
seen_default = True
@@ -543,8 +564,15 @@ def _init_fn(fields, frozen, has_post_init, self_name, globals):
543
564
if not body_lines :
544
565
body_lines = ['pass' ]
545
566
567
+ _init_params = [_init_param (f ) for f in std_fields ]
568
+ if kw_only_fields :
569
+ # Add the keyword-only args. Because the * can only be added if
570
+ # there's at least one keyword-only arg, there needs to be a test here
571
+ # (instead of just concatenting the lists together).
572
+ _init_params += ['*' ]
573
+ _init_params += [_init_param (f ) for f in kw_only_fields ]
546
574
return _create_fn ('__init__' ,
547
- [self_name ] + [ _init_param ( f ) for f in fields if f . init ] ,
575
+ [self_name ] + _init_params ,
548
576
body_lines ,
549
577
locals = locals ,
550
578
globals = globals ,
@@ -623,6 +651,9 @@ def _is_initvar(a_type, dataclasses):
623
651
return (a_type is dataclasses .InitVar
624
652
or type (a_type ) is dataclasses .InitVar )
625
653
654
+ def _is_kw_only (a_type , dataclasses ):
655
+ return a_type is dataclasses .KW_ONLY
656
+
626
657
627
658
def _is_type (annotation , cls , a_module , a_type , is_type_predicate ):
628
659
# Given a type annotation string, does it refer to a_type in
@@ -683,10 +714,11 @@ def _is_type(annotation, cls, a_module, a_type, is_type_predicate):
683
714
return False
684
715
685
716
686
- def _get_field (cls , a_name , a_type ):
687
- # Return a Field object for this field name and type. ClassVars
688
- # and InitVars are also returned, but marked as such (see
689
- # f._field_type).
717
+ def _get_field (cls , a_name , a_type , default_kw_only ):
718
+ # Return a Field object for this field name and type. ClassVars and
719
+ # InitVars are also returned, but marked as such (see f._field_type).
720
+ # default_kw_only is the value of kw_only to use if there isn't a field()
721
+ # that defines it.
690
722
691
723
# If the default value isn't derived from Field, then it's only a
692
724
# normal default value. Convert it to a Field().
@@ -757,6 +789,19 @@ def _get_field(cls, a_name, a_type):
757
789
# init=<not-the-default-init-value>)? It makes no sense for
758
790
# ClassVar and InitVar to specify init=<anything>.
759
791
792
+ # kw_only validation and assignment.
793
+ if f ._field_type in (_FIELD , _FIELD_INITVAR ):
794
+ # For real and InitVar fields, if kw_only wasn't specified use the
795
+ # default value.
796
+ if f .kw_only is MISSING :
797
+ f .kw_only = default_kw_only
798
+ else :
799
+ # Make sure kw_only isn't set for ClassVars
800
+ assert f ._field_type is _FIELD_CLASSVAR
801
+ if f .kw_only is not MISSING :
802
+ raise TypeError (f'field { f .name } is a ClassVar but specifies '
803
+ 'kw_only' )
804
+
760
805
# For real fields, disallow mutable defaults for known types.
761
806
if f ._field_type is _FIELD and isinstance (f .default , (list , dict , set )):
762
807
raise ValueError (f'mutable default { type (f .default )} for field '
@@ -829,7 +874,7 @@ def _hash_exception(cls, fields, globals):
829
874
830
875
831
876
def _process_class (cls , init , repr , eq , order , unsafe_hash , frozen ,
832
- match_args ):
877
+ match_args , kw_only ):
833
878
# Now that dicts retain insertion order, there's no reason to use
834
879
# an ordered dict. I am leveraging that ordering here, because
835
880
# derived class fields overwrite base class fields, but the order
@@ -883,8 +928,22 @@ def _process_class(cls, init, repr, eq, order, unsafe_hash, frozen,
883
928
# Now find fields in our class. While doing so, validate some
884
929
# things, and set the default values (as class attributes) where
885
930
# we can.
886
- cls_fields = [_get_field (cls , name , type )
887
- for name , type in cls_annotations .items ()]
931
+ cls_fields = []
932
+ # Get a reference to this module for the _is_kw_only() test.
933
+ dataclasses = sys .modules [__name__ ]
934
+ for name , type in cls_annotations .items ():
935
+ # See if this is a marker to change the value of kw_only.
936
+ if (_is_kw_only (type , dataclasses )
937
+ or (isinstance (type , str )
938
+ and _is_type (type , cls , dataclasses , dataclasses .KW_ONLY ,
939
+ _is_kw_only ))):
940
+ # Switch the default to kw_only=True, and ignore this
941
+ # annotation: it's not a real field.
942
+ kw_only = True
943
+ else :
944
+ # Otherwise it's a field of some type.
945
+ cls_fields .append (_get_field (cls , name , type , kw_only ))
946
+
888
947
for f in cls_fields :
889
948
fields [f .name ] = f
890
949
@@ -939,15 +998,22 @@ def _process_class(cls, init, repr, eq, order, unsafe_hash, frozen,
939
998
if order and not eq :
940
999
raise ValueError ('eq must be true if order is true' )
941
1000
1001
+ # Include InitVars and regular fields (so, not ClassVars). This is
1002
+ # initialized here, outside of the "if init:" test, because std_init_fields
1003
+ # is used with match_args, below.
1004
+ all_init_fields = [f for f in fields .values ()
1005
+ if f ._field_type in (_FIELD , _FIELD_INITVAR )]
1006
+ (std_init_fields ,
1007
+ kw_only_init_fields ) = _fields_in_init_order (all_init_fields )
1008
+
942
1009
if init :
943
1010
# Does this class have a post-init function?
944
1011
has_post_init = hasattr (cls , _POST_INIT_NAME )
945
1012
946
- # Include InitVars and regular fields (so, not ClassVars).
947
- flds = [f for f in fields .values ()
948
- if f ._field_type in (_FIELD , _FIELD_INITVAR )]
949
1013
_set_new_attribute (cls , '__init__' ,
950
- _init_fn (flds ,
1014
+ _init_fn (all_init_fields ,
1015
+ std_init_fields ,
1016
+ kw_only_init_fields ,
951
1017
frozen ,
952
1018
has_post_init ,
953
1019
# The name to use for the "self"
@@ -1016,16 +1082,18 @@ def _process_class(cls, init, repr, eq, order, unsafe_hash, frozen,
1016
1082
str (inspect .signature (cls )).replace (' -> None' , '' ))
1017
1083
1018
1084
if match_args :
1085
+ # I could probably compute this once
1019
1086
_set_new_attribute (cls , '__match_args__' ,
1020
- tuple (f .name for f in field_list if f . init ))
1087
+ tuple (f .name for f in std_init_fields ))
1021
1088
1022
1089
abc .update_abstractmethods (cls )
1023
1090
1024
1091
return cls
1025
1092
1026
1093
1027
1094
def dataclass (cls = None , / , * , init = True , repr = True , eq = True , order = False ,
1028
- unsafe_hash = False , frozen = False , match_args = True ):
1095
+ unsafe_hash = False , frozen = False , match_args = True ,
1096
+ kw_only = False ):
1029
1097
"""Returns the same class as was passed in, with dunder methods
1030
1098
added based on the fields defined in the class.
1031
1099
@@ -1036,12 +1104,13 @@ def dataclass(cls=None, /, *, init=True, repr=True, eq=True, order=False,
1036
1104
comparison dunder methods are added. If unsafe_hash is true, a
1037
1105
__hash__() method function is added. If frozen is true, fields may
1038
1106
not be assigned to after instance creation. If match_args is true,
1039
- the __match_args__ tuple is added.
1107
+ the __match_args__ tuple is added. If kw_only is true, then by
1108
+ default all fields are keyword-only.
1040
1109
"""
1041
1110
1042
1111
def wrap (cls ):
1043
1112
return _process_class (cls , init , repr , eq , order , unsafe_hash ,
1044
- frozen , match_args )
1113
+ frozen , match_args , kw_only )
1045
1114
1046
1115
# See if we're being called as @dataclass or @dataclass().
1047
1116
if cls is None :
0 commit comments