codekingpro/portable-devtools
114k
1import re2import sys3import copy4import types5import inspect6import keyword7import itertools8import annotationlib9import abc10from reprlib import recursive_repr11 12 13__all__ = ['dataclass',14 'field',15 'Field',16 'FrozenInstanceError',17 'InitVar',18 'KW_ONLY',19 'MISSING',20 21 # Helper functions.22 'fields',23 'asdict',24 'astuple',25 'make_dataclass',26 'replace',27 'is_dataclass',28 ]29 30# Conditions for adding methods. The boxes indicate what action the31# dataclass decorator takes. For all of these tables, when I talk32# about init=, repr=, eq=, order=, unsafe_hash=, or frozen=, I'm33# referring to the arguments to the @dataclass decorator. When34# checking if a dunder method already exists, I mean check for an35# entry in the class's __dict__. I never check to see if an attribute36# is defined in a base class.37 38# Key:39# +=========+=========================================+40# + Value | Meaning |41# +=========+=========================================+42# | <blank> | No action: no method is added. |43# +---------+-----------------------------------------+44# | add | Generated method is added. |45# +---------+-----------------------------------------+46# | raise | TypeError is raised. |47# +---------+-----------------------------------------+48# | None | Attribute is set to None. |49# +=========+=========================================+50 51# __init__52#53# +--- init= parameter54# |55# v | | |56# | no | yes | <--- class has __init__ in __dict__?57# +=======+=======+=======+58# | False | | |59# +-------+-------+-------+60# | True | add | | <- the default61# +=======+=======+=======+62 63# __repr__64#65# +--- repr= parameter66# |67# v | | |68# | no | yes | <--- class has __repr__ in __dict__?69# +=======+=======+=======+70# | False | | |71# +-------+-------+-------+72# | True | add | | <- the default73# +=======+=======+=======+74 75 76# __setattr__77# __delattr__78#79# +--- frozen= parameter80# |81# v | | |82# | no | yes | <--- class has __setattr__ or __delattr__ in __dict__?83# +=======+=======+=======+84# | False | | | <- the default85# +-------+-------+-------+86# | True | add | raise |87# +=======+=======+=======+88# Raise because not adding these methods would break the "frozen-ness"89# of the class.90 91# __eq__92#93# +--- eq= parameter94# |95# v | | |96# | no | yes | <--- class has __eq__ in __dict__?97# +=======+=======+=======+98# | False | | |99# +-------+-------+-------+100# | True | add | | <- the default101# +=======+=======+=======+102 103# __lt__104# __le__105# __gt__106# __ge__107#108# +--- order= parameter109# |110# v | | |111# | no | yes | <--- class has any comparison method in __dict__?112# +=======+=======+=======+113# | False | | | <- the default114# +-------+-------+-------+115# | True | add | raise |116# +=======+=======+=======+117# Raise because to allow this case would interfere with using118# functools.total_ordering.119 120# __hash__121 122# +------------------- unsafe_hash= parameter123# | +----------- eq= parameter124# | | +--- frozen= parameter125# | | |126# v v v | | |127# | no | yes | <--- class has explicitly defined __hash__128# +=======+=======+=======+========+========+129# | False | False | False | | | No __eq__, use the base class __hash__130# +-------+-------+-------+--------+--------+131# | False | False | True | | | No __eq__, use the base class __hash__132# +-------+-------+-------+--------+--------+133# | False | True | False | None | | <-- the default, not hashable134# +-------+-------+-------+--------+--------+135# | False | True | True | add | | Frozen, so hashable, allows override136# +-------+-------+-------+--------+--------+137# | True | False | False | add | raise | Has no __eq__, but hashable138# +-------+-------+-------+--------+--------+139# | True | False | True | add | raise | Has no __eq__, but hashable140# +-------+-------+-------+--------+--------+141# | True | True | False | add | raise | Not frozen, but hashable142# +-------+-------+-------+--------+--------+143# | True | True | True | add | raise | Frozen, so hashable144# +=======+=======+=======+========+========+145# For boxes that are blank, __hash__ is untouched and therefore146# inherited from the base class. If the base is object, then147# id-based hashing is used.148#149# Note that a class may already have __hash__=None if it specified an150# __eq__ method in the class body (not one that was created by151# @dataclass).152#153# See _hash_action (below) for a coded version of this table.154 155# __match_args__156#157# +--- match_args= parameter158# |159# v | | |160# | no | yes | <--- class has __match_args__ in __dict__?161# +=======+=======+=======+162# | False | | |163# +-------+-------+-------+164# | True | add | | <- the default165# +=======+=======+=======+166# __match_args__ is always added unless the class already defines it. It is a167# tuple of __init__ parameter names; non-init fields must be matched by keyword.168 169 170# Raised when an attempt is made to modify a frozen class.171class FrozenInstanceError(AttributeError): pass172 173# A sentinel object for default values to signal that a default174# factory will be used. This is given a nice repr() which will appear175# in the function signature of dataclasses' constructors.176class _HAS_DEFAULT_FACTORY_CLASS:177 def __repr__(self):178 return '<factory>'179_HAS_DEFAULT_FACTORY = _HAS_DEFAULT_FACTORY_CLASS()180 181# A sentinel object to detect if a parameter is supplied or not. Use182# a class to give it a better repr.183class _MISSING_TYPE:184 pass185MISSING = _MISSING_TYPE()186 187# A sentinel object to indicate that following fields are keyword-only by188# default. Use a class to give it a better repr.189class _KW_ONLY_TYPE:190 pass191KW_ONLY = _KW_ONLY_TYPE()192 193# Since most per-field metadata will be unused, create an empty194# read-only proxy that can be shared among all fields.195_EMPTY_METADATA = types.MappingProxyType({})196 197# Markers for the various kinds of fields and pseudo-fields.198class _FIELD_BASE:199 def __init__(self, name):200 self.name = name201 def __repr__(self):202 return self.name203_FIELD = _FIELD_BASE('_FIELD')204_FIELD_CLASSVAR = _FIELD_BASE('_FIELD_CLASSVAR')205_FIELD_INITVAR = _FIELD_BASE('_FIELD_INITVAR')206 207# The name of an attribute on the class where we store the Field208# objects. Also used to check if a class is a Data Class.209_FIELDS = '__dataclass_fields__'210 211# The name of an attribute on the class that stores the parameters to212# @dataclass.213_PARAMS = '__dataclass_params__'214 215# The name of the function, that if it exists, is called at the end of216# __init__.217_POST_INIT_NAME = '__post_init__'218 219# String regex that string annotations for ClassVar or InitVar must match.220# Allows "identifier.identifier[" or "identifier[".221# https://bugs.python.org/issue33453 for details.222_MODULE_IDENTIFIER_RE = re.compile(r'^(?:\s*(\w+)\s*\.)?\s*(\w+)')223 224# Atomic immutable types which don't require any recursive handling and for which deepcopy225# returns the same object. We can provide a fast-path for these types in asdict and astuple.226_ATOMIC_TYPES = frozenset({227 # Common JSON Serializable types228 types.NoneType,229 bool,230 int,231 float,232 str,233 # Other common types234 complex,235 bytes,236 # Other types that are also unaffected by deepcopy237 types.EllipsisType,238 types.NotImplementedType,239 types.CodeType,240 types.BuiltinFunctionType,241 types.FunctionType,242 type,243 range,244 property,245})246 247# Any marker is used in `make_dataclass` to mark unannotated fields as `Any`248# without importing `typing` module.249_ANY_MARKER = object()250 251 252class InitVar:253 __slots__ = ('type', )254 255 def __init__(self, type):256 self.type = type257 258 def __repr__(self):259 if isinstance(self.type, type):260 type_name = self.type.__name__261 else:262 # typing objects, e.g. List[int]263 type_name = repr(self.type)264 return f'dataclasses.InitVar[{type_name}]'265 266 def __class_getitem__(cls, type):267 return InitVar(type)268 269# Instances of Field are only ever created from within this module,270# and only from the field() function, although Field instances are271# exposed externally as (conceptually) read-only objects.272#273# name and type are filled in after the fact, not in __init__.274# They're not known at the time this class is instantiated, but it's275# convenient if they're available later.276#277# When cls._FIELDS is filled in with a list of Field objects, the name278# and type fields will have been populated.279class Field:280 __slots__ = ('name',281 'type',282 'default',283 'default_factory',284 'repr',285 'hash',286 'init',287 'compare',288 'metadata',289 'kw_only',290 'doc',291 '_field_type', # Private: not to be used by user code.292 )293 294 def __init__(self, default, default_factory, init, repr, hash, compare,295 metadata, kw_only, doc):296 self.name = None297 self.type = None298 self.default = default299 self.default_factory = default_factory300 self.init = init301 self.repr = repr302 self.hash = hash303 self.compare = compare304 self.metadata = (_EMPTY_METADATA305 if metadata is None else306 types.MappingProxyType(metadata))307 self.kw_only = kw_only308 self.doc = doc309 self._field_type = None310 311 @recursive_repr()312 def __repr__(self):313 return ('Field('314 f'name={self.name!r},'315 f'type={self.type!r},'316 f'default={self.default!r},'317 f'default_factory={self.default_factory!r},'318 f'init={self.init!r},'319 f'repr={self.repr!r},'320 f'hash={self.hash!r},'321 f'compare={self.compare!r},'322 f'metadata={self.metadata!r},'323 f'kw_only={self.kw_only!r},'324 f'doc={self.doc!r},'325 f'_field_type={self._field_type}'326 ')')327 328 # This is used to support the PEP 487 __set_name__ protocol in the329 # case where we're using a field that contains a descriptor as a330 # default value. For details on __set_name__, see331 # https://peps.python.org/pep-0487/#implementation-details.332 #333 # Note that in _process_class, this Field object is overwritten334 # with the default value, so the end result is a descriptor that335 # had __set_name__ called on it at the right time.336 def __set_name__(self, owner, name):337 func = getattr(type(self.default), '__set_name__', None)338 if func:339 # There is a __set_name__ method on the descriptor, call340 # it.341 func(self.default, owner, name)342 343 __class_getitem__ = classmethod(types.GenericAlias)344 345 346class _DataclassParams:347 __slots__ = ('init',348 'repr',349 'eq',350 'order',351 'unsafe_hash',352 'frozen',353 'match_args',354 'kw_only',355 'slots',356 'weakref_slot',357 )358 359 def __init__(self,360 init, repr, eq, order, unsafe_hash, frozen,361 match_args, kw_only, slots, weakref_slot):362 self.init = init363 self.repr = repr364 self.eq = eq365 self.order = order366 self.unsafe_hash = unsafe_hash367 self.frozen = frozen368 self.match_args = match_args369 self.kw_only = kw_only370 self.slots = slots371 self.weakref_slot = weakref_slot372 373 def __repr__(self):374 return ('_DataclassParams('375 f'init={self.init!r},'376 f'repr={self.repr!r},'377 f'eq={self.eq!r},'378 f'order={self.order!r},'379 f'unsafe_hash={self.unsafe_hash!r},'380 f'frozen={self.frozen!r},'381 f'match_args={self.match_args!r},'382 f'kw_only={self.kw_only!r},'383 f'slots={self.slots!r},'384 f'weakref_slot={self.weakref_slot!r}'385 ')')386 387 388# This function is used instead of exposing Field creation directly,389# so that a type checker can be told (via overloads) that this is a390# function whose type depends on its parameters.391def field(*, default=MISSING, default_factory=MISSING, init=True, repr=True,392 hash=None, compare=True, metadata=None, kw_only=MISSING, doc=None):393 """Return an object to identify dataclass fields.394 395 default is the default value of the field. default_factory is a396 0-argument function called to initialize a field's value. If init397 is true, the field will be a parameter to the class's __init__()398 function. If repr is true, the field will be included in the399 object's repr(). If hash is true, the field will be included in the400 object's hash(). If compare is true, the field will be used in401 comparison functions. metadata, if specified, must be a mapping402 which is stored but not otherwise examined by dataclass. If kw_only403 is true, the field will become a keyword-only parameter to404 __init__(). doc is an optional docstring for this field.405 406 It is an error to specify both default and default_factory.407 """408 409 if default is not MISSING and default_factory is not MISSING:410 raise ValueError('cannot specify both default and default_factory')411 return Field(default, default_factory, init, repr, hash, compare,412 metadata, kw_only, doc)413 414 415def _fields_in_init_order(fields):416 # Returns the fields as __init__ will output them. It returns 2 tuples:417 # the first for normal args, and the second for keyword args.418 419 return (tuple(f for f in fields if f.init and not f.kw_only),420 tuple(f for f in fields if f.init and f.kw_only)421 )422 423 424def _tuple_str(obj_name, fields):425 # Return a string representing each field of obj_name as a tuple426 # member. So, if fields is ['x', 'y'] and obj_name is "self",427 # return "(self.x,self.y)".428 429 # Special case for the 0-tuple.430 if not fields:431 return '()'432 # Note the trailing comma, needed if this turns out to be a 1-tuple.433 return f'({",".join([f"{obj_name}.{f.name}" for f in fields])},)'434 435 436class _FuncBuilder:437 def __init__(self, globals):438 self.names = []439 self.src = []440 self.globals = globals441 self.locals = {}442 self.overwrite_errors = {}443 self.unconditional_adds = {}444 self.method_annotations = {}445 446 def add_fn(self, name, args, body, *, locals=None, return_type=MISSING,447 overwrite_error=False, unconditional_add=False, decorator=None,448 annotation_fields=None):449 if locals is not None:450 self.locals.update(locals)451 452 # Keep track if this method is allowed to be overwritten if it already453 # exists in the class. The error is method-specific, so keep it with454 # the name. We'll use this when we generate all of the functions in455 # the add_fns_to_class call. overwrite_error is either True, in which456 # case we'll raise an error, or it's a string, in which case we'll457 # raise an error and append this string.458 if overwrite_error:459 self.overwrite_errors[name] = overwrite_error460 461 # Should this function always overwrite anything that's already in the462 # class? The default is to not overwrite a function that already463 # exists.464 if unconditional_add:465 self.unconditional_adds[name] = True466 467 self.names.append(name)468 469 if annotation_fields is not None:470 self.method_annotations[name] = (annotation_fields, return_type)471 472 args = ','.join(args)473 body = '\n'.join(body)474 475 # Compute the text of the entire function, add it to the text we're generating.476 self.src.append(f'{f' {decorator}\n' if decorator else ''} def {name}({args}):\n{body}')477 478 def add_fns_to_class(self, cls):479 # The source to all of the functions we're generating.480 fns_src = '\n'.join(self.src)481 482 # The locals they use.483 local_vars = ','.join(self.locals.keys())484 485 # The names of all of the functions, used for the return value of the486 # outer function. Need to handle the 0-tuple specially.487 if len(self.names) == 0:488 return_names = '()'489 else:490 return_names =f'({",".join(self.names)},)'491 492 # txt is the entire function we're going to execute, including the493 # bodies of the functions we're defining. Here's a greatly simplified494 # version:495 # def __create_fn__():496 # def __init__(self, x, y):497 # self.x = x498 # self.y = y499 # @recursive_repr500 # def __repr__(self):501 # return f"cls(x={self.x!r},y={self.y!r})"502 # return __init__,__repr__503 504 txt = f"def __create_fn__({local_vars}):\n{fns_src}\n return {return_names}"505 ns = {}506 exec(txt, self.globals, ns)507 fns = ns['__create_fn__'](**self.locals)508 509 # Now that we've generated the functions, assign them into cls.510 for name, fn in zip(self.names, fns):511 fn.__qualname__ = f"{cls.__qualname__}.{fn.__name__}"512 513 try:514 annotation_fields, return_type = self.method_annotations[name]515 except KeyError:516 pass517 else:518 annotate_fn = _make_annotate_function(cls, name, annotation_fields, return_type)519 fn.__annotate__ = annotate_fn520 521 if self.unconditional_adds.get(name, False):522 setattr(cls, name, fn)523 else:524 already_exists = _set_new_attribute(cls, name, fn)525 526 # See if it's an error to overwrite this particular function.527 if already_exists and (msg_extra := self.overwrite_errors.get(name)):528 error_msg = (f'Cannot overwrite attribute {fn.__name__} '529 f'in class {cls.__name__}')530 if not msg_extra is True:531 error_msg = f'{error_msg} {msg_extra}'532 533 raise TypeError(error_msg)534 535 536def _make_annotate_function(__class__, method_name, annotation_fields, return_type):537 # Create an __annotate__ function for a dataclass538 # Try to return annotations in the same format as they would be539 # from a regular __init__ function540 541 def __annotate__(format, /):542 Format = annotationlib.Format543 match format:544 case Format.VALUE | Format.FORWARDREF | Format.STRING:545 cls_annotations = {}546 for base in reversed(__class__.__mro__):547 cls_annotations.update(548 annotationlib.get_annotations(base, format=format)549 )550 551 new_annotations = {}552 for k in annotation_fields:553 # gh-142214: The annotation may be missing in unusual dynamic cases.554 # If so, just skip it.555 try:556 new_annotations[k] = cls_annotations[k]557 except KeyError:558 pass559 560 if return_type is not MISSING:561 if format == Format.STRING:562 new_annotations["return"] = annotationlib.type_repr(return_type)563 else:564 new_annotations["return"] = return_type565 566 return new_annotations567 568 case _:569 raise NotImplementedError(format)570 571 # This is a flag for _add_slots to know it needs to regenerate this method572 # In order to remove references to the original class when it is replaced573 __annotate__.__generated_by_dataclasses__ = True574 __annotate__.__qualname__ = f"{__class__.__qualname__}.{method_name}.__annotate__"575 576 return __annotate__577 578 579def _field_assign(frozen, name, value, self_name):580 # If we're a frozen class, then assign to our fields in __init__581 # via object.__setattr__. Otherwise, just use a simple582 # assignment.583 #584 # self_name is what "self" is called in this function: don't585 # hard-code "self", since that might be a field name.586 if frozen:587 return f' __dataclass_builtins_object__.__setattr__({self_name},{name!r},{value})'588 return f' {self_name}.{name}={value}'589 590 591def _field_init(f, frozen, globals, self_name, slots):592 # Return the text of the line in the body of __init__ that will593 # initialize this field.594 595 default_name = f'__dataclass_dflt_{f.name}__'596 if f.default_factory is not MISSING:597 if f.init:598 # This field has a default factory. If a parameter is599 # given, use it. If not, call the factory.600 globals[default_name] = f.default_factory601 value = (f'{default_name}() '602 f'if {f.name} is __dataclass_HAS_DEFAULT_FACTORY__ '603 f'else {f.name}')604 else:605 # This is a field that's not in the __init__ params, but606 # has a default factory function. It needs to be607 # initialized here by calling the factory function,608 # because there's no other way to initialize it.609 610 # For a field initialized with a default=defaultvalue, the611 # class dict just has the default value612 # (cls.fieldname=defaultvalue). But that won't work for a613 # default factory, the factory must be called in __init__614 # and we must assign that to self.fieldname. We can't615 # fall back to the class dict's value, both because it's616 # not set, and because it might be different per-class617 # (which, after all, is why we have a factory function!).618 619 globals[default_name] = f.default_factory620 value = f'{default_name}()'621 else:622 # No default factory.623 if f.init:624 if f.default is MISSING:625 # There's no default, just do an assignment.626 value = f.name627 elif f.default is not MISSING:628 globals[default_name] = f.default629 value = f.name630 else:631 # If the class has slots, then initialize this field.632 if slots and f.default is not MISSING:633 globals[default_name] = f.default634 value = default_name635 else:636 # This field does not need initialization: reading from it will637 # just use the class attribute that contains the default.638 # Signify that to the caller by returning None.639 return None640 641 # Only test this now, so that we can create variables for the642 # default. However, return None to signify that we're not going643 # to actually do the assignment statement for InitVars.644 if f._field_type is _FIELD_INITVAR:645 return None646 647 # Now, actually generate the field assignment.648 return _field_assign(frozen, f.name, value, self_name)649 650 651def _init_param(f):652 # Return the __init__ parameter string for this field. For653 # example, the equivalent of 'x:int=3' (except instead of 'int',654 # reference a variable set to int, and instead of '3', reference a655 # variable set to 3).656 if f.default is MISSING and f.default_factory is MISSING:657 # There's no default, and no default_factory, just output the658 # variable name and type.659 default = ''660 elif f.default is not MISSING:661 # There's a default, this will be the name that's used to look662 # it up.663 default = f'=__dataclass_dflt_{f.name}__'664 elif f.default_factory is not MISSING:665 # There's a factory function. Set a marker.666 default = '=__dataclass_HAS_DEFAULT_FACTORY__'667 return f'{f.name}{default}'668 669 670def _init_fn(fields, std_fields, kw_only_fields, frozen, has_post_init,671 self_name, func_builder, slots):672 # fields contains both real fields and InitVar pseudo-fields.673 674 # Make sure we don't have fields without defaults following fields675 # with defaults. This actually would be caught when exec-ing the676 # function source code, but catching it here gives a better error677 # message, and future-proofs us in case we build up the function678 # using ast.679 680 seen_default = None681 for f in std_fields:682 # Only consider the non-kw-only fields in the __init__ call.683 if f.init:684 if not (f.default is MISSING and f.default_factory is MISSING):685 seen_default = f686 elif seen_default:687 raise TypeError(f'non-default argument {f.name!r} '688 f'follows default argument {seen_default.name!r}')689 690 annotation_fields = [f.name for f in fields if f.init]691 692 locals = {'__dataclass_HAS_DEFAULT_FACTORY__': _HAS_DEFAULT_FACTORY,693 '__dataclass_builtins_object__': object}694 695 body_lines = []696 for f in fields:697 line = _field_init(f, frozen, locals, self_name, slots)698 # line is None means that this field doesn't require699 # initialization (it's a pseudo-field). Just skip it.700 if line:701 body_lines.append(line)702 703 # Does this class have a post-init function?704 if has_post_init:705 params_str = ','.join(f.name for f in fields706 if f._field_type is _FIELD_INITVAR)707 body_lines.append(f' {self_name}.{_POST_INIT_NAME}({params_str})')708 709 # If no body lines, use 'pass'.710 if not body_lines:711 body_lines = [' pass']712 713 _init_params = [_init_param(f) for f in std_fields]714 if kw_only_fields:715 # Add the keyword-only args. Because the * can only be added if716 # there's at least one keyword-only arg, there needs to be a test here717 # (instead of just concatenating the lists together).718 _init_params += ['*']719 _init_params += [_init_param(f) for f in kw_only_fields]720 func_builder.add_fn('__init__',721 [self_name] + _init_params,722 body_lines,723 locals=locals,724 return_type=None,725 annotation_fields=annotation_fields)726 727 728def _frozen_get_del_attr(cls, fields, func_builder):729 locals = {'cls': cls,730 'FrozenInstanceError': FrozenInstanceError}731 condition = 'type(self) is cls'732 if fields:733 condition += ' or name in {' + ', '.join(repr(f.name) for f in fields) + '}'734 735 func_builder.add_fn('__setattr__',736 ('self', 'name', 'value'),737 (f' if {condition}:',738 ' raise FrozenInstanceError(f"cannot assign to field {name!r}")',739 f' super(cls, self).__setattr__(name, value)'),740 locals=locals,741 overwrite_error=True)742 func_builder.add_fn('__delattr__',743 ('self', 'name'),744 (f' if {condition}:',745 ' raise FrozenInstanceError(f"cannot delete field {name!r}")',746 f' super(cls, self).__delattr__(name)'),747 locals=locals,748 overwrite_error=True)749 750 751def _is_classvar(a_type, typing):752 return (a_type is typing.ClassVar753 or (typing.get_origin(a_type) is typing.ClassVar))754 755 756def _is_initvar(a_type, dataclasses):757 # The module we're checking against is the module we're758 # currently in (dataclasses.py).759 return (a_type is dataclasses.InitVar760 or type(a_type) is dataclasses.InitVar)761 762def _is_kw_only(a_type, dataclasses):763 return a_type is dataclasses.KW_ONLY764 765 766def _is_type(annotation, cls, a_module, a_type, is_type_predicate):767 # Given a type annotation string, does it refer to a_type in768 # a_module? For example, when checking that annotation denotes a769 # ClassVar, then a_module is typing, and a_type is770 # typing.ClassVar.771 772 # It's possible to look up a_module given a_type, but it involves773 # looking in sys.modules (again!), and seems like a waste since774 # the caller already knows a_module.775 776 # - annotation is a string type annotation777 # - cls is the class that this annotation was found in778 # - a_module is the module we want to match779 # - a_type is the type in that module we want to match780 # - is_type_predicate is a function called with (obj, a_module)781 # that determines if obj is of the desired type.782 783 # Since this test does not do a local namespace lookup (and784 # instead only a module (global) lookup), there are some things it785 # gets wrong.786 787 # With string annotations, cv0 will be detected as a ClassVar:788 # CV = ClassVar789 # @dataclass790 # class C0:791 # cv0: CV792 793 # But in this example cv1 will not be detected as a ClassVar:794 # @dataclass795 # class C1:796 # CV = ClassVar797 # cv1: CV798 799 # In C1, the code in this function (_is_type) will look up "CV" in800 # the module and not find it, so it will not consider cv1 as a801 # ClassVar. This is a fairly obscure corner case, and the best802 # way to fix it would be to eval() the string "CV" with the803 # correct global and local namespaces. However that would involve804 # a eval() penalty for every single field of every dataclass805 # that's defined. It was judged not worth it.806 807 match = _MODULE_IDENTIFIER_RE.match(annotation)808 if match:809 ns = None810 module_name = match.group(1)811 if not module_name:812 # No module name, assume the class's module did813 # "from dataclasses import InitVar".814 ns = sys.modules.get(cls.__module__).__dict__815 else:816 # Look up module_name in the class's module.817 module = sys.modules.get(cls.__module__)818 if module and module.__dict__.get(module_name) is a_module:819 ns = sys.modules.get(a_type.__module__).__dict__820 if ns and is_type_predicate(ns.get(match.group(2)), a_module):821 return True822 return False823 824 825def _get_field(cls, a_name, a_type, default_kw_only):826 # Return a Field object for this field name and type. ClassVars and827 # InitVars are also returned, but marked as such (see f._field_type).828 # default_kw_only is the value of kw_only to use if there isn't a field()829 # that defines it.830 831 # If the default value isn't derived from Field, then it's only a832 # normal default value. Convert it to a Field().833 default = getattr(cls, a_name, MISSING)834 if isinstance(default, Field):835 f = default836 else:837 if isinstance(default, types.MemberDescriptorType):838 # This is a field in __slots__, so it has no default value.839 default = MISSING840 f = field(default=default)841 842 # Only at this point do we know the name and the type. Set them.843 f.name = a_name844 f.type = a_type845 846 # Assume it's a normal field until proven otherwise. We're next847 # going to decide if it's a ClassVar or InitVar, everything else848 # is just a normal field.849 f._field_type = _FIELD850 851 # In addition to checking for actual types here, also check for852 # string annotations. get_type_hints() won't always work for us853 # (see https://github.com/python/typing/issues/508 for example),854 # plus it's expensive and would require an eval for every string855 # annotation. So, make a best effort to see if this is a ClassVar856 # or InitVar using regex's and checking that the thing referenced857 # is actually of the correct type.858 859 # For the complete discussion, see https://bugs.python.org/issue33453860 861 # If typing has not been imported, then it's impossible for any862 # annotation to be a ClassVar. So, only look for ClassVar if863 # typing has been imported by any module (not necessarily cls's864 # module).865 typing = sys.modules.get('typing')866 if typing:867 if (_is_classvar(a_type, typing)868 or (isinstance(f.type, str)869 and _is_type(f.type, cls, typing, typing.ClassVar,870 _is_classvar))):871 f._field_type = _FIELD_CLASSVAR872 873 # If the type is InitVar, or if it's a matching string annotation,874 # then it's an InitVar.875 if f._field_type is _FIELD:876 # The module we're checking against is the module we're877 # currently in (dataclasses.py).878 dataclasses = sys.modules[__name__]879 if (_is_initvar(a_type, dataclasses)880 or (isinstance(f.type, str)881 and _is_type(f.type, cls, dataclasses, dataclasses.InitVar,882 _is_initvar))):883 f._field_type = _FIELD_INITVAR884 885 # Validations for individual fields. This is delayed until now,886 # instead of in the Field() constructor, since only here do we887 # know the field name, which allows for better error reporting.888 889 # Special restrictions for ClassVar and InitVar.890 if f._field_type in (_FIELD_CLASSVAR, _FIELD_INITVAR):891 if f.default_factory is not MISSING:892 raise TypeError(f'field {f.name} cannot have a '893 'default factory')894 # Should I check for other field settings? default_factory895 # seems the most serious to check for. Maybe add others. For896 # example, how about init=False (or really,897 # init=<not-the-default-init-value>)? It makes no sense for898 # ClassVar and InitVar to specify init=<anything>.899 900 # kw_only validation and assignment.901 if f._field_type in (_FIELD, _FIELD_INITVAR):902 # For real and InitVar fields, if kw_only wasn't specified use the903 # default value.904 if f.kw_only is MISSING:905 f.kw_only = default_kw_only906 else:907 # Make sure kw_only isn't set for ClassVars908 assert f._field_type is _FIELD_CLASSVAR909 if f.kw_only is not MISSING:910 raise TypeError(f'field {f.name} is a ClassVar but specifies '911 'kw_only')912 913 # For real fields, disallow mutable defaults. Use unhashable as a proxy914 # indicator for mutability. Read the __hash__ attribute from the class,915 # not the instance.916 if f._field_type is _FIELD and f.default.__class__.__hash__ is None:917 raise ValueError(f'mutable default {type(f.default)} for field '918 f'{f.name} is not allowed: use default_factory')919 920 return f921 922def _set_new_attribute(cls, name, value):923 # Never overwrites an existing attribute. Returns True if the924 # attribute already exists.925 if name in cls.__dict__:926 return True927 setattr(cls, name, value)928 return False929 930 931# Decide if/how we're going to create a hash function. Key is932# (unsafe_hash, eq, frozen, does-hash-exist). Value is the action to933# take. The common case is to do nothing, so instead of providing a934# function that is a no-op, use None to signify that.935 936def _hash_set_none(cls, fields, func_builder):937 # It's sort of a hack that I'm setting this here, instead of at938 # func_builder.add_fns_to_class time, but since this is an exceptional case939 # (it's not setting an attribute to a function, but to a scalar value),940 # just do it directly here. I might come to regret this.941 cls.__hash__ = None942 943def _hash_add(cls, fields, func_builder):944 flds = [f for f in fields if (f.compare if f.hash is None else f.hash)]945 self_tuple = _tuple_str('self', flds)946 func_builder.add_fn('__hash__',947 ('self',),948 [f' return hash({self_tuple})'],949 unconditional_add=True)950 951def _hash_exception(cls, fields, func_builder):952 # Raise an exception.953 raise TypeError(f'Cannot overwrite attribute __hash__ '954 f'in class {cls.__name__}')955 956#957# +-------------------------------------- unsafe_hash?958# | +------------------------------- eq?959# | | +------------------------ frozen?960# | | | +---------------- has-explicit-hash?961# | | | |962# | | | | +------- action963# | | | | |964# v v v v v965_hash_action = {(False, False, False, False): None,966 (False, False, False, True ): None,967 (False, False, True, False): None,968 (False, False, True, True ): None,969 (False, True, False, False): _hash_set_none,970 (False, True, False, True ): None,971 (False, True, True, False): _hash_add,972 (False, True, True, True ): None,973 (True, False, False, False): _hash_add,974 (True, False, False, True ): _hash_exception,975 (True, False, True, False): _hash_add,976 (True, False, True, True ): _hash_exception,977 (True, True, False, False): _hash_add,978 (True, True, False, True ): _hash_exception,979 (True, True, True, False): _hash_add,980 (True, True, True, True ): _hash_exception,981 }982# See https://bugs.python.org/issue32929#msg312829 for an if-statement983# version of this table.984 985 986def _process_class(cls, init, repr, eq, order, unsafe_hash, frozen,987 match_args, kw_only, slots, weakref_slot):988 # Now that dicts retain insertion order, there's no reason to use989 # an ordered dict. I am leveraging that ordering here, because990 # derived class fields overwrite base class fields, but the order991 # is defined by the base class, which is found first.992 fields = {}993 994 if cls.__module__ in sys.modules:995 globals = sys.modules[cls.__module__].__dict__996 else:997 # Theoretically this can happen if someone writes998 # a custom string to cls.__module__. In which case999 # such dataclass won't be fully introspectable1000 # (w.r.t. typing.get_type_hints) but will still function1001 # correctly.1002 globals = {}1003 1004 setattr(cls, _PARAMS, _DataclassParams(init, repr, eq, order,1005 unsafe_hash, frozen,1006 match_args, kw_only,1007 slots, weakref_slot))1008 1009 # Find our base classes in reverse MRO order, and exclude1010 # ourselves. In reversed order so that more derived classes1011 # override earlier field definitions in base classes. As long as1012 # we're iterating over them, see if all or any of them are frozen.1013 any_frozen_base = False1014 # By default `all_frozen_bases` is `None` to represent a case,1015 # where some dataclasses does not have any bases with `_FIELDS`1016 all_frozen_bases = None1017 has_dataclass_bases = False1018 for b in cls.__mro__[-1:0:-1]:1019 # Only process classes that have been processed by our1020 # decorator. That is, they have a _FIELDS attribute.1021 base_fields = getattr(b, _FIELDS, None)1022 if base_fields is not None:1023 has_dataclass_bases = True1024 for f in base_fields.values():1025 fields[f.name] = f1026 if all_frozen_bases is None:1027 all_frozen_bases = True1028 current_frozen = getattr(b, _PARAMS).frozen1029 all_frozen_bases = all_frozen_bases and current_frozen1030 any_frozen_base = any_frozen_base or current_frozen1031 1032 # Annotations defined specifically in this class (not in base classes).1033 #1034 # Fields are found from cls_annotations, which is guaranteed to be1035 # ordered. Default values are from class attributes, if a field1036 # has a default. If the default value is a Field(), then it1037 # contains additional info beyond (and possibly including) the1038 # actual default value. Pseudo-fields ClassVars and InitVars are1039 # included, despite the fact that they're not real fields. That's1040 # dealt with later.1041 cls_annotations = annotationlib.get_annotations(1042 cls, format=annotationlib.Format.FORWARDREF)1043 1044 # Now find fields in our class. While doing so, validate some1045 # things, and set the default values (as class attributes) where1046 # we can.1047 cls_fields = []1048 # Get a reference to this module for the _is_kw_only() test.1049 KW_ONLY_seen = False1050 dataclasses = sys.modules[__name__]1051 for name, type in cls_annotations.items():1052 # See if this is a marker to change the value of kw_only.1053 if (_is_kw_only(type, dataclasses)1054 or (isinstance(type, str)1055 and _is_type(type, cls, dataclasses, dataclasses.KW_ONLY,1056 _is_kw_only))):1057 # Switch the default to kw_only=True, and ignore this1058 # annotation: it's not a real field.1059 if KW_ONLY_seen:1060 raise TypeError(f'{name!r} is KW_ONLY, but KW_ONLY '1061 'has already been specified')1062 KW_ONLY_seen = True1063 kw_only = True1064 else:1065 # Otherwise it's a field of some type.1066 cls_fields.append(_get_field(cls, name, type, kw_only))1067 1068 for f in cls_fields:1069 fields[f.name] = f1070 1071 # If the class attribute (which is the default value for this1072 # field) exists and is of type 'Field', replace it with the1073 # real default. This is so that normal class introspection1074 # sees a real default value, not a Field.1075 if isinstance(getattr(cls, f.name, None), Field):1076 if f.default is MISSING:1077 # If there's no default, delete the class attribute.1078 # This happens if we specify field(repr=False), for1079 # example (that is, we specified a field object, but1080 # no default value). Also if we're using a default1081 # factory. The class attribute should not be set at1082 # all in the post-processed class.1083 delattr(cls, f.name)1084 else:1085 setattr(cls, f.name, f.default)1086 1087 # Do we have any Field members that don't also have annotations?1088 for name, value in cls.__dict__.items():1089 if isinstance(value, Field) and not name in cls_annotations:1090 raise TypeError(f'{name!r} is a field but has no type annotation')1091 1092 # Check rules that apply if we are derived from any dataclasses.1093 if has_dataclass_bases:1094 # Raise an exception if any of our bases are frozen, but we're not.1095 if any_frozen_base and not frozen:1096 raise TypeError('cannot inherit non-frozen dataclass from a '1097 'frozen one')1098 1099 # Raise an exception if we're frozen, but none of our bases are.1100 if all_frozen_bases is False and frozen:1101 raise TypeError('cannot inherit frozen dataclass from a '1102 'non-frozen one')1103 1104 # Remember all of the fields on our class (including bases). This1105 # also marks this class as being a dataclass.1106 setattr(cls, _FIELDS, fields)1107 1108 # Was this class defined with an explicit __hash__? Note that if1109 # __eq__ is defined in this class, then python will automatically1110 # set __hash__ to None. This is a heuristic, as it's possible1111 # that such a __hash__ == None was not auto-generated, but it's1112 # close enough.1113 class_hash = cls.__dict__.get('__hash__', MISSING)1114 has_explicit_hash = not (class_hash is MISSING or1115 (class_hash is None and '__eq__' in cls.__dict__))1116 1117 # If we're generating ordering methods, we must be generating the1118 # eq methods.1119 if order and not eq:1120 raise ValueError('eq must be true if order is true')1121 1122 # Include InitVars and regular fields (so, not ClassVars). This is1123 # initialized here, outside of the "if init:" test, because std_init_fields1124 # is used with match_args, below.1125 all_init_fields = [f for f in fields.values()1126 if f._field_type in (_FIELD, _FIELD_INITVAR)]1127 (std_init_fields,1128 kw_only_init_fields) = _fields_in_init_order(all_init_fields)1129 1130 func_builder = _FuncBuilder(globals)1131 1132 if init:1133 # Does this class have a post-init function?1134 has_post_init = hasattr(cls, _POST_INIT_NAME)1135 1136 _init_fn(all_init_fields,1137 std_init_fields,1138 kw_only_init_fields,1139 frozen,1140 has_post_init,1141 # The name to use for the "self"1142 # param in __init__. Use "self"1143 # if possible.1144 '__dataclass_self__' if 'self' in fields1145 else 'self',1146 func_builder,1147 slots,1148 )1149 1150 _set_new_attribute(cls, '__replace__', _replace)1151 1152 # Get the fields as a list, and include only real fields. This is1153 # used in all of the following methods.1154 field_list = [f for f in fields.values() if f._field_type is _FIELD]1155 1156 if repr:1157 flds = [f for f in field_list if f.repr]1158 func_builder.add_fn('__repr__',1159 ('self',),1160 [' return f"{self.__class__.__qualname__}(' +1161 ', '.join([f"{f.name}={{self.{f.name}!r}}"1162 for f in flds]) + ')"'],1163 locals={'__dataclasses_recursive_repr': recursive_repr},1164 decorator="@__dataclasses_recursive_repr()")1165 1166 if eq:1167 # Create __eq__ method. There's no need for a __ne__ method,1168 # since python will call __eq__ and negate it.1169 cmp_fields = (field for field in field_list if field.compare)1170 terms = [f'self.{field.name}==other.{field.name}' for field in cmp_fields]1171 field_comparisons = ' and '.join(terms) or 'True'1172 func_builder.add_fn('__eq__',1173 ('self', 'other'),1174 [ ' if self is other:',1175 ' return True',1176 ' if other.__class__ is self.__class__:',1177 f' return {field_comparisons}',1178 ' return NotImplemented'])1179 1180 if order:1181 # Create and set the ordering methods.1182 flds = [f for f in field_list if f.compare]1183 self_tuple = _tuple_str('self', flds)1184 other_tuple = _tuple_str('other', flds)1185 for name, op in [('__lt__', '<'),1186 ('__le__', '<='),1187 ('__gt__', '>'),1188 ('__ge__', '>='),1189 ]:1190 # Create a comparison function. If the fields in the object are1191 # named 'x' and 'y', then self_tuple is the string1192 # '(self.x,self.y)' and other_tuple is the string1193 # '(other.x,other.y)'.1194 func_builder.add_fn(name,1195 ('self', 'other'),1196 [ ' if other.__class__ is self.__class__:',1197 f' return {self_tuple}{op}{other_tuple}',1198 ' return NotImplemented'],1199 overwrite_error='Consider using functools.total_ordering')1200 