blob: eaaed63ef2826ec8b9b3b079980929bd811263bb [file] [log] [blame]
Eric V. Smithf0db54a2017-12-04 16:58:55 -05001import sys
2import types
3from copy import deepcopy
4import collections
5import inspect
6
7__all__ = ['dataclass',
8 'field',
9 'FrozenInstanceError',
10 'InitVar',
Eric V. Smith03220fd2017-12-29 13:59:58 -050011 'MISSING',
Eric V. Smithf0db54a2017-12-04 16:58:55 -050012
13 # Helper functions.
14 'fields',
15 'asdict',
16 'astuple',
17 'make_dataclass',
18 'replace',
19 ]
20
21# Raised when an attempt is made to modify a frozen class.
22class FrozenInstanceError(AttributeError): pass
23
24# A sentinel object for default values to signal that a
25# default-factory will be used.
26# This is given a nice repr() which will appear in the function
27# signature of dataclasses' constructors.
28class _HAS_DEFAULT_FACTORY_CLASS:
29 def __repr__(self):
30 return '<factory>'
31_HAS_DEFAULT_FACTORY = _HAS_DEFAULT_FACTORY_CLASS()
32
Eric V. Smith03220fd2017-12-29 13:59:58 -050033# A sentinel object to detect if a parameter is supplied or not. Use
34# a class to give it a better repr.
35class _MISSING_TYPE:
36 pass
37MISSING = _MISSING_TYPE()
Eric V. Smithf0db54a2017-12-04 16:58:55 -050038
39# Since most per-field metadata will be unused, create an empty
40# read-only proxy that can be shared among all fields.
41_EMPTY_METADATA = types.MappingProxyType({})
42
43# Markers for the various kinds of fields and pseudo-fields.
44_FIELD = object() # An actual field.
45_FIELD_CLASSVAR = object() # Not a field, but a ClassVar.
46_FIELD_INITVAR = object() # Not a field, but an InitVar.
47
48# The name of an attribute on the class where we store the Field
49# objects. Also used to check if a class is a Data Class.
50_MARKER = '__dataclass_fields__'
51
52# The name of the function, that if it exists, is called at the end of
53# __init__.
54_POST_INIT_NAME = '__post_init__'
55
56
57class _InitVarMeta(type):
58 def __getitem__(self, params):
59 return self
60
61class InitVar(metaclass=_InitVarMeta):
62 pass
63
64
65# Instances of Field are only ever created from within this module,
66# and only from the field() function, although Field instances are
67# exposed externally as (conceptually) read-only objects.
68# name and type are filled in after the fact, not in __init__. They're
69# not known at the time this class is instantiated, but it's
70# convenient if they're available later.
71# When cls._MARKER is filled in with a list of Field objects, the name
72# and type fields will have been populated.
73class Field:
74 __slots__ = ('name',
75 'type',
76 'default',
77 'default_factory',
78 'repr',
79 'hash',
80 'init',
81 'compare',
82 'metadata',
83 '_field_type', # Private: not to be used by user code.
84 )
85
86 def __init__(self, default, default_factory, init, repr, hash, compare,
87 metadata):
88 self.name = None
89 self.type = None
90 self.default = default
91 self.default_factory = default_factory
92 self.init = init
93 self.repr = repr
94 self.hash = hash
95 self.compare = compare
96 self.metadata = (_EMPTY_METADATA
97 if metadata is None or len(metadata) == 0 else
98 types.MappingProxyType(metadata))
99 self._field_type = None
100
101 def __repr__(self):
102 return ('Field('
103 f'name={self.name!r},'
104 f'type={self.type},'
105 f'default={self.default},'
106 f'default_factory={self.default_factory},'
107 f'init={self.init},'
108 f'repr={self.repr},'
109 f'hash={self.hash},'
110 f'compare={self.compare},'
111 f'metadata={self.metadata}'
112 ')')
113
114
115# This function is used instead of exposing Field creation directly,
116# so that a type checker can be told (via overloads) that this is a
117# function whose type depends on its parameters.
Eric V. Smith03220fd2017-12-29 13:59:58 -0500118def field(*, default=MISSING, default_factory=MISSING, init=True, repr=True,
Eric V. Smithf0db54a2017-12-04 16:58:55 -0500119 hash=None, compare=True, metadata=None):
120 """Return an object to identify dataclass fields.
121
122 default is the default value of the field. default_factory is a
123 0-argument function called to initialize a field's value. If init
124 is True, the field will be a parameter to the class's __init__()
125 function. If repr is True, the field will be included in the
126 object's repr(). If hash is True, the field will be included in
127 the object's hash(). If compare is True, the field will be used in
128 comparison functions. metadata, if specified, must be a mapping
129 which is stored but not otherwise examined by dataclass.
130
131 It is an error to specify both default and default_factory.
132 """
133
Eric V. Smith03220fd2017-12-29 13:59:58 -0500134 if default is not MISSING and default_factory is not MISSING:
Eric V. Smithf0db54a2017-12-04 16:58:55 -0500135 raise ValueError('cannot specify both default and default_factory')
136 return Field(default, default_factory, init, repr, hash, compare,
137 metadata)
138
139
140def _tuple_str(obj_name, fields):
141 # Return a string representing each field of obj_name as a tuple
142 # member. So, if fields is ['x', 'y'] and obj_name is "self",
143 # return "(self.x,self.y)".
144
145 # Special case for the 0-tuple.
146 if len(fields) == 0:
147 return '()'
148 # Note the trailing comma, needed if this turns out to be a 1-tuple.
149 return f'({",".join([f"{obj_name}.{f.name}" for f in fields])},)'
150
151
152def _create_fn(name, args, body, globals=None, locals=None,
Eric V. Smith03220fd2017-12-29 13:59:58 -0500153 return_type=MISSING):
Eric V. Smithf0db54a2017-12-04 16:58:55 -0500154 # Note that we mutate locals when exec() is called. Caller beware!
155 if locals is None:
156 locals = {}
157 return_annotation = ''
Eric V. Smith03220fd2017-12-29 13:59:58 -0500158 if return_type is not MISSING:
Eric V. Smithf0db54a2017-12-04 16:58:55 -0500159 locals['_return_type'] = return_type
160 return_annotation = '->_return_type'
161 args = ','.join(args)
162 body = '\n'.join(f' {b}' for b in body)
163
164 txt = f'def {name}({args}){return_annotation}:\n{body}'
165
166 exec(txt, globals, locals)
167 return locals[name]
168
169
170def _field_assign(frozen, name, value, self_name):
171 # If we're a frozen class, then assign to our fields in __init__
172 # via object.__setattr__. Otherwise, just use a simple
173 # assignment.
174 # self_name is what "self" is called in this function: don't
175 # hard-code "self", since that might be a field name.
176 if frozen:
177 return f'object.__setattr__({self_name},{name!r},{value})'
178 return f'{self_name}.{name}={value}'
179
180
181def _field_init(f, frozen, globals, self_name):
182 # Return the text of the line in the body of __init__ that will
183 # initialize this field.
184
185 default_name = f'_dflt_{f.name}'
Eric V. Smith03220fd2017-12-29 13:59:58 -0500186 if f.default_factory is not MISSING:
Eric V. Smithf0db54a2017-12-04 16:58:55 -0500187 if f.init:
188 # This field has a default factory. If a parameter is
189 # given, use it. If not, call the factory.
190 globals[default_name] = f.default_factory
191 value = (f'{default_name}() '
192 f'if {f.name} is _HAS_DEFAULT_FACTORY '
193 f'else {f.name}')
194 else:
195 # This is a field that's not in the __init__ params, but
196 # has a default factory function. It needs to be
197 # initialized here by calling the factory function,
198 # because there's no other way to initialize it.
199
200 # For a field initialized with a default=defaultvalue, the
201 # class dict just has the default value
202 # (cls.fieldname=defaultvalue). But that won't work for a
203 # default factory, the factory must be called in __init__
204 # and we must assign that to self.fieldname. We can't
205 # fall back to the class dict's value, both because it's
206 # not set, and because it might be different per-class
207 # (which, after all, is why we have a factory function!).
208
209 globals[default_name] = f.default_factory
210 value = f'{default_name}()'
211 else:
212 # No default factory.
213 if f.init:
Eric V. Smith03220fd2017-12-29 13:59:58 -0500214 if f.default is MISSING:
Eric V. Smithf0db54a2017-12-04 16:58:55 -0500215 # There's no default, just do an assignment.
216 value = f.name
Eric V. Smith03220fd2017-12-29 13:59:58 -0500217 elif f.default is not MISSING:
Eric V. Smithf0db54a2017-12-04 16:58:55 -0500218 globals[default_name] = f.default
219 value = f.name
220 else:
221 # This field does not need initialization. Signify that to
222 # the caller by returning None.
223 return None
224
225 # Only test this now, so that we can create variables for the
226 # default. However, return None to signify that we're not going
227 # to actually do the assignment statement for InitVars.
228 if f._field_type == _FIELD_INITVAR:
229 return None
230
231 # Now, actually generate the field assignment.
232 return _field_assign(frozen, f.name, value, self_name)
233
234
235def _init_param(f):
236 # Return the __init__ parameter string for this field.
237 # For example, the equivalent of 'x:int=3' (except instead of 'int',
238 # reference a variable set to int, and instead of '3', reference a
239 # variable set to 3).
Eric V. Smith03220fd2017-12-29 13:59:58 -0500240 if f.default is MISSING and f.default_factory is MISSING:
Eric V. Smithf0db54a2017-12-04 16:58:55 -0500241 # There's no default, and no default_factory, just
242 # output the variable name and type.
243 default = ''
Eric V. Smith03220fd2017-12-29 13:59:58 -0500244 elif f.default is not MISSING:
Eric V. Smithf0db54a2017-12-04 16:58:55 -0500245 # There's a default, this will be the name that's used to look it up.
246 default = f'=_dflt_{f.name}'
Eric V. Smith03220fd2017-12-29 13:59:58 -0500247 elif f.default_factory is not MISSING:
Eric V. Smithf0db54a2017-12-04 16:58:55 -0500248 # There's a factory function. Set a marker.
249 default = '=_HAS_DEFAULT_FACTORY'
250 return f'{f.name}:_type_{f.name}{default}'
251
252
253def _init_fn(fields, frozen, has_post_init, self_name):
254 # fields contains both real fields and InitVar pseudo-fields.
255
256 # Make sure we don't have fields without defaults following fields
257 # with defaults. This actually would be caught when exec-ing the
258 # function source code, but catching it here gives a better error
259 # message, and future-proofs us in case we build up the function
260 # using ast.
261 seen_default = False
262 for f in fields:
263 # Only consider fields in the __init__ call.
264 if f.init:
Eric V. Smith03220fd2017-12-29 13:59:58 -0500265 if not (f.default is MISSING and f.default_factory is MISSING):
Eric V. Smithf0db54a2017-12-04 16:58:55 -0500266 seen_default = True
267 elif seen_default:
268 raise TypeError(f'non-default argument {f.name!r} '
269 'follows default argument')
270
Eric V. Smith03220fd2017-12-29 13:59:58 -0500271 globals = {'MISSING': MISSING,
Eric V. Smithf0db54a2017-12-04 16:58:55 -0500272 '_HAS_DEFAULT_FACTORY': _HAS_DEFAULT_FACTORY}
273
274 body_lines = []
275 for f in fields:
276 # Do not initialize the pseudo-fields, only the real ones.
277 line = _field_init(f, frozen, globals, self_name)
278 if line is not None:
279 # line is None means that this field doesn't require
280 # initialization. Just skip it.
281 body_lines.append(line)
282
283 # Does this class have a post-init function?
284 if has_post_init:
285 params_str = ','.join(f.name for f in fields
286 if f._field_type is _FIELD_INITVAR)
287 body_lines += [f'{self_name}.{_POST_INIT_NAME}({params_str})']
288
289 # If no body lines, use 'pass'.
290 if len(body_lines) == 0:
291 body_lines = ['pass']
292
293 locals = {f'_type_{f.name}': f.type for f in fields}
294 return _create_fn('__init__',
295 [self_name] +[_init_param(f) for f in fields if f.init],
296 body_lines,
297 locals=locals,
298 globals=globals,
299 return_type=None)
300
301
302def _repr_fn(fields):
303 return _create_fn('__repr__',
304 ['self'],
305 ['return self.__class__.__qualname__ + f"(' +
306 ', '.join([f"{f.name}={{self.{f.name}!r}}"
307 for f in fields]) +
308 ')"'])
309
310
311def _frozen_setattr(self, name, value):
312 raise FrozenInstanceError(f'cannot assign to field {name!r}')
313
314
315def _frozen_delattr(self, name):
316 raise FrozenInstanceError(f'cannot delete field {name!r}')
317
318
319def _cmp_fn(name, op, self_tuple, other_tuple):
320 # Create a comparison function. If the fields in the object are
321 # named 'x' and 'y', then self_tuple is the string
322 # '(self.x,self.y)' and other_tuple is the string
323 # '(other.x,other.y)'.
324
325 return _create_fn(name,
326 ['self', 'other'],
327 [ 'if other.__class__ is self.__class__:',
328 f' return {self_tuple}{op}{other_tuple}',
329 'return NotImplemented'])
330
331
332def _set_eq_fns(cls, fields):
333 # Create and set the equality comparison methods on cls.
334 # Pre-compute self_tuple and other_tuple, then re-use them for
335 # each function.
336 self_tuple = _tuple_str('self', fields)
337 other_tuple = _tuple_str('other', fields)
338 for name, op in [('__eq__', '=='),
339 ('__ne__', '!='),
340 ]:
341 _set_attribute(cls, name, _cmp_fn(name, op, self_tuple, other_tuple))
342
343
344def _set_order_fns(cls, fields):
345 # Create and set the ordering methods on cls.
346 # Pre-compute self_tuple and other_tuple, then re-use them for
347 # each function.
348 self_tuple = _tuple_str('self', fields)
349 other_tuple = _tuple_str('other', fields)
350 for name, op in [('__lt__', '<'),
351 ('__le__', '<='),
352 ('__gt__', '>'),
353 ('__ge__', '>='),
354 ]:
355 _set_attribute(cls, name, _cmp_fn(name, op, self_tuple, other_tuple))
356
357
358def _hash_fn(fields):
359 self_tuple = _tuple_str('self', fields)
360 return _create_fn('__hash__',
361 ['self'],
362 [f'return hash({self_tuple})'])
363
364
365def _get_field(cls, a_name, a_type):
366 # Return a Field object, for this field name and type. ClassVars
367 # and InitVars are also returned, but marked as such (see
368 # f._field_type).
369
370 # If the default value isn't derived from field, then it's
371 # only a normal default value. Convert it to a Field().
Eric V. Smith03220fd2017-12-29 13:59:58 -0500372 default = getattr(cls, a_name, MISSING)
Eric V. Smithf0db54a2017-12-04 16:58:55 -0500373 if isinstance(default, Field):
374 f = default
375 else:
376 f = field(default=default)
377
378 # Assume it's a normal field until proven otherwise.
379 f._field_type = _FIELD
380
381 # Only at this point do we know the name and the type. Set them.
382 f.name = a_name
383 f.type = a_type
384
385 # If typing has not been imported, then it's impossible for
386 # any annotation to be a ClassVar. So, only look for ClassVar
387 # if typing has been imported.
388 typing = sys.modules.get('typing')
389 if typing is not None:
390 # This test uses a typing internal class, but it's the best
391 # way to test if this is a ClassVar.
392 if type(a_type) is typing._ClassVar:
393 # This field is a ClassVar, so it's not a field.
394 f._field_type = _FIELD_CLASSVAR
395
396 if f._field_type is _FIELD:
397 # Check if this is an InitVar.
398 if a_type is InitVar:
399 # InitVars are not fields, either.
400 f._field_type = _FIELD_INITVAR
401
402 # Validations for fields. This is delayed until now, instead of
403 # in the Field() constructor, since only here do we know the field
404 # name, which allows better error reporting.
405
406 # Special restrictions for ClassVar and InitVar.
407 if f._field_type in (_FIELD_CLASSVAR, _FIELD_INITVAR):
Eric V. Smith03220fd2017-12-29 13:59:58 -0500408 if f.default_factory is not MISSING:
Eric V. Smithf0db54a2017-12-04 16:58:55 -0500409 raise TypeError(f'field {f.name} cannot have a '
410 'default factory')
411 # Should I check for other field settings? default_factory
412 # seems the most serious to check for. Maybe add others. For
413 # example, how about init=False (or really,
414 # init=<not-the-default-init-value>)? It makes no sense for
415 # ClassVar and InitVar to specify init=<anything>.
416
417 # For real fields, disallow mutable defaults for known types.
418 if f._field_type is _FIELD and isinstance(f.default, (list, dict, set)):
419 raise ValueError(f'mutable default {type(f.default)} for field '
420 f'{f.name} is not allowed: use default_factory')
421
422 return f
423
424
425def _find_fields(cls):
426 # Return a list of Field objects, in order, for this class (and no
427 # base classes). Fields are found from __annotations__ (which is
428 # guaranteed to be ordered). Default values are from class
429 # attributes, if a field has a default. If the default value is
430 # a Field(), then it contains additional info beyond (and
431 # possibly including) the actual default value. Pseudo-fields
432 # ClassVars and InitVars are included, despite the fact that
433 # they're not real fields. That's deal with later.
434
435 annotations = getattr(cls, '__annotations__', {})
436
437 return [_get_field(cls, a_name, a_type)
438 for a_name, a_type in annotations.items()]
439
440
441def _set_attribute(cls, name, value):
442 # Raise TypeError if an attribute by this name already exists.
443 if name in cls.__dict__:
444 raise TypeError(f'Cannot overwrite attribute {name} '
445 f'in {cls.__name__}')
446 setattr(cls, name, value)
447
448
449def _process_class(cls, repr, eq, order, hash, init, frozen):
450 # Use an OrderedDict because:
451 # - Order matters!
452 # - Derived class fields overwrite base class fields, but the
453 # order is defined by the base class, which is found first.
454 fields = collections.OrderedDict()
455
456 # Find our base classes in reverse MRO order, and exclude
457 # ourselves. In reversed order so that more derived classes
458 # override earlier field definitions in base classes.
459 for b in cls.__mro__[-1:0:-1]:
460 # Only process classes that have been processed by our
461 # decorator. That is, they have a _MARKER attribute.
462 base_fields = getattr(b, _MARKER, None)
463 if base_fields:
464 for f in base_fields.values():
465 fields[f.name] = f
466
467 # Now find fields in our class. While doing so, validate some
468 # things, and set the default values (as class attributes)
469 # where we can.
470 for f in _find_fields(cls):
471 fields[f.name] = f
472
473 # If the class attribute (which is the default value for
474 # this field) exists and is of type 'Field', replace it
475 # with the real default. This is so that normal class
476 # introspection sees a real default value, not a Field.
477 if isinstance(getattr(cls, f.name, None), Field):
Eric V. Smith03220fd2017-12-29 13:59:58 -0500478 if f.default is MISSING:
Eric V. Smithf0db54a2017-12-04 16:58:55 -0500479 # If there's no default, delete the class attribute.
480 # This happens if we specify field(repr=False), for
481 # example (that is, we specified a field object, but
482 # no default value). Also if we're using a default
483 # factory. The class attribute should not be set at
484 # all in the post-processed class.
485 delattr(cls, f.name)
486 else:
487 setattr(cls, f.name, f.default)
488
489 # Remember all of the fields on our class (including bases). This
490 # marks this class as being a dataclass.
491 setattr(cls, _MARKER, fields)
492
493 # We also need to check if a parent class is frozen: frozen has to
494 # be inherited down.
495 is_frozen = frozen or cls.__setattr__ is _frozen_setattr
496
497 # If we're generating ordering methods, we must be generating
498 # the eq methods.
499 if order and not eq:
500 raise ValueError('eq must be true if order is true')
501
502 if init:
503 # Does this class have a post-init function?
504 has_post_init = hasattr(cls, _POST_INIT_NAME)
505
506 # Include InitVars and regular fields (so, not ClassVars).
507 _set_attribute(cls, '__init__',
508 _init_fn(list(filter(lambda f: f._field_type
509 in (_FIELD, _FIELD_INITVAR),
510 fields.values())),
511 is_frozen,
512 has_post_init,
513 # The name to use for the "self" param
514 # in __init__. Use "self" if possible.
515 '__dataclass_self__' if 'self' in fields
516 else 'self',
517 ))
518
519 # Get the fields as a list, and include only real fields. This is
520 # used in all of the following methods.
521 field_list = list(filter(lambda f: f._field_type is _FIELD,
522 fields.values()))
523
524 if repr:
525 _set_attribute(cls, '__repr__',
526 _repr_fn(list(filter(lambda f: f.repr, field_list))))
527
528 if is_frozen:
529 _set_attribute(cls, '__setattr__', _frozen_setattr)
530 _set_attribute(cls, '__delattr__', _frozen_delattr)
531
532 generate_hash = False
533 if hash is None:
534 if eq and frozen:
535 # Generate a hash function.
536 generate_hash = True
537 elif eq and not frozen:
538 # Not hashable.
539 _set_attribute(cls, '__hash__', None)
540 elif not eq:
541 # Otherwise, use the base class definition of hash(). That is,
542 # don't set anything on this class.
543 pass
544 else:
545 assert "can't get here"
546 else:
547 generate_hash = hash
548 if generate_hash:
549 _set_attribute(cls, '__hash__',
550 _hash_fn(list(filter(lambda f: f.compare
551 if f.hash is None
552 else f.hash,
553 field_list))))
554
555 if eq:
556 # Create and __eq__ and __ne__ methods.
557 _set_eq_fns(cls, list(filter(lambda f: f.compare, field_list)))
558
559 if order:
560 # Create and __lt__, __le__, __gt__, and __ge__ methods.
561 # Create and set the comparison functions.
562 _set_order_fns(cls, list(filter(lambda f: f.compare, field_list)))
563
564 if not getattr(cls, '__doc__'):
565 # Create a class doc-string.
566 cls.__doc__ = (cls.__name__ +
567 str(inspect.signature(cls)).replace(' -> None', ''))
568
569 return cls
570
571
572# _cls should never be specified by keyword, so start it with an
573# underscore. The presense of _cls is used to detect if this
574# decorator is being called with parameters or not.
575def dataclass(_cls=None, *, init=True, repr=True, eq=True, order=False,
576 hash=None, frozen=False):
577 """Returns the same class as was passed in, with dunder methods
578 added based on the fields defined in the class.
579
580 Examines PEP 526 __annotations__ to determine fields.
581
582 If init is true, an __init__() method is added to the class. If
583 repr is true, a __repr__() method is added. If order is true, rich
584 comparison dunder methods are added. If hash is true, a __hash__()
585 method function is added. If frozen is true, fields may not be
586 assigned to after instance creation.
587 """
588
589 def wrap(cls):
590 return _process_class(cls, repr, eq, order, hash, init, frozen)
591
592 # See if we're being called as @dataclass or @dataclass().
593 if _cls is None:
594 # We're called with parens.
595 return wrap
596
597 # We're called as @dataclass without parens.
598 return wrap(_cls)
599
600
601def fields(class_or_instance):
602 """Return a tuple describing the fields of this dataclass.
603
604 Accepts a dataclass or an instance of one. Tuple elements are of
605 type Field.
606 """
607
608 # Might it be worth caching this, per class?
609 try:
610 fields = getattr(class_or_instance, _MARKER)
611 except AttributeError:
612 raise TypeError('must be called with a dataclass type or instance')
613
614 # Exclude pseudo-fields.
615 return tuple(f for f in fields.values() if f._field_type is _FIELD)
616
617
618def _isdataclass(obj):
619 """Returns True if obj is an instance of a dataclass."""
620 return not isinstance(obj, type) and hasattr(obj, _MARKER)
621
622
623def asdict(obj, *, dict_factory=dict):
624 """Return the fields of a dataclass instance as a new dictionary mapping
625 field names to field values.
626
627 Example usage:
628
629 @dataclass
630 class C:
631 x: int
632 y: int
633
634 c = C(1, 2)
635 assert asdict(c) == {'x': 1, 'y': 2}
636
637 If given, 'dict_factory' will be used instead of built-in dict.
638 The function applies recursively to field values that are
639 dataclass instances. This will also look into built-in containers:
640 tuples, lists, and dicts.
641 """
642 if not _isdataclass(obj):
643 raise TypeError("asdict() should be called on dataclass instances")
644 return _asdict_inner(obj, dict_factory)
645
646def _asdict_inner(obj, dict_factory):
647 if _isdataclass(obj):
648 result = []
649 for f in fields(obj):
650 value = _asdict_inner(getattr(obj, f.name), dict_factory)
651 result.append((f.name, value))
652 return dict_factory(result)
653 elif isinstance(obj, (list, tuple)):
654 return type(obj)(_asdict_inner(v, dict_factory) for v in obj)
655 elif isinstance(obj, dict):
656 return type(obj)((_asdict_inner(k, dict_factory), _asdict_inner(v, dict_factory))
657 for k, v in obj.items())
658 else:
659 return deepcopy(obj)
660
661
662def astuple(obj, *, tuple_factory=tuple):
663 """Return the fields of a dataclass instance as a new tuple of field values.
664
665 Example usage::
666
667 @dataclass
668 class C:
669 x: int
670 y: int
671
672 c = C(1, 2)
673 assert asdtuple(c) == (1, 2)
674
675 If given, 'tuple_factory' will be used instead of built-in tuple.
676 The function applies recursively to field values that are
677 dataclass instances. This will also look into built-in containers:
678 tuples, lists, and dicts.
679 """
680
681 if not _isdataclass(obj):
682 raise TypeError("astuple() should be called on dataclass instances")
683 return _astuple_inner(obj, tuple_factory)
684
685def _astuple_inner(obj, tuple_factory):
686 if _isdataclass(obj):
687 result = []
688 for f in fields(obj):
689 value = _astuple_inner(getattr(obj, f.name), tuple_factory)
690 result.append(value)
691 return tuple_factory(result)
692 elif isinstance(obj, (list, tuple)):
693 return type(obj)(_astuple_inner(v, tuple_factory) for v in obj)
694 elif isinstance(obj, dict):
695 return type(obj)((_astuple_inner(k, tuple_factory), _astuple_inner(v, tuple_factory))
696 for k, v in obj.items())
697 else:
698 return deepcopy(obj)
699
700
701def make_dataclass(cls_name, fields, *, bases=(), namespace=None):
702 """Return a new dynamically created dataclass.
703
704 The dataclass name will be 'cls_name'. 'fields' is an interable
705 of either (name, type) or (name, type, Field) objects. Field
706 objects are created by calling 'field(name, type [, Field])'.
707
708 C = make_class('C', [('a', int', ('b', int, Field(init=False))], bases=Base)
709
710 is equivalent to:
711
712 @dataclass
713 class C(Base):
714 a: int
715 b: int = field(init=False)
716
717 For the bases and namespace paremeters, see the builtin type() function.
718 """
719
720 if namespace is None:
721 namespace = {}
722 else:
723 # Copy namespace since we're going to mutate it.
724 namespace = namespace.copy()
725
726 anns = collections.OrderedDict((name, tp) for name, tp, *_ in fields)
727 namespace['__annotations__'] = anns
728 for item in fields:
729 if len(item) == 3:
730 name, tp, spec = item
731 namespace[name] = spec
732 cls = type(cls_name, bases, namespace)
733 return dataclass(cls)
734
735
736def replace(obj, **changes):
737 """Return a new object replacing specified fields with new values.
738
739 This is especially useful for frozen classes. Example usage:
740
741 @dataclass(frozen=True)
742 class C:
743 x: int
744 y: int
745
746 c = C(1, 2)
747 c1 = replace(c, x=3)
748 assert c1.x == 3 and c1.y == 2
749 """
750
751 # We're going to mutate 'changes', but that's okay because it's a new
752 # dict, even if called with 'replace(obj, **my_changes)'.
753
754 if not _isdataclass(obj):
755 raise TypeError("replace() should be called on dataclass instances")
756
757 # It's an error to have init=False fields in 'changes'.
758 # If a field is not in 'changes', read its value from the provided obj.
759
760 for f in getattr(obj, _MARKER).values():
761 if not f.init:
762 # Error if this field is specified in changes.
763 if f.name in changes:
764 raise ValueError(f'field {f.name} is declared with '
765 'init=False, it cannot be specified with '
766 'replace()')
767 continue
768
769 if f.name not in changes:
770 changes[f.name] = getattr(obj, f.name)
771
772 # Create the new object, which calls __init__() and __post_init__
773 # (if defined), using all of the init fields we've added and/or
774 # left in 'changes'.
775 # If there are values supplied in changes that aren't fields, this
776 # will correctly raise a TypeError.
777 return obj.__class__(**changes)