17db96d56Sopenharmony_ciimport re
27db96d56Sopenharmony_ciimport sys
37db96d56Sopenharmony_ciimport copy
47db96d56Sopenharmony_ciimport types
57db96d56Sopenharmony_ciimport inspect
67db96d56Sopenharmony_ciimport keyword
77db96d56Sopenharmony_ciimport builtins
87db96d56Sopenharmony_ciimport functools
97db96d56Sopenharmony_ciimport itertools
107db96d56Sopenharmony_ciimport abc
117db96d56Sopenharmony_ciimport _thread
127db96d56Sopenharmony_cifrom types import FunctionType, GenericAlias
137db96d56Sopenharmony_ci
147db96d56Sopenharmony_ci
157db96d56Sopenharmony_ci__all__ = ['dataclass',
167db96d56Sopenharmony_ci           'field',
177db96d56Sopenharmony_ci           'Field',
187db96d56Sopenharmony_ci           'FrozenInstanceError',
197db96d56Sopenharmony_ci           'InitVar',
207db96d56Sopenharmony_ci           'KW_ONLY',
217db96d56Sopenharmony_ci           'MISSING',
227db96d56Sopenharmony_ci
237db96d56Sopenharmony_ci           # Helper functions.
247db96d56Sopenharmony_ci           'fields',
257db96d56Sopenharmony_ci           'asdict',
267db96d56Sopenharmony_ci           'astuple',
277db96d56Sopenharmony_ci           'make_dataclass',
287db96d56Sopenharmony_ci           'replace',
297db96d56Sopenharmony_ci           'is_dataclass',
307db96d56Sopenharmony_ci           ]
317db96d56Sopenharmony_ci
327db96d56Sopenharmony_ci# Conditions for adding methods.  The boxes indicate what action the
337db96d56Sopenharmony_ci# dataclass decorator takes.  For all of these tables, when I talk
347db96d56Sopenharmony_ci# about init=, repr=, eq=, order=, unsafe_hash=, or frozen=, I'm
357db96d56Sopenharmony_ci# referring to the arguments to the @dataclass decorator.  When
367db96d56Sopenharmony_ci# checking if a dunder method already exists, I mean check for an
377db96d56Sopenharmony_ci# entry in the class's __dict__.  I never check to see if an attribute
387db96d56Sopenharmony_ci# is defined in a base class.
397db96d56Sopenharmony_ci
407db96d56Sopenharmony_ci# Key:
417db96d56Sopenharmony_ci# +=========+=========================================+
427db96d56Sopenharmony_ci# + Value   | Meaning                                 |
437db96d56Sopenharmony_ci# +=========+=========================================+
447db96d56Sopenharmony_ci# | <blank> | No action: no method is added.          |
457db96d56Sopenharmony_ci# +---------+-----------------------------------------+
467db96d56Sopenharmony_ci# | add     | Generated method is added.              |
477db96d56Sopenharmony_ci# +---------+-----------------------------------------+
487db96d56Sopenharmony_ci# | raise   | TypeError is raised.                    |
497db96d56Sopenharmony_ci# +---------+-----------------------------------------+
507db96d56Sopenharmony_ci# | None    | Attribute is set to None.               |
517db96d56Sopenharmony_ci# +=========+=========================================+
527db96d56Sopenharmony_ci
537db96d56Sopenharmony_ci# __init__
547db96d56Sopenharmony_ci#
557db96d56Sopenharmony_ci#   +--- init= parameter
567db96d56Sopenharmony_ci#   |
577db96d56Sopenharmony_ci#   v     |       |       |
587db96d56Sopenharmony_ci#         |  no   |  yes  |  <--- class has __init__ in __dict__?
597db96d56Sopenharmony_ci# +=======+=======+=======+
607db96d56Sopenharmony_ci# | False |       |       |
617db96d56Sopenharmony_ci# +-------+-------+-------+
627db96d56Sopenharmony_ci# | True  | add   |       |  <- the default
637db96d56Sopenharmony_ci# +=======+=======+=======+
647db96d56Sopenharmony_ci
657db96d56Sopenharmony_ci# __repr__
667db96d56Sopenharmony_ci#
677db96d56Sopenharmony_ci#    +--- repr= parameter
687db96d56Sopenharmony_ci#    |
697db96d56Sopenharmony_ci#    v    |       |       |
707db96d56Sopenharmony_ci#         |  no   |  yes  |  <--- class has __repr__ in __dict__?
717db96d56Sopenharmony_ci# +=======+=======+=======+
727db96d56Sopenharmony_ci# | False |       |       |
737db96d56Sopenharmony_ci# +-------+-------+-------+
747db96d56Sopenharmony_ci# | True  | add   |       |  <- the default
757db96d56Sopenharmony_ci# +=======+=======+=======+
767db96d56Sopenharmony_ci
777db96d56Sopenharmony_ci
787db96d56Sopenharmony_ci# __setattr__
797db96d56Sopenharmony_ci# __delattr__
807db96d56Sopenharmony_ci#
817db96d56Sopenharmony_ci#    +--- frozen= parameter
827db96d56Sopenharmony_ci#    |
837db96d56Sopenharmony_ci#    v    |       |       |
847db96d56Sopenharmony_ci#         |  no   |  yes  |  <--- class has __setattr__ or __delattr__ in __dict__?
857db96d56Sopenharmony_ci# +=======+=======+=======+
867db96d56Sopenharmony_ci# | False |       |       |  <- the default
877db96d56Sopenharmony_ci# +-------+-------+-------+
887db96d56Sopenharmony_ci# | True  | add   | raise |
897db96d56Sopenharmony_ci# +=======+=======+=======+
907db96d56Sopenharmony_ci# Raise because not adding these methods would break the "frozen-ness"
917db96d56Sopenharmony_ci# of the class.
927db96d56Sopenharmony_ci
937db96d56Sopenharmony_ci# __eq__
947db96d56Sopenharmony_ci#
957db96d56Sopenharmony_ci#    +--- eq= parameter
967db96d56Sopenharmony_ci#    |
977db96d56Sopenharmony_ci#    v    |       |       |
987db96d56Sopenharmony_ci#         |  no   |  yes  |  <--- class has __eq__ in __dict__?
997db96d56Sopenharmony_ci# +=======+=======+=======+
1007db96d56Sopenharmony_ci# | False |       |       |
1017db96d56Sopenharmony_ci# +-------+-------+-------+
1027db96d56Sopenharmony_ci# | True  | add   |       |  <- the default
1037db96d56Sopenharmony_ci# +=======+=======+=======+
1047db96d56Sopenharmony_ci
1057db96d56Sopenharmony_ci# __lt__
1067db96d56Sopenharmony_ci# __le__
1077db96d56Sopenharmony_ci# __gt__
1087db96d56Sopenharmony_ci# __ge__
1097db96d56Sopenharmony_ci#
1107db96d56Sopenharmony_ci#    +--- order= parameter
1117db96d56Sopenharmony_ci#    |
1127db96d56Sopenharmony_ci#    v    |       |       |
1137db96d56Sopenharmony_ci#         |  no   |  yes  |  <--- class has any comparison method in __dict__?
1147db96d56Sopenharmony_ci# +=======+=======+=======+
1157db96d56Sopenharmony_ci# | False |       |       |  <- the default
1167db96d56Sopenharmony_ci# +-------+-------+-------+
1177db96d56Sopenharmony_ci# | True  | add   | raise |
1187db96d56Sopenharmony_ci# +=======+=======+=======+
1197db96d56Sopenharmony_ci# Raise because to allow this case would interfere with using
1207db96d56Sopenharmony_ci# functools.total_ordering.
1217db96d56Sopenharmony_ci
1227db96d56Sopenharmony_ci# __hash__
1237db96d56Sopenharmony_ci
1247db96d56Sopenharmony_ci#    +------------------- unsafe_hash= parameter
1257db96d56Sopenharmony_ci#    |       +----------- eq= parameter
1267db96d56Sopenharmony_ci#    |       |       +--- frozen= parameter
1277db96d56Sopenharmony_ci#    |       |       |
1287db96d56Sopenharmony_ci#    v       v       v    |        |        |
1297db96d56Sopenharmony_ci#                         |   no   |  yes   |  <--- class has explicitly defined __hash__
1307db96d56Sopenharmony_ci# +=======+=======+=======+========+========+
1317db96d56Sopenharmony_ci# | False | False | False |        |        | No __eq__, use the base class __hash__
1327db96d56Sopenharmony_ci# +-------+-------+-------+--------+--------+
1337db96d56Sopenharmony_ci# | False | False | True  |        |        | No __eq__, use the base class __hash__
1347db96d56Sopenharmony_ci# +-------+-------+-------+--------+--------+
1357db96d56Sopenharmony_ci# | False | True  | False | None   |        | <-- the default, not hashable
1367db96d56Sopenharmony_ci# +-------+-------+-------+--------+--------+
1377db96d56Sopenharmony_ci# | False | True  | True  | add    |        | Frozen, so hashable, allows override
1387db96d56Sopenharmony_ci# +-------+-------+-------+--------+--------+
1397db96d56Sopenharmony_ci# | True  | False | False | add    | raise  | Has no __eq__, but hashable
1407db96d56Sopenharmony_ci# +-------+-------+-------+--------+--------+
1417db96d56Sopenharmony_ci# | True  | False | True  | add    | raise  | Has no __eq__, but hashable
1427db96d56Sopenharmony_ci# +-------+-------+-------+--------+--------+
1437db96d56Sopenharmony_ci# | True  | True  | False | add    | raise  | Not frozen, but hashable
1447db96d56Sopenharmony_ci# +-------+-------+-------+--------+--------+
1457db96d56Sopenharmony_ci# | True  | True  | True  | add    | raise  | Frozen, so hashable
1467db96d56Sopenharmony_ci# +=======+=======+=======+========+========+
1477db96d56Sopenharmony_ci# For boxes that are blank, __hash__ is untouched and therefore
1487db96d56Sopenharmony_ci# inherited from the base class.  If the base is object, then
1497db96d56Sopenharmony_ci# id-based hashing is used.
1507db96d56Sopenharmony_ci#
1517db96d56Sopenharmony_ci# Note that a class may already have __hash__=None if it specified an
1527db96d56Sopenharmony_ci# __eq__ method in the class body (not one that was created by
1537db96d56Sopenharmony_ci# @dataclass).
1547db96d56Sopenharmony_ci#
1557db96d56Sopenharmony_ci# See _hash_action (below) for a coded version of this table.
1567db96d56Sopenharmony_ci
1577db96d56Sopenharmony_ci# __match_args__
1587db96d56Sopenharmony_ci#
1597db96d56Sopenharmony_ci#    +--- match_args= parameter
1607db96d56Sopenharmony_ci#    |
1617db96d56Sopenharmony_ci#    v    |       |       |
1627db96d56Sopenharmony_ci#         |  no   |  yes  |  <--- class has __match_args__ in __dict__?
1637db96d56Sopenharmony_ci# +=======+=======+=======+
1647db96d56Sopenharmony_ci# | False |       |       |
1657db96d56Sopenharmony_ci# +-------+-------+-------+
1667db96d56Sopenharmony_ci# | True  | add   |       |  <- the default
1677db96d56Sopenharmony_ci# +=======+=======+=======+
1687db96d56Sopenharmony_ci# __match_args__ is always added unless the class already defines it. It is a
1697db96d56Sopenharmony_ci# tuple of __init__ parameter names; non-init fields must be matched by keyword.
1707db96d56Sopenharmony_ci
1717db96d56Sopenharmony_ci
1727db96d56Sopenharmony_ci# Raised when an attempt is made to modify a frozen class.
1737db96d56Sopenharmony_ciclass FrozenInstanceError(AttributeError): pass
1747db96d56Sopenharmony_ci
1757db96d56Sopenharmony_ci# A sentinel object for default values to signal that a default
1767db96d56Sopenharmony_ci# factory will be used.  This is given a nice repr() which will appear
1777db96d56Sopenharmony_ci# in the function signature of dataclasses' constructors.
1787db96d56Sopenharmony_ciclass _HAS_DEFAULT_FACTORY_CLASS:
1797db96d56Sopenharmony_ci    def __repr__(self):
1807db96d56Sopenharmony_ci        return '<factory>'
1817db96d56Sopenharmony_ci_HAS_DEFAULT_FACTORY = _HAS_DEFAULT_FACTORY_CLASS()
1827db96d56Sopenharmony_ci
1837db96d56Sopenharmony_ci# A sentinel object to detect if a parameter is supplied or not.  Use
1847db96d56Sopenharmony_ci# a class to give it a better repr.
1857db96d56Sopenharmony_ciclass _MISSING_TYPE:
1867db96d56Sopenharmony_ci    pass
1877db96d56Sopenharmony_ciMISSING = _MISSING_TYPE()
1887db96d56Sopenharmony_ci
1897db96d56Sopenharmony_ci# A sentinel object to indicate that following fields are keyword-only by
1907db96d56Sopenharmony_ci# default.  Use a class to give it a better repr.
1917db96d56Sopenharmony_ciclass _KW_ONLY_TYPE:
1927db96d56Sopenharmony_ci    pass
1937db96d56Sopenharmony_ciKW_ONLY = _KW_ONLY_TYPE()
1947db96d56Sopenharmony_ci
1957db96d56Sopenharmony_ci# Since most per-field metadata will be unused, create an empty
1967db96d56Sopenharmony_ci# read-only proxy that can be shared among all fields.
1977db96d56Sopenharmony_ci_EMPTY_METADATA = types.MappingProxyType({})
1987db96d56Sopenharmony_ci
1997db96d56Sopenharmony_ci# Markers for the various kinds of fields and pseudo-fields.
2007db96d56Sopenharmony_ciclass _FIELD_BASE:
2017db96d56Sopenharmony_ci    def __init__(self, name):
2027db96d56Sopenharmony_ci        self.name = name
2037db96d56Sopenharmony_ci    def __repr__(self):
2047db96d56Sopenharmony_ci        return self.name
2057db96d56Sopenharmony_ci_FIELD = _FIELD_BASE('_FIELD')
2067db96d56Sopenharmony_ci_FIELD_CLASSVAR = _FIELD_BASE('_FIELD_CLASSVAR')
2077db96d56Sopenharmony_ci_FIELD_INITVAR = _FIELD_BASE('_FIELD_INITVAR')
2087db96d56Sopenharmony_ci
2097db96d56Sopenharmony_ci# The name of an attribute on the class where we store the Field
2107db96d56Sopenharmony_ci# objects.  Also used to check if a class is a Data Class.
2117db96d56Sopenharmony_ci_FIELDS = '__dataclass_fields__'
2127db96d56Sopenharmony_ci
2137db96d56Sopenharmony_ci# The name of an attribute on the class that stores the parameters to
2147db96d56Sopenharmony_ci# @dataclass.
2157db96d56Sopenharmony_ci_PARAMS = '__dataclass_params__'
2167db96d56Sopenharmony_ci
2177db96d56Sopenharmony_ci# The name of the function, that if it exists, is called at the end of
2187db96d56Sopenharmony_ci# __init__.
2197db96d56Sopenharmony_ci_POST_INIT_NAME = '__post_init__'
2207db96d56Sopenharmony_ci
2217db96d56Sopenharmony_ci# String regex that string annotations for ClassVar or InitVar must match.
2227db96d56Sopenharmony_ci# Allows "identifier.identifier[" or "identifier[".
2237db96d56Sopenharmony_ci# https://bugs.python.org/issue33453 for details.
2247db96d56Sopenharmony_ci_MODULE_IDENTIFIER_RE = re.compile(r'^(?:\s*(\w+)\s*\.)?\s*(\w+)')
2257db96d56Sopenharmony_ci
2267db96d56Sopenharmony_ci# This function's logic is copied from "recursive_repr" function in
2277db96d56Sopenharmony_ci# reprlib module to avoid dependency.
2287db96d56Sopenharmony_cidef _recursive_repr(user_function):
2297db96d56Sopenharmony_ci    # Decorator to make a repr function return "..." for a recursive
2307db96d56Sopenharmony_ci    # call.
2317db96d56Sopenharmony_ci    repr_running = set()
2327db96d56Sopenharmony_ci
2337db96d56Sopenharmony_ci    @functools.wraps(user_function)
2347db96d56Sopenharmony_ci    def wrapper(self):
2357db96d56Sopenharmony_ci        key = id(self), _thread.get_ident()
2367db96d56Sopenharmony_ci        if key in repr_running:
2377db96d56Sopenharmony_ci            return '...'
2387db96d56Sopenharmony_ci        repr_running.add(key)
2397db96d56Sopenharmony_ci        try:
2407db96d56Sopenharmony_ci            result = user_function(self)
2417db96d56Sopenharmony_ci        finally:
2427db96d56Sopenharmony_ci            repr_running.discard(key)
2437db96d56Sopenharmony_ci        return result
2447db96d56Sopenharmony_ci    return wrapper
2457db96d56Sopenharmony_ci
2467db96d56Sopenharmony_ciclass InitVar:
2477db96d56Sopenharmony_ci    __slots__ = ('type', )
2487db96d56Sopenharmony_ci
2497db96d56Sopenharmony_ci    def __init__(self, type):
2507db96d56Sopenharmony_ci        self.type = type
2517db96d56Sopenharmony_ci
2527db96d56Sopenharmony_ci    def __repr__(self):
2537db96d56Sopenharmony_ci        if isinstance(self.type, type):
2547db96d56Sopenharmony_ci            type_name = self.type.__name__
2557db96d56Sopenharmony_ci        else:
2567db96d56Sopenharmony_ci            # typing objects, e.g. List[int]
2577db96d56Sopenharmony_ci            type_name = repr(self.type)
2587db96d56Sopenharmony_ci        return f'dataclasses.InitVar[{type_name}]'
2597db96d56Sopenharmony_ci
2607db96d56Sopenharmony_ci    def __class_getitem__(cls, type):
2617db96d56Sopenharmony_ci        return InitVar(type)
2627db96d56Sopenharmony_ci
2637db96d56Sopenharmony_ci# Instances of Field are only ever created from within this module,
2647db96d56Sopenharmony_ci# and only from the field() function, although Field instances are
2657db96d56Sopenharmony_ci# exposed externally as (conceptually) read-only objects.
2667db96d56Sopenharmony_ci#
2677db96d56Sopenharmony_ci# name and type are filled in after the fact, not in __init__.
2687db96d56Sopenharmony_ci# They're not known at the time this class is instantiated, but it's
2697db96d56Sopenharmony_ci# convenient if they're available later.
2707db96d56Sopenharmony_ci#
2717db96d56Sopenharmony_ci# When cls._FIELDS is filled in with a list of Field objects, the name
2727db96d56Sopenharmony_ci# and type fields will have been populated.
2737db96d56Sopenharmony_ciclass Field:
2747db96d56Sopenharmony_ci    __slots__ = ('name',
2757db96d56Sopenharmony_ci                 'type',
2767db96d56Sopenharmony_ci                 'default',
2777db96d56Sopenharmony_ci                 'default_factory',
2787db96d56Sopenharmony_ci                 'repr',
2797db96d56Sopenharmony_ci                 'hash',
2807db96d56Sopenharmony_ci                 'init',
2817db96d56Sopenharmony_ci                 'compare',
2827db96d56Sopenharmony_ci                 'metadata',
2837db96d56Sopenharmony_ci                 'kw_only',
2847db96d56Sopenharmony_ci                 '_field_type',  # Private: not to be used by user code.
2857db96d56Sopenharmony_ci                 )
2867db96d56Sopenharmony_ci
2877db96d56Sopenharmony_ci    def __init__(self, default, default_factory, init, repr, hash, compare,
2887db96d56Sopenharmony_ci                 metadata, kw_only):
2897db96d56Sopenharmony_ci        self.name = None
2907db96d56Sopenharmony_ci        self.type = None
2917db96d56Sopenharmony_ci        self.default = default
2927db96d56Sopenharmony_ci        self.default_factory = default_factory
2937db96d56Sopenharmony_ci        self.init = init
2947db96d56Sopenharmony_ci        self.repr = repr
2957db96d56Sopenharmony_ci        self.hash = hash
2967db96d56Sopenharmony_ci        self.compare = compare
2977db96d56Sopenharmony_ci        self.metadata = (_EMPTY_METADATA
2987db96d56Sopenharmony_ci                         if metadata is None else
2997db96d56Sopenharmony_ci                         types.MappingProxyType(metadata))
3007db96d56Sopenharmony_ci        self.kw_only = kw_only
3017db96d56Sopenharmony_ci        self._field_type = None
3027db96d56Sopenharmony_ci
3037db96d56Sopenharmony_ci    @_recursive_repr
3047db96d56Sopenharmony_ci    def __repr__(self):
3057db96d56Sopenharmony_ci        return ('Field('
3067db96d56Sopenharmony_ci                f'name={self.name!r},'
3077db96d56Sopenharmony_ci                f'type={self.type!r},'
3087db96d56Sopenharmony_ci                f'default={self.default!r},'
3097db96d56Sopenharmony_ci                f'default_factory={self.default_factory!r},'
3107db96d56Sopenharmony_ci                f'init={self.init!r},'
3117db96d56Sopenharmony_ci                f'repr={self.repr!r},'
3127db96d56Sopenharmony_ci                f'hash={self.hash!r},'
3137db96d56Sopenharmony_ci                f'compare={self.compare!r},'
3147db96d56Sopenharmony_ci                f'metadata={self.metadata!r},'
3157db96d56Sopenharmony_ci                f'kw_only={self.kw_only!r},'
3167db96d56Sopenharmony_ci                f'_field_type={self._field_type}'
3177db96d56Sopenharmony_ci                ')')
3187db96d56Sopenharmony_ci
3197db96d56Sopenharmony_ci    # This is used to support the PEP 487 __set_name__ protocol in the
3207db96d56Sopenharmony_ci    # case where we're using a field that contains a descriptor as a
3217db96d56Sopenharmony_ci    # default value.  For details on __set_name__, see
3227db96d56Sopenharmony_ci    # https://peps.python.org/pep-0487/#implementation-details.
3237db96d56Sopenharmony_ci    #
3247db96d56Sopenharmony_ci    # Note that in _process_class, this Field object is overwritten
3257db96d56Sopenharmony_ci    # with the default value, so the end result is a descriptor that
3267db96d56Sopenharmony_ci    # had __set_name__ called on it at the right time.
3277db96d56Sopenharmony_ci    def __set_name__(self, owner, name):
3287db96d56Sopenharmony_ci        func = getattr(type(self.default), '__set_name__', None)
3297db96d56Sopenharmony_ci        if func:
3307db96d56Sopenharmony_ci            # There is a __set_name__ method on the descriptor, call
3317db96d56Sopenharmony_ci            # it.
3327db96d56Sopenharmony_ci            func(self.default, owner, name)
3337db96d56Sopenharmony_ci
3347db96d56Sopenharmony_ci    __class_getitem__ = classmethod(GenericAlias)
3357db96d56Sopenharmony_ci
3367db96d56Sopenharmony_ci
3377db96d56Sopenharmony_ciclass _DataclassParams:
3387db96d56Sopenharmony_ci    __slots__ = ('init',
3397db96d56Sopenharmony_ci                 'repr',
3407db96d56Sopenharmony_ci                 'eq',
3417db96d56Sopenharmony_ci                 'order',
3427db96d56Sopenharmony_ci                 'unsafe_hash',
3437db96d56Sopenharmony_ci                 'frozen',
3447db96d56Sopenharmony_ci                 )
3457db96d56Sopenharmony_ci
3467db96d56Sopenharmony_ci    def __init__(self, init, repr, eq, order, unsafe_hash, frozen):
3477db96d56Sopenharmony_ci        self.init = init
3487db96d56Sopenharmony_ci        self.repr = repr
3497db96d56Sopenharmony_ci        self.eq = eq
3507db96d56Sopenharmony_ci        self.order = order
3517db96d56Sopenharmony_ci        self.unsafe_hash = unsafe_hash
3527db96d56Sopenharmony_ci        self.frozen = frozen
3537db96d56Sopenharmony_ci
3547db96d56Sopenharmony_ci    def __repr__(self):
3557db96d56Sopenharmony_ci        return ('_DataclassParams('
3567db96d56Sopenharmony_ci                f'init={self.init!r},'
3577db96d56Sopenharmony_ci                f'repr={self.repr!r},'
3587db96d56Sopenharmony_ci                f'eq={self.eq!r},'
3597db96d56Sopenharmony_ci                f'order={self.order!r},'
3607db96d56Sopenharmony_ci                f'unsafe_hash={self.unsafe_hash!r},'
3617db96d56Sopenharmony_ci                f'frozen={self.frozen!r}'
3627db96d56Sopenharmony_ci                ')')
3637db96d56Sopenharmony_ci
3647db96d56Sopenharmony_ci
3657db96d56Sopenharmony_ci# This function is used instead of exposing Field creation directly,
3667db96d56Sopenharmony_ci# so that a type checker can be told (via overloads) that this is a
3677db96d56Sopenharmony_ci# function whose type depends on its parameters.
3687db96d56Sopenharmony_cidef field(*, default=MISSING, default_factory=MISSING, init=True, repr=True,
3697db96d56Sopenharmony_ci          hash=None, compare=True, metadata=None, kw_only=MISSING):
3707db96d56Sopenharmony_ci    """Return an object to identify dataclass fields.
3717db96d56Sopenharmony_ci
3727db96d56Sopenharmony_ci    default is the default value of the field.  default_factory is a
3737db96d56Sopenharmony_ci    0-argument function called to initialize a field's value.  If init
3747db96d56Sopenharmony_ci    is true, the field will be a parameter to the class's __init__()
3757db96d56Sopenharmony_ci    function.  If repr is true, the field will be included in the
3767db96d56Sopenharmony_ci    object's repr().  If hash is true, the field will be included in the
3777db96d56Sopenharmony_ci    object's hash().  If compare is true, the field will be used in
3787db96d56Sopenharmony_ci    comparison functions.  metadata, if specified, must be a mapping
3797db96d56Sopenharmony_ci    which is stored but not otherwise examined by dataclass.  If kw_only
3807db96d56Sopenharmony_ci    is true, the field will become a keyword-only parameter to
3817db96d56Sopenharmony_ci    __init__().
3827db96d56Sopenharmony_ci
3837db96d56Sopenharmony_ci    It is an error to specify both default and default_factory.
3847db96d56Sopenharmony_ci    """
3857db96d56Sopenharmony_ci
3867db96d56Sopenharmony_ci    if default is not MISSING and default_factory is not MISSING:
3877db96d56Sopenharmony_ci        raise ValueError('cannot specify both default and default_factory')
3887db96d56Sopenharmony_ci    return Field(default, default_factory, init, repr, hash, compare,
3897db96d56Sopenharmony_ci                 metadata, kw_only)
3907db96d56Sopenharmony_ci
3917db96d56Sopenharmony_ci
3927db96d56Sopenharmony_cidef _fields_in_init_order(fields):
3937db96d56Sopenharmony_ci    # Returns the fields as __init__ will output them.  It returns 2 tuples:
3947db96d56Sopenharmony_ci    # the first for normal args, and the second for keyword args.
3957db96d56Sopenharmony_ci
3967db96d56Sopenharmony_ci    return (tuple(f for f in fields if f.init and not f.kw_only),
3977db96d56Sopenharmony_ci            tuple(f for f in fields if f.init and f.kw_only)
3987db96d56Sopenharmony_ci            )
3997db96d56Sopenharmony_ci
4007db96d56Sopenharmony_ci
4017db96d56Sopenharmony_cidef _tuple_str(obj_name, fields):
4027db96d56Sopenharmony_ci    # Return a string representing each field of obj_name as a tuple
4037db96d56Sopenharmony_ci    # member.  So, if fields is ['x', 'y'] and obj_name is "self",
4047db96d56Sopenharmony_ci    # return "(self.x,self.y)".
4057db96d56Sopenharmony_ci
4067db96d56Sopenharmony_ci    # Special case for the 0-tuple.
4077db96d56Sopenharmony_ci    if not fields:
4087db96d56Sopenharmony_ci        return '()'
4097db96d56Sopenharmony_ci    # Note the trailing comma, needed if this turns out to be a 1-tuple.
4107db96d56Sopenharmony_ci    return f'({",".join([f"{obj_name}.{f.name}" for f in fields])},)'
4117db96d56Sopenharmony_ci
4127db96d56Sopenharmony_ci
4137db96d56Sopenharmony_cidef _create_fn(name, args, body, *, globals=None, locals=None,
4147db96d56Sopenharmony_ci               return_type=MISSING):
4157db96d56Sopenharmony_ci    # Note that we may mutate locals. Callers beware!
4167db96d56Sopenharmony_ci    # The only callers are internal to this module, so no
4177db96d56Sopenharmony_ci    # worries about external callers.
4187db96d56Sopenharmony_ci    if locals is None:
4197db96d56Sopenharmony_ci        locals = {}
4207db96d56Sopenharmony_ci    return_annotation = ''
4217db96d56Sopenharmony_ci    if return_type is not MISSING:
4227db96d56Sopenharmony_ci        locals['_return_type'] = return_type
4237db96d56Sopenharmony_ci        return_annotation = '->_return_type'
4247db96d56Sopenharmony_ci    args = ','.join(args)
4257db96d56Sopenharmony_ci    body = '\n'.join(f'  {b}' for b in body)
4267db96d56Sopenharmony_ci
4277db96d56Sopenharmony_ci    # Compute the text of the entire function.
4287db96d56Sopenharmony_ci    txt = f' def {name}({args}){return_annotation}:\n{body}'
4297db96d56Sopenharmony_ci
4307db96d56Sopenharmony_ci    local_vars = ', '.join(locals.keys())
4317db96d56Sopenharmony_ci    txt = f"def __create_fn__({local_vars}):\n{txt}\n return {name}"
4327db96d56Sopenharmony_ci    ns = {}
4337db96d56Sopenharmony_ci    exec(txt, globals, ns)
4347db96d56Sopenharmony_ci    return ns['__create_fn__'](**locals)
4357db96d56Sopenharmony_ci
4367db96d56Sopenharmony_ci
4377db96d56Sopenharmony_cidef _field_assign(frozen, name, value, self_name):
4387db96d56Sopenharmony_ci    # If we're a frozen class, then assign to our fields in __init__
4397db96d56Sopenharmony_ci    # via object.__setattr__.  Otherwise, just use a simple
4407db96d56Sopenharmony_ci    # assignment.
4417db96d56Sopenharmony_ci    #
4427db96d56Sopenharmony_ci    # self_name is what "self" is called in this function: don't
4437db96d56Sopenharmony_ci    # hard-code "self", since that might be a field name.
4447db96d56Sopenharmony_ci    if frozen:
4457db96d56Sopenharmony_ci        return f'__dataclass_builtins_object__.__setattr__({self_name},{name!r},{value})'
4467db96d56Sopenharmony_ci    return f'{self_name}.{name}={value}'
4477db96d56Sopenharmony_ci
4487db96d56Sopenharmony_ci
4497db96d56Sopenharmony_cidef _field_init(f, frozen, globals, self_name, slots):
4507db96d56Sopenharmony_ci    # Return the text of the line in the body of __init__ that will
4517db96d56Sopenharmony_ci    # initialize this field.
4527db96d56Sopenharmony_ci
4537db96d56Sopenharmony_ci    default_name = f'_dflt_{f.name}'
4547db96d56Sopenharmony_ci    if f.default_factory is not MISSING:
4557db96d56Sopenharmony_ci        if f.init:
4567db96d56Sopenharmony_ci            # This field has a default factory.  If a parameter is
4577db96d56Sopenharmony_ci            # given, use it.  If not, call the factory.
4587db96d56Sopenharmony_ci            globals[default_name] = f.default_factory
4597db96d56Sopenharmony_ci            value = (f'{default_name}() '
4607db96d56Sopenharmony_ci                     f'if {f.name} is _HAS_DEFAULT_FACTORY '
4617db96d56Sopenharmony_ci                     f'else {f.name}')
4627db96d56Sopenharmony_ci        else:
4637db96d56Sopenharmony_ci            # This is a field that's not in the __init__ params, but
4647db96d56Sopenharmony_ci            # has a default factory function.  It needs to be
4657db96d56Sopenharmony_ci            # initialized here by calling the factory function,
4667db96d56Sopenharmony_ci            # because there's no other way to initialize it.
4677db96d56Sopenharmony_ci
4687db96d56Sopenharmony_ci            # For a field initialized with a default=defaultvalue, the
4697db96d56Sopenharmony_ci            # class dict just has the default value
4707db96d56Sopenharmony_ci            # (cls.fieldname=defaultvalue).  But that won't work for a
4717db96d56Sopenharmony_ci            # default factory, the factory must be called in __init__
4727db96d56Sopenharmony_ci            # and we must assign that to self.fieldname.  We can't
4737db96d56Sopenharmony_ci            # fall back to the class dict's value, both because it's
4747db96d56Sopenharmony_ci            # not set, and because it might be different per-class
4757db96d56Sopenharmony_ci            # (which, after all, is why we have a factory function!).
4767db96d56Sopenharmony_ci
4777db96d56Sopenharmony_ci            globals[default_name] = f.default_factory
4787db96d56Sopenharmony_ci            value = f'{default_name}()'
4797db96d56Sopenharmony_ci    else:
4807db96d56Sopenharmony_ci        # No default factory.
4817db96d56Sopenharmony_ci        if f.init:
4827db96d56Sopenharmony_ci            if f.default is MISSING:
4837db96d56Sopenharmony_ci                # There's no default, just do an assignment.
4847db96d56Sopenharmony_ci                value = f.name
4857db96d56Sopenharmony_ci            elif f.default is not MISSING:
4867db96d56Sopenharmony_ci                globals[default_name] = f.default
4877db96d56Sopenharmony_ci                value = f.name
4887db96d56Sopenharmony_ci        else:
4897db96d56Sopenharmony_ci            # If the class has slots, then initialize this field.
4907db96d56Sopenharmony_ci            if slots and f.default is not MISSING:
4917db96d56Sopenharmony_ci                globals[default_name] = f.default
4927db96d56Sopenharmony_ci                value = default_name
4937db96d56Sopenharmony_ci            else:
4947db96d56Sopenharmony_ci                # This field does not need initialization: reading from it will
4957db96d56Sopenharmony_ci                # just use the class attribute that contains the default.
4967db96d56Sopenharmony_ci                # Signify that to the caller by returning None.
4977db96d56Sopenharmony_ci                return None
4987db96d56Sopenharmony_ci
4997db96d56Sopenharmony_ci    # Only test this now, so that we can create variables for the
5007db96d56Sopenharmony_ci    # default.  However, return None to signify that we're not going
5017db96d56Sopenharmony_ci    # to actually do the assignment statement for InitVars.
5027db96d56Sopenharmony_ci    if f._field_type is _FIELD_INITVAR:
5037db96d56Sopenharmony_ci        return None
5047db96d56Sopenharmony_ci
5057db96d56Sopenharmony_ci    # Now, actually generate the field assignment.
5067db96d56Sopenharmony_ci    return _field_assign(frozen, f.name, value, self_name)
5077db96d56Sopenharmony_ci
5087db96d56Sopenharmony_ci
5097db96d56Sopenharmony_cidef _init_param(f):
5107db96d56Sopenharmony_ci    # Return the __init__ parameter string for this field.  For
5117db96d56Sopenharmony_ci    # example, the equivalent of 'x:int=3' (except instead of 'int',
5127db96d56Sopenharmony_ci    # reference a variable set to int, and instead of '3', reference a
5137db96d56Sopenharmony_ci    # variable set to 3).
5147db96d56Sopenharmony_ci    if f.default is MISSING and f.default_factory is MISSING:
5157db96d56Sopenharmony_ci        # There's no default, and no default_factory, just output the
5167db96d56Sopenharmony_ci        # variable name and type.
5177db96d56Sopenharmony_ci        default = ''
5187db96d56Sopenharmony_ci    elif f.default is not MISSING:
5197db96d56Sopenharmony_ci        # There's a default, this will be the name that's used to look
5207db96d56Sopenharmony_ci        # it up.
5217db96d56Sopenharmony_ci        default = f'=_dflt_{f.name}'
5227db96d56Sopenharmony_ci    elif f.default_factory is not MISSING:
5237db96d56Sopenharmony_ci        # There's a factory function.  Set a marker.
5247db96d56Sopenharmony_ci        default = '=_HAS_DEFAULT_FACTORY'
5257db96d56Sopenharmony_ci    return f'{f.name}:_type_{f.name}{default}'
5267db96d56Sopenharmony_ci
5277db96d56Sopenharmony_ci
5287db96d56Sopenharmony_cidef _init_fn(fields, std_fields, kw_only_fields, frozen, has_post_init,
5297db96d56Sopenharmony_ci             self_name, globals, slots):
5307db96d56Sopenharmony_ci    # fields contains both real fields and InitVar pseudo-fields.
5317db96d56Sopenharmony_ci
5327db96d56Sopenharmony_ci    # Make sure we don't have fields without defaults following fields
5337db96d56Sopenharmony_ci    # with defaults.  This actually would be caught when exec-ing the
5347db96d56Sopenharmony_ci    # function source code, but catching it here gives a better error
5357db96d56Sopenharmony_ci    # message, and future-proofs us in case we build up the function
5367db96d56Sopenharmony_ci    # using ast.
5377db96d56Sopenharmony_ci
5387db96d56Sopenharmony_ci    seen_default = False
5397db96d56Sopenharmony_ci    for f in std_fields:
5407db96d56Sopenharmony_ci        # Only consider the non-kw-only fields in the __init__ call.
5417db96d56Sopenharmony_ci        if f.init:
5427db96d56Sopenharmony_ci            if not (f.default is MISSING and f.default_factory is MISSING):
5437db96d56Sopenharmony_ci                seen_default = True
5447db96d56Sopenharmony_ci            elif seen_default:
5457db96d56Sopenharmony_ci                raise TypeError(f'non-default argument {f.name!r} '
5467db96d56Sopenharmony_ci                                'follows default argument')
5477db96d56Sopenharmony_ci
5487db96d56Sopenharmony_ci    locals = {f'_type_{f.name}': f.type for f in fields}
5497db96d56Sopenharmony_ci    locals.update({
5507db96d56Sopenharmony_ci        'MISSING': MISSING,
5517db96d56Sopenharmony_ci        '_HAS_DEFAULT_FACTORY': _HAS_DEFAULT_FACTORY,
5527db96d56Sopenharmony_ci        '__dataclass_builtins_object__': object,
5537db96d56Sopenharmony_ci    })
5547db96d56Sopenharmony_ci
5557db96d56Sopenharmony_ci    body_lines = []
5567db96d56Sopenharmony_ci    for f in fields:
5577db96d56Sopenharmony_ci        line = _field_init(f, frozen, locals, self_name, slots)
5587db96d56Sopenharmony_ci        # line is None means that this field doesn't require
5597db96d56Sopenharmony_ci        # initialization (it's a pseudo-field).  Just skip it.
5607db96d56Sopenharmony_ci        if line:
5617db96d56Sopenharmony_ci            body_lines.append(line)
5627db96d56Sopenharmony_ci
5637db96d56Sopenharmony_ci    # Does this class have a post-init function?
5647db96d56Sopenharmony_ci    if has_post_init:
5657db96d56Sopenharmony_ci        params_str = ','.join(f.name for f in fields
5667db96d56Sopenharmony_ci                              if f._field_type is _FIELD_INITVAR)
5677db96d56Sopenharmony_ci        body_lines.append(f'{self_name}.{_POST_INIT_NAME}({params_str})')
5687db96d56Sopenharmony_ci
5697db96d56Sopenharmony_ci    # If no body lines, use 'pass'.
5707db96d56Sopenharmony_ci    if not body_lines:
5717db96d56Sopenharmony_ci        body_lines = ['pass']
5727db96d56Sopenharmony_ci
5737db96d56Sopenharmony_ci    _init_params = [_init_param(f) for f in std_fields]
5747db96d56Sopenharmony_ci    if kw_only_fields:
5757db96d56Sopenharmony_ci        # Add the keyword-only args.  Because the * can only be added if
5767db96d56Sopenharmony_ci        # there's at least one keyword-only arg, there needs to be a test here
5777db96d56Sopenharmony_ci        # (instead of just concatenting the lists together).
5787db96d56Sopenharmony_ci        _init_params += ['*']
5797db96d56Sopenharmony_ci        _init_params += [_init_param(f) for f in kw_only_fields]
5807db96d56Sopenharmony_ci    return _create_fn('__init__',
5817db96d56Sopenharmony_ci                      [self_name] + _init_params,
5827db96d56Sopenharmony_ci                      body_lines,
5837db96d56Sopenharmony_ci                      locals=locals,
5847db96d56Sopenharmony_ci                      globals=globals,
5857db96d56Sopenharmony_ci                      return_type=None)
5867db96d56Sopenharmony_ci
5877db96d56Sopenharmony_ci
5887db96d56Sopenharmony_cidef _repr_fn(fields, globals):
5897db96d56Sopenharmony_ci    fn = _create_fn('__repr__',
5907db96d56Sopenharmony_ci                    ('self',),
5917db96d56Sopenharmony_ci                    ['return self.__class__.__qualname__ + f"(' +
5927db96d56Sopenharmony_ci                     ', '.join([f"{f.name}={{self.{f.name}!r}}"
5937db96d56Sopenharmony_ci                                for f in fields]) +
5947db96d56Sopenharmony_ci                     ')"'],
5957db96d56Sopenharmony_ci                     globals=globals)
5967db96d56Sopenharmony_ci    return _recursive_repr(fn)
5977db96d56Sopenharmony_ci
5987db96d56Sopenharmony_ci
5997db96d56Sopenharmony_cidef _frozen_get_del_attr(cls, fields, globals):
6007db96d56Sopenharmony_ci    locals = {'cls': cls,
6017db96d56Sopenharmony_ci              'FrozenInstanceError': FrozenInstanceError}
6027db96d56Sopenharmony_ci    if fields:
6037db96d56Sopenharmony_ci        fields_str = '(' + ','.join(repr(f.name) for f in fields) + ',)'
6047db96d56Sopenharmony_ci    else:
6057db96d56Sopenharmony_ci        # Special case for the zero-length tuple.
6067db96d56Sopenharmony_ci        fields_str = '()'
6077db96d56Sopenharmony_ci    return (_create_fn('__setattr__',
6087db96d56Sopenharmony_ci                      ('self', 'name', 'value'),
6097db96d56Sopenharmony_ci                      (f'if type(self) is cls or name in {fields_str}:',
6107db96d56Sopenharmony_ci                        ' raise FrozenInstanceError(f"cannot assign to field {name!r}")',
6117db96d56Sopenharmony_ci                       f'super(cls, self).__setattr__(name, value)'),
6127db96d56Sopenharmony_ci                       locals=locals,
6137db96d56Sopenharmony_ci                       globals=globals),
6147db96d56Sopenharmony_ci            _create_fn('__delattr__',
6157db96d56Sopenharmony_ci                      ('self', 'name'),
6167db96d56Sopenharmony_ci                      (f'if type(self) is cls or name in {fields_str}:',
6177db96d56Sopenharmony_ci                        ' raise FrozenInstanceError(f"cannot delete field {name!r}")',
6187db96d56Sopenharmony_ci                       f'super(cls, self).__delattr__(name)'),
6197db96d56Sopenharmony_ci                       locals=locals,
6207db96d56Sopenharmony_ci                       globals=globals),
6217db96d56Sopenharmony_ci            )
6227db96d56Sopenharmony_ci
6237db96d56Sopenharmony_ci
6247db96d56Sopenharmony_cidef _cmp_fn(name, op, self_tuple, other_tuple, globals):
6257db96d56Sopenharmony_ci    # Create a comparison function.  If the fields in the object are
6267db96d56Sopenharmony_ci    # named 'x' and 'y', then self_tuple is the string
6277db96d56Sopenharmony_ci    # '(self.x,self.y)' and other_tuple is the string
6287db96d56Sopenharmony_ci    # '(other.x,other.y)'.
6297db96d56Sopenharmony_ci
6307db96d56Sopenharmony_ci    return _create_fn(name,
6317db96d56Sopenharmony_ci                      ('self', 'other'),
6327db96d56Sopenharmony_ci                      [ 'if other.__class__ is self.__class__:',
6337db96d56Sopenharmony_ci                       f' return {self_tuple}{op}{other_tuple}',
6347db96d56Sopenharmony_ci                        'return NotImplemented'],
6357db96d56Sopenharmony_ci                      globals=globals)
6367db96d56Sopenharmony_ci
6377db96d56Sopenharmony_ci
6387db96d56Sopenharmony_cidef _hash_fn(fields, globals):
6397db96d56Sopenharmony_ci    self_tuple = _tuple_str('self', fields)
6407db96d56Sopenharmony_ci    return _create_fn('__hash__',
6417db96d56Sopenharmony_ci                      ('self',),
6427db96d56Sopenharmony_ci                      [f'return hash({self_tuple})'],
6437db96d56Sopenharmony_ci                      globals=globals)
6447db96d56Sopenharmony_ci
6457db96d56Sopenharmony_ci
6467db96d56Sopenharmony_cidef _is_classvar(a_type, typing):
6477db96d56Sopenharmony_ci    # This test uses a typing internal class, but it's the best way to
6487db96d56Sopenharmony_ci    # test if this is a ClassVar.
6497db96d56Sopenharmony_ci    return (a_type is typing.ClassVar
6507db96d56Sopenharmony_ci            or (type(a_type) is typing._GenericAlias
6517db96d56Sopenharmony_ci                and a_type.__origin__ is typing.ClassVar))
6527db96d56Sopenharmony_ci
6537db96d56Sopenharmony_ci
6547db96d56Sopenharmony_cidef _is_initvar(a_type, dataclasses):
6557db96d56Sopenharmony_ci    # The module we're checking against is the module we're
6567db96d56Sopenharmony_ci    # currently in (dataclasses.py).
6577db96d56Sopenharmony_ci    return (a_type is dataclasses.InitVar
6587db96d56Sopenharmony_ci            or type(a_type) is dataclasses.InitVar)
6597db96d56Sopenharmony_ci
6607db96d56Sopenharmony_cidef _is_kw_only(a_type, dataclasses):
6617db96d56Sopenharmony_ci    return a_type is dataclasses.KW_ONLY
6627db96d56Sopenharmony_ci
6637db96d56Sopenharmony_ci
6647db96d56Sopenharmony_cidef _is_type(annotation, cls, a_module, a_type, is_type_predicate):
6657db96d56Sopenharmony_ci    # Given a type annotation string, does it refer to a_type in
6667db96d56Sopenharmony_ci    # a_module?  For example, when checking that annotation denotes a
6677db96d56Sopenharmony_ci    # ClassVar, then a_module is typing, and a_type is
6687db96d56Sopenharmony_ci    # typing.ClassVar.
6697db96d56Sopenharmony_ci
6707db96d56Sopenharmony_ci    # It's possible to look up a_module given a_type, but it involves
6717db96d56Sopenharmony_ci    # looking in sys.modules (again!), and seems like a waste since
6727db96d56Sopenharmony_ci    # the caller already knows a_module.
6737db96d56Sopenharmony_ci
6747db96d56Sopenharmony_ci    # - annotation is a string type annotation
6757db96d56Sopenharmony_ci    # - cls is the class that this annotation was found in
6767db96d56Sopenharmony_ci    # - a_module is the module we want to match
6777db96d56Sopenharmony_ci    # - a_type is the type in that module we want to match
6787db96d56Sopenharmony_ci    # - is_type_predicate is a function called with (obj, a_module)
6797db96d56Sopenharmony_ci    #   that determines if obj is of the desired type.
6807db96d56Sopenharmony_ci
6817db96d56Sopenharmony_ci    # Since this test does not do a local namespace lookup (and
6827db96d56Sopenharmony_ci    # instead only a module (global) lookup), there are some things it
6837db96d56Sopenharmony_ci    # gets wrong.
6847db96d56Sopenharmony_ci
6857db96d56Sopenharmony_ci    # With string annotations, cv0 will be detected as a ClassVar:
6867db96d56Sopenharmony_ci    #   CV = ClassVar
6877db96d56Sopenharmony_ci    #   @dataclass
6887db96d56Sopenharmony_ci    #   class C0:
6897db96d56Sopenharmony_ci    #     cv0: CV
6907db96d56Sopenharmony_ci
6917db96d56Sopenharmony_ci    # But in this example cv1 will not be detected as a ClassVar:
6927db96d56Sopenharmony_ci    #   @dataclass
6937db96d56Sopenharmony_ci    #   class C1:
6947db96d56Sopenharmony_ci    #     CV = ClassVar
6957db96d56Sopenharmony_ci    #     cv1: CV
6967db96d56Sopenharmony_ci
6977db96d56Sopenharmony_ci    # In C1, the code in this function (_is_type) will look up "CV" in
6987db96d56Sopenharmony_ci    # the module and not find it, so it will not consider cv1 as a
6997db96d56Sopenharmony_ci    # ClassVar.  This is a fairly obscure corner case, and the best
7007db96d56Sopenharmony_ci    # way to fix it would be to eval() the string "CV" with the
7017db96d56Sopenharmony_ci    # correct global and local namespaces.  However that would involve
7027db96d56Sopenharmony_ci    # a eval() penalty for every single field of every dataclass
7037db96d56Sopenharmony_ci    # that's defined.  It was judged not worth it.
7047db96d56Sopenharmony_ci
7057db96d56Sopenharmony_ci    match = _MODULE_IDENTIFIER_RE.match(annotation)
7067db96d56Sopenharmony_ci    if match:
7077db96d56Sopenharmony_ci        ns = None
7087db96d56Sopenharmony_ci        module_name = match.group(1)
7097db96d56Sopenharmony_ci        if not module_name:
7107db96d56Sopenharmony_ci            # No module name, assume the class's module did
7117db96d56Sopenharmony_ci            # "from dataclasses import InitVar".
7127db96d56Sopenharmony_ci            ns = sys.modules.get(cls.__module__).__dict__
7137db96d56Sopenharmony_ci        else:
7147db96d56Sopenharmony_ci            # Look up module_name in the class's module.
7157db96d56Sopenharmony_ci            module = sys.modules.get(cls.__module__)
7167db96d56Sopenharmony_ci            if module and module.__dict__.get(module_name) is a_module:
7177db96d56Sopenharmony_ci                ns = sys.modules.get(a_type.__module__).__dict__
7187db96d56Sopenharmony_ci        if ns and is_type_predicate(ns.get(match.group(2)), a_module):
7197db96d56Sopenharmony_ci            return True
7207db96d56Sopenharmony_ci    return False
7217db96d56Sopenharmony_ci
7227db96d56Sopenharmony_ci
7237db96d56Sopenharmony_cidef _get_field(cls, a_name, a_type, default_kw_only):
7247db96d56Sopenharmony_ci    # Return a Field object for this field name and type.  ClassVars and
7257db96d56Sopenharmony_ci    # InitVars are also returned, but marked as such (see f._field_type).
7267db96d56Sopenharmony_ci    # default_kw_only is the value of kw_only to use if there isn't a field()
7277db96d56Sopenharmony_ci    # that defines it.
7287db96d56Sopenharmony_ci
7297db96d56Sopenharmony_ci    # If the default value isn't derived from Field, then it's only a
7307db96d56Sopenharmony_ci    # normal default value.  Convert it to a Field().
7317db96d56Sopenharmony_ci    default = getattr(cls, a_name, MISSING)
7327db96d56Sopenharmony_ci    if isinstance(default, Field):
7337db96d56Sopenharmony_ci        f = default
7347db96d56Sopenharmony_ci    else:
7357db96d56Sopenharmony_ci        if isinstance(default, types.MemberDescriptorType):
7367db96d56Sopenharmony_ci            # This is a field in __slots__, so it has no default value.
7377db96d56Sopenharmony_ci            default = MISSING
7387db96d56Sopenharmony_ci        f = field(default=default)
7397db96d56Sopenharmony_ci
7407db96d56Sopenharmony_ci    # Only at this point do we know the name and the type.  Set them.
7417db96d56Sopenharmony_ci    f.name = a_name
7427db96d56Sopenharmony_ci    f.type = a_type
7437db96d56Sopenharmony_ci
7447db96d56Sopenharmony_ci    # Assume it's a normal field until proven otherwise.  We're next
7457db96d56Sopenharmony_ci    # going to decide if it's a ClassVar or InitVar, everything else
7467db96d56Sopenharmony_ci    # is just a normal field.
7477db96d56Sopenharmony_ci    f._field_type = _FIELD
7487db96d56Sopenharmony_ci
7497db96d56Sopenharmony_ci    # In addition to checking for actual types here, also check for
7507db96d56Sopenharmony_ci    # string annotations.  get_type_hints() won't always work for us
7517db96d56Sopenharmony_ci    # (see https://github.com/python/typing/issues/508 for example),
7527db96d56Sopenharmony_ci    # plus it's expensive and would require an eval for every string
7537db96d56Sopenharmony_ci    # annotation.  So, make a best effort to see if this is a ClassVar
7547db96d56Sopenharmony_ci    # or InitVar using regex's and checking that the thing referenced
7557db96d56Sopenharmony_ci    # is actually of the correct type.
7567db96d56Sopenharmony_ci
7577db96d56Sopenharmony_ci    # For the complete discussion, see https://bugs.python.org/issue33453
7587db96d56Sopenharmony_ci
7597db96d56Sopenharmony_ci    # If typing has not been imported, then it's impossible for any
7607db96d56Sopenharmony_ci    # annotation to be a ClassVar.  So, only look for ClassVar if
7617db96d56Sopenharmony_ci    # typing has been imported by any module (not necessarily cls's
7627db96d56Sopenharmony_ci    # module).
7637db96d56Sopenharmony_ci    typing = sys.modules.get('typing')
7647db96d56Sopenharmony_ci    if typing:
7657db96d56Sopenharmony_ci        if (_is_classvar(a_type, typing)
7667db96d56Sopenharmony_ci            or (isinstance(f.type, str)
7677db96d56Sopenharmony_ci                and _is_type(f.type, cls, typing, typing.ClassVar,
7687db96d56Sopenharmony_ci                             _is_classvar))):
7697db96d56Sopenharmony_ci            f._field_type = _FIELD_CLASSVAR
7707db96d56Sopenharmony_ci
7717db96d56Sopenharmony_ci    # If the type is InitVar, or if it's a matching string annotation,
7727db96d56Sopenharmony_ci    # then it's an InitVar.
7737db96d56Sopenharmony_ci    if f._field_type is _FIELD:
7747db96d56Sopenharmony_ci        # The module we're checking against is the module we're
7757db96d56Sopenharmony_ci        # currently in (dataclasses.py).
7767db96d56Sopenharmony_ci        dataclasses = sys.modules[__name__]
7777db96d56Sopenharmony_ci        if (_is_initvar(a_type, dataclasses)
7787db96d56Sopenharmony_ci            or (isinstance(f.type, str)
7797db96d56Sopenharmony_ci                and _is_type(f.type, cls, dataclasses, dataclasses.InitVar,
7807db96d56Sopenharmony_ci                             _is_initvar))):
7817db96d56Sopenharmony_ci            f._field_type = _FIELD_INITVAR
7827db96d56Sopenharmony_ci
7837db96d56Sopenharmony_ci    # Validations for individual fields.  This is delayed until now,
7847db96d56Sopenharmony_ci    # instead of in the Field() constructor, since only here do we
7857db96d56Sopenharmony_ci    # know the field name, which allows for better error reporting.
7867db96d56Sopenharmony_ci
7877db96d56Sopenharmony_ci    # Special restrictions for ClassVar and InitVar.
7887db96d56Sopenharmony_ci    if f._field_type in (_FIELD_CLASSVAR, _FIELD_INITVAR):
7897db96d56Sopenharmony_ci        if f.default_factory is not MISSING:
7907db96d56Sopenharmony_ci            raise TypeError(f'field {f.name} cannot have a '
7917db96d56Sopenharmony_ci                            'default factory')
7927db96d56Sopenharmony_ci        # Should I check for other field settings? default_factory
7937db96d56Sopenharmony_ci        # seems the most serious to check for.  Maybe add others.  For
7947db96d56Sopenharmony_ci        # example, how about init=False (or really,
7957db96d56Sopenharmony_ci        # init=<not-the-default-init-value>)?  It makes no sense for
7967db96d56Sopenharmony_ci        # ClassVar and InitVar to specify init=<anything>.
7977db96d56Sopenharmony_ci
7987db96d56Sopenharmony_ci    # kw_only validation and assignment.
7997db96d56Sopenharmony_ci    if f._field_type in (_FIELD, _FIELD_INITVAR):
8007db96d56Sopenharmony_ci        # For real and InitVar fields, if kw_only wasn't specified use the
8017db96d56Sopenharmony_ci        # default value.
8027db96d56Sopenharmony_ci        if f.kw_only is MISSING:
8037db96d56Sopenharmony_ci            f.kw_only = default_kw_only
8047db96d56Sopenharmony_ci    else:
8057db96d56Sopenharmony_ci        # Make sure kw_only isn't set for ClassVars
8067db96d56Sopenharmony_ci        assert f._field_type is _FIELD_CLASSVAR
8077db96d56Sopenharmony_ci        if f.kw_only is not MISSING:
8087db96d56Sopenharmony_ci            raise TypeError(f'field {f.name} is a ClassVar but specifies '
8097db96d56Sopenharmony_ci                            'kw_only')
8107db96d56Sopenharmony_ci
8117db96d56Sopenharmony_ci    # For real fields, disallow mutable defaults.  Use unhashable as a proxy
8127db96d56Sopenharmony_ci    # indicator for mutability.  Read the __hash__ attribute from the class,
8137db96d56Sopenharmony_ci    # not the instance.
8147db96d56Sopenharmony_ci    if f._field_type is _FIELD and f.default.__class__.__hash__ is None:
8157db96d56Sopenharmony_ci        raise ValueError(f'mutable default {type(f.default)} for field '
8167db96d56Sopenharmony_ci                         f'{f.name} is not allowed: use default_factory')
8177db96d56Sopenharmony_ci
8187db96d56Sopenharmony_ci    return f
8197db96d56Sopenharmony_ci
8207db96d56Sopenharmony_cidef _set_qualname(cls, value):
8217db96d56Sopenharmony_ci    # Ensure that the functions returned from _create_fn uses the proper
8227db96d56Sopenharmony_ci    # __qualname__ (the class they belong to).
8237db96d56Sopenharmony_ci    if isinstance(value, FunctionType):
8247db96d56Sopenharmony_ci        value.__qualname__ = f"{cls.__qualname__}.{value.__name__}"
8257db96d56Sopenharmony_ci    return value
8267db96d56Sopenharmony_ci
8277db96d56Sopenharmony_cidef _set_new_attribute(cls, name, value):
8287db96d56Sopenharmony_ci    # Never overwrites an existing attribute.  Returns True if the
8297db96d56Sopenharmony_ci    # attribute already exists.
8307db96d56Sopenharmony_ci    if name in cls.__dict__:
8317db96d56Sopenharmony_ci        return True
8327db96d56Sopenharmony_ci    _set_qualname(cls, value)
8337db96d56Sopenharmony_ci    setattr(cls, name, value)
8347db96d56Sopenharmony_ci    return False
8357db96d56Sopenharmony_ci
8367db96d56Sopenharmony_ci
8377db96d56Sopenharmony_ci# Decide if/how we're going to create a hash function.  Key is
8387db96d56Sopenharmony_ci# (unsafe_hash, eq, frozen, does-hash-exist).  Value is the action to
8397db96d56Sopenharmony_ci# take.  The common case is to do nothing, so instead of providing a
8407db96d56Sopenharmony_ci# function that is a no-op, use None to signify that.
8417db96d56Sopenharmony_ci
8427db96d56Sopenharmony_cidef _hash_set_none(cls, fields, globals):
8437db96d56Sopenharmony_ci    return None
8447db96d56Sopenharmony_ci
8457db96d56Sopenharmony_cidef _hash_add(cls, fields, globals):
8467db96d56Sopenharmony_ci    flds = [f for f in fields if (f.compare if f.hash is None else f.hash)]
8477db96d56Sopenharmony_ci    return _set_qualname(cls, _hash_fn(flds, globals))
8487db96d56Sopenharmony_ci
8497db96d56Sopenharmony_cidef _hash_exception(cls, fields, globals):
8507db96d56Sopenharmony_ci    # Raise an exception.
8517db96d56Sopenharmony_ci    raise TypeError(f'Cannot overwrite attribute __hash__ '
8527db96d56Sopenharmony_ci                    f'in class {cls.__name__}')
8537db96d56Sopenharmony_ci
8547db96d56Sopenharmony_ci#
8557db96d56Sopenharmony_ci#                +-------------------------------------- unsafe_hash?
8567db96d56Sopenharmony_ci#                |      +------------------------------- eq?
8577db96d56Sopenharmony_ci#                |      |      +------------------------ frozen?
8587db96d56Sopenharmony_ci#                |      |      |      +----------------  has-explicit-hash?
8597db96d56Sopenharmony_ci#                |      |      |      |
8607db96d56Sopenharmony_ci#                |      |      |      |        +-------  action
8617db96d56Sopenharmony_ci#                |      |      |      |        |
8627db96d56Sopenharmony_ci#                v      v      v      v        v
8637db96d56Sopenharmony_ci_hash_action = {(False, False, False, False): None,
8647db96d56Sopenharmony_ci                (False, False, False, True ): None,
8657db96d56Sopenharmony_ci                (False, False, True,  False): None,
8667db96d56Sopenharmony_ci                (False, False, True,  True ): None,
8677db96d56Sopenharmony_ci                (False, True,  False, False): _hash_set_none,
8687db96d56Sopenharmony_ci                (False, True,  False, True ): None,
8697db96d56Sopenharmony_ci                (False, True,  True,  False): _hash_add,
8707db96d56Sopenharmony_ci                (False, True,  True,  True ): None,
8717db96d56Sopenharmony_ci                (True,  False, False, False): _hash_add,
8727db96d56Sopenharmony_ci                (True,  False, False, True ): _hash_exception,
8737db96d56Sopenharmony_ci                (True,  False, True,  False): _hash_add,
8747db96d56Sopenharmony_ci                (True,  False, True,  True ): _hash_exception,
8757db96d56Sopenharmony_ci                (True,  True,  False, False): _hash_add,
8767db96d56Sopenharmony_ci                (True,  True,  False, True ): _hash_exception,
8777db96d56Sopenharmony_ci                (True,  True,  True,  False): _hash_add,
8787db96d56Sopenharmony_ci                (True,  True,  True,  True ): _hash_exception,
8797db96d56Sopenharmony_ci                }
8807db96d56Sopenharmony_ci# See https://bugs.python.org/issue32929#msg312829 for an if-statement
8817db96d56Sopenharmony_ci# version of this table.
8827db96d56Sopenharmony_ci
8837db96d56Sopenharmony_ci
8847db96d56Sopenharmony_cidef _process_class(cls, init, repr, eq, order, unsafe_hash, frozen,
8857db96d56Sopenharmony_ci                   match_args, kw_only, slots, weakref_slot):
8867db96d56Sopenharmony_ci    # Now that dicts retain insertion order, there's no reason to use
8877db96d56Sopenharmony_ci    # an ordered dict.  I am leveraging that ordering here, because
8887db96d56Sopenharmony_ci    # derived class fields overwrite base class fields, but the order
8897db96d56Sopenharmony_ci    # is defined by the base class, which is found first.
8907db96d56Sopenharmony_ci    fields = {}
8917db96d56Sopenharmony_ci
8927db96d56Sopenharmony_ci    if cls.__module__ in sys.modules:
8937db96d56Sopenharmony_ci        globals = sys.modules[cls.__module__].__dict__
8947db96d56Sopenharmony_ci    else:
8957db96d56Sopenharmony_ci        # Theoretically this can happen if someone writes
8967db96d56Sopenharmony_ci        # a custom string to cls.__module__.  In which case
8977db96d56Sopenharmony_ci        # such dataclass won't be fully introspectable
8987db96d56Sopenharmony_ci        # (w.r.t. typing.get_type_hints) but will still function
8997db96d56Sopenharmony_ci        # correctly.
9007db96d56Sopenharmony_ci        globals = {}
9017db96d56Sopenharmony_ci
9027db96d56Sopenharmony_ci    setattr(cls, _PARAMS, _DataclassParams(init, repr, eq, order,
9037db96d56Sopenharmony_ci                                           unsafe_hash, frozen))
9047db96d56Sopenharmony_ci
9057db96d56Sopenharmony_ci    # Find our base classes in reverse MRO order, and exclude
9067db96d56Sopenharmony_ci    # ourselves.  In reversed order so that more derived classes
9077db96d56Sopenharmony_ci    # override earlier field definitions in base classes.  As long as
9087db96d56Sopenharmony_ci    # we're iterating over them, see if any are frozen.
9097db96d56Sopenharmony_ci    any_frozen_base = False
9107db96d56Sopenharmony_ci    has_dataclass_bases = False
9117db96d56Sopenharmony_ci    for b in cls.__mro__[-1:0:-1]:
9127db96d56Sopenharmony_ci        # Only process classes that have been processed by our
9137db96d56Sopenharmony_ci        # decorator.  That is, they have a _FIELDS attribute.
9147db96d56Sopenharmony_ci        base_fields = getattr(b, _FIELDS, None)
9157db96d56Sopenharmony_ci        if base_fields is not None:
9167db96d56Sopenharmony_ci            has_dataclass_bases = True
9177db96d56Sopenharmony_ci            for f in base_fields.values():
9187db96d56Sopenharmony_ci                fields[f.name] = f
9197db96d56Sopenharmony_ci            if getattr(b, _PARAMS).frozen:
9207db96d56Sopenharmony_ci                any_frozen_base = True
9217db96d56Sopenharmony_ci
9227db96d56Sopenharmony_ci    # Annotations that are defined in this class (not in base
9237db96d56Sopenharmony_ci    # classes).  If __annotations__ isn't present, then this class
9247db96d56Sopenharmony_ci    # adds no new annotations.  We use this to compute fields that are
9257db96d56Sopenharmony_ci    # added by this class.
9267db96d56Sopenharmony_ci    #
9277db96d56Sopenharmony_ci    # Fields are found from cls_annotations, which is guaranteed to be
9287db96d56Sopenharmony_ci    # ordered.  Default values are from class attributes, if a field
9297db96d56Sopenharmony_ci    # has a default.  If the default value is a Field(), then it
9307db96d56Sopenharmony_ci    # contains additional info beyond (and possibly including) the
9317db96d56Sopenharmony_ci    # actual default value.  Pseudo-fields ClassVars and InitVars are
9327db96d56Sopenharmony_ci    # included, despite the fact that they're not real fields.  That's
9337db96d56Sopenharmony_ci    # dealt with later.
9347db96d56Sopenharmony_ci    cls_annotations = cls.__dict__.get('__annotations__', {})
9357db96d56Sopenharmony_ci
9367db96d56Sopenharmony_ci    # Now find fields in our class.  While doing so, validate some
9377db96d56Sopenharmony_ci    # things, and set the default values (as class attributes) where
9387db96d56Sopenharmony_ci    # we can.
9397db96d56Sopenharmony_ci    cls_fields = []
9407db96d56Sopenharmony_ci    # Get a reference to this module for the _is_kw_only() test.
9417db96d56Sopenharmony_ci    KW_ONLY_seen = False
9427db96d56Sopenharmony_ci    dataclasses = sys.modules[__name__]
9437db96d56Sopenharmony_ci    for name, type in cls_annotations.items():
9447db96d56Sopenharmony_ci        # See if this is a marker to change the value of kw_only.
9457db96d56Sopenharmony_ci        if (_is_kw_only(type, dataclasses)
9467db96d56Sopenharmony_ci            or (isinstance(type, str)
9477db96d56Sopenharmony_ci                and _is_type(type, cls, dataclasses, dataclasses.KW_ONLY,
9487db96d56Sopenharmony_ci                             _is_kw_only))):
9497db96d56Sopenharmony_ci            # Switch the default to kw_only=True, and ignore this
9507db96d56Sopenharmony_ci            # annotation: it's not a real field.
9517db96d56Sopenharmony_ci            if KW_ONLY_seen:
9527db96d56Sopenharmony_ci                raise TypeError(f'{name!r} is KW_ONLY, but KW_ONLY '
9537db96d56Sopenharmony_ci                                'has already been specified')
9547db96d56Sopenharmony_ci            KW_ONLY_seen = True
9557db96d56Sopenharmony_ci            kw_only = True
9567db96d56Sopenharmony_ci        else:
9577db96d56Sopenharmony_ci            # Otherwise it's a field of some type.
9587db96d56Sopenharmony_ci            cls_fields.append(_get_field(cls, name, type, kw_only))
9597db96d56Sopenharmony_ci
9607db96d56Sopenharmony_ci    for f in cls_fields:
9617db96d56Sopenharmony_ci        fields[f.name] = f
9627db96d56Sopenharmony_ci
9637db96d56Sopenharmony_ci        # If the class attribute (which is the default value for this
9647db96d56Sopenharmony_ci        # field) exists and is of type 'Field', replace it with the
9657db96d56Sopenharmony_ci        # real default.  This is so that normal class introspection
9667db96d56Sopenharmony_ci        # sees a real default value, not a Field.
9677db96d56Sopenharmony_ci        if isinstance(getattr(cls, f.name, None), Field):
9687db96d56Sopenharmony_ci            if f.default is MISSING:
9697db96d56Sopenharmony_ci                # If there's no default, delete the class attribute.
9707db96d56Sopenharmony_ci                # This happens if we specify field(repr=False), for
9717db96d56Sopenharmony_ci                # example (that is, we specified a field object, but
9727db96d56Sopenharmony_ci                # no default value).  Also if we're using a default
9737db96d56Sopenharmony_ci                # factory.  The class attribute should not be set at
9747db96d56Sopenharmony_ci                # all in the post-processed class.
9757db96d56Sopenharmony_ci                delattr(cls, f.name)
9767db96d56Sopenharmony_ci            else:
9777db96d56Sopenharmony_ci                setattr(cls, f.name, f.default)
9787db96d56Sopenharmony_ci
9797db96d56Sopenharmony_ci    # Do we have any Field members that don't also have annotations?
9807db96d56Sopenharmony_ci    for name, value in cls.__dict__.items():
9817db96d56Sopenharmony_ci        if isinstance(value, Field) and not name in cls_annotations:
9827db96d56Sopenharmony_ci            raise TypeError(f'{name!r} is a field but has no type annotation')
9837db96d56Sopenharmony_ci
9847db96d56Sopenharmony_ci    # Check rules that apply if we are derived from any dataclasses.
9857db96d56Sopenharmony_ci    if has_dataclass_bases:
9867db96d56Sopenharmony_ci        # Raise an exception if any of our bases are frozen, but we're not.
9877db96d56Sopenharmony_ci        if any_frozen_base and not frozen:
9887db96d56Sopenharmony_ci            raise TypeError('cannot inherit non-frozen dataclass from a '
9897db96d56Sopenharmony_ci                            'frozen one')
9907db96d56Sopenharmony_ci
9917db96d56Sopenharmony_ci        # Raise an exception if we're frozen, but none of our bases are.
9927db96d56Sopenharmony_ci        if not any_frozen_base and frozen:
9937db96d56Sopenharmony_ci            raise TypeError('cannot inherit frozen dataclass from a '
9947db96d56Sopenharmony_ci                            'non-frozen one')
9957db96d56Sopenharmony_ci
9967db96d56Sopenharmony_ci    # Remember all of the fields on our class (including bases).  This
9977db96d56Sopenharmony_ci    # also marks this class as being a dataclass.
9987db96d56Sopenharmony_ci    setattr(cls, _FIELDS, fields)
9997db96d56Sopenharmony_ci
10007db96d56Sopenharmony_ci    # Was this class defined with an explicit __hash__?  Note that if
10017db96d56Sopenharmony_ci    # __eq__ is defined in this class, then python will automatically
10027db96d56Sopenharmony_ci    # set __hash__ to None.  This is a heuristic, as it's possible
10037db96d56Sopenharmony_ci    # that such a __hash__ == None was not auto-generated, but it
10047db96d56Sopenharmony_ci    # close enough.
10057db96d56Sopenharmony_ci    class_hash = cls.__dict__.get('__hash__', MISSING)
10067db96d56Sopenharmony_ci    has_explicit_hash = not (class_hash is MISSING or
10077db96d56Sopenharmony_ci                             (class_hash is None and '__eq__' in cls.__dict__))
10087db96d56Sopenharmony_ci
10097db96d56Sopenharmony_ci    # If we're generating ordering methods, we must be generating the
10107db96d56Sopenharmony_ci    # eq methods.
10117db96d56Sopenharmony_ci    if order and not eq:
10127db96d56Sopenharmony_ci        raise ValueError('eq must be true if order is true')
10137db96d56Sopenharmony_ci
10147db96d56Sopenharmony_ci    # Include InitVars and regular fields (so, not ClassVars).  This is
10157db96d56Sopenharmony_ci    # initialized here, outside of the "if init:" test, because std_init_fields
10167db96d56Sopenharmony_ci    # is used with match_args, below.
10177db96d56Sopenharmony_ci    all_init_fields = [f for f in fields.values()
10187db96d56Sopenharmony_ci                       if f._field_type in (_FIELD, _FIELD_INITVAR)]
10197db96d56Sopenharmony_ci    (std_init_fields,
10207db96d56Sopenharmony_ci     kw_only_init_fields) = _fields_in_init_order(all_init_fields)
10217db96d56Sopenharmony_ci
10227db96d56Sopenharmony_ci    if init:
10237db96d56Sopenharmony_ci        # Does this class have a post-init function?
10247db96d56Sopenharmony_ci        has_post_init = hasattr(cls, _POST_INIT_NAME)
10257db96d56Sopenharmony_ci
10267db96d56Sopenharmony_ci        _set_new_attribute(cls, '__init__',
10277db96d56Sopenharmony_ci                           _init_fn(all_init_fields,
10287db96d56Sopenharmony_ci                                    std_init_fields,
10297db96d56Sopenharmony_ci                                    kw_only_init_fields,
10307db96d56Sopenharmony_ci                                    frozen,
10317db96d56Sopenharmony_ci                                    has_post_init,
10327db96d56Sopenharmony_ci                                    # The name to use for the "self"
10337db96d56Sopenharmony_ci                                    # param in __init__.  Use "self"
10347db96d56Sopenharmony_ci                                    # if possible.
10357db96d56Sopenharmony_ci                                    '__dataclass_self__' if 'self' in fields
10367db96d56Sopenharmony_ci                                            else 'self',
10377db96d56Sopenharmony_ci                                    globals,
10387db96d56Sopenharmony_ci                                    slots,
10397db96d56Sopenharmony_ci                          ))
10407db96d56Sopenharmony_ci
10417db96d56Sopenharmony_ci    # Get the fields as a list, and include only real fields.  This is
10427db96d56Sopenharmony_ci    # used in all of the following methods.
10437db96d56Sopenharmony_ci    field_list = [f for f in fields.values() if f._field_type is _FIELD]
10447db96d56Sopenharmony_ci
10457db96d56Sopenharmony_ci    if repr:
10467db96d56Sopenharmony_ci        flds = [f for f in field_list if f.repr]
10477db96d56Sopenharmony_ci        _set_new_attribute(cls, '__repr__', _repr_fn(flds, globals))
10487db96d56Sopenharmony_ci
10497db96d56Sopenharmony_ci    if eq:
10507db96d56Sopenharmony_ci        # Create __eq__ method.  There's no need for a __ne__ method,
10517db96d56Sopenharmony_ci        # since python will call __eq__ and negate it.
10527db96d56Sopenharmony_ci        flds = [f for f in field_list if f.compare]
10537db96d56Sopenharmony_ci        self_tuple = _tuple_str('self', flds)
10547db96d56Sopenharmony_ci        other_tuple = _tuple_str('other', flds)
10557db96d56Sopenharmony_ci        _set_new_attribute(cls, '__eq__',
10567db96d56Sopenharmony_ci                           _cmp_fn('__eq__', '==',
10577db96d56Sopenharmony_ci                                   self_tuple, other_tuple,
10587db96d56Sopenharmony_ci                                   globals=globals))
10597db96d56Sopenharmony_ci
10607db96d56Sopenharmony_ci    if order:
10617db96d56Sopenharmony_ci        # Create and set the ordering methods.
10627db96d56Sopenharmony_ci        flds = [f for f in field_list if f.compare]
10637db96d56Sopenharmony_ci        self_tuple = _tuple_str('self', flds)
10647db96d56Sopenharmony_ci        other_tuple = _tuple_str('other', flds)
10657db96d56Sopenharmony_ci        for name, op in [('__lt__', '<'),
10667db96d56Sopenharmony_ci                         ('__le__', '<='),
10677db96d56Sopenharmony_ci                         ('__gt__', '>'),
10687db96d56Sopenharmony_ci                         ('__ge__', '>='),
10697db96d56Sopenharmony_ci                         ]:
10707db96d56Sopenharmony_ci            if _set_new_attribute(cls, name,
10717db96d56Sopenharmony_ci                                  _cmp_fn(name, op, self_tuple, other_tuple,
10727db96d56Sopenharmony_ci                                          globals=globals)):
10737db96d56Sopenharmony_ci                raise TypeError(f'Cannot overwrite attribute {name} '
10747db96d56Sopenharmony_ci                                f'in class {cls.__name__}. Consider using '
10757db96d56Sopenharmony_ci                                'functools.total_ordering')
10767db96d56Sopenharmony_ci
10777db96d56Sopenharmony_ci    if frozen:
10787db96d56Sopenharmony_ci        for fn in _frozen_get_del_attr(cls, field_list, globals):
10797db96d56Sopenharmony_ci            if _set_new_attribute(cls, fn.__name__, fn):
10807db96d56Sopenharmony_ci                raise TypeError(f'Cannot overwrite attribute {fn.__name__} '
10817db96d56Sopenharmony_ci                                f'in class {cls.__name__}')
10827db96d56Sopenharmony_ci
10837db96d56Sopenharmony_ci    # Decide if/how we're going to create a hash function.
10847db96d56Sopenharmony_ci    hash_action = _hash_action[bool(unsafe_hash),
10857db96d56Sopenharmony_ci                               bool(eq),
10867db96d56Sopenharmony_ci                               bool(frozen),
10877db96d56Sopenharmony_ci                               has_explicit_hash]
10887db96d56Sopenharmony_ci    if hash_action:
10897db96d56Sopenharmony_ci        # No need to call _set_new_attribute here, since by the time
10907db96d56Sopenharmony_ci        # we're here the overwriting is unconditional.
10917db96d56Sopenharmony_ci        cls.__hash__ = hash_action(cls, field_list, globals)
10927db96d56Sopenharmony_ci
10937db96d56Sopenharmony_ci    if not getattr(cls, '__doc__'):
10947db96d56Sopenharmony_ci        # Create a class doc-string.
10957db96d56Sopenharmony_ci        try:
10967db96d56Sopenharmony_ci            # In some cases fetching a signature is not possible.
10977db96d56Sopenharmony_ci            # But, we surely should not fail in this case.
10987db96d56Sopenharmony_ci            text_sig = str(inspect.signature(cls)).replace(' -> None', '')
10997db96d56Sopenharmony_ci        except (TypeError, ValueError):
11007db96d56Sopenharmony_ci            text_sig = ''
11017db96d56Sopenharmony_ci        cls.__doc__ = (cls.__name__ + text_sig)
11027db96d56Sopenharmony_ci
11037db96d56Sopenharmony_ci    if match_args:
11047db96d56Sopenharmony_ci        # I could probably compute this once
11057db96d56Sopenharmony_ci        _set_new_attribute(cls, '__match_args__',
11067db96d56Sopenharmony_ci                           tuple(f.name for f in std_init_fields))
11077db96d56Sopenharmony_ci
11087db96d56Sopenharmony_ci    # It's an error to specify weakref_slot if slots is False.
11097db96d56Sopenharmony_ci    if weakref_slot and not slots:
11107db96d56Sopenharmony_ci        raise TypeError('weakref_slot is True but slots is False')
11117db96d56Sopenharmony_ci    if slots:
11127db96d56Sopenharmony_ci        cls = _add_slots(cls, frozen, weakref_slot)
11137db96d56Sopenharmony_ci
11147db96d56Sopenharmony_ci    abc.update_abstractmethods(cls)
11157db96d56Sopenharmony_ci
11167db96d56Sopenharmony_ci    return cls
11177db96d56Sopenharmony_ci
11187db96d56Sopenharmony_ci
11197db96d56Sopenharmony_ci# _dataclass_getstate and _dataclass_setstate are needed for pickling frozen
11207db96d56Sopenharmony_ci# classes with slots.  These could be slightly more performant if we generated
11217db96d56Sopenharmony_ci# the code instead of iterating over fields.  But that can be a project for
11227db96d56Sopenharmony_ci# another day, if performance becomes an issue.
11237db96d56Sopenharmony_cidef _dataclass_getstate(self):
11247db96d56Sopenharmony_ci    return [getattr(self, f.name) for f in fields(self)]
11257db96d56Sopenharmony_ci
11267db96d56Sopenharmony_ci
11277db96d56Sopenharmony_cidef _dataclass_setstate(self, state):
11287db96d56Sopenharmony_ci    for field, value in zip(fields(self), state):
11297db96d56Sopenharmony_ci        # use setattr because dataclass may be frozen
11307db96d56Sopenharmony_ci        object.__setattr__(self, field.name, value)
11317db96d56Sopenharmony_ci
11327db96d56Sopenharmony_ci
11337db96d56Sopenharmony_cidef _get_slots(cls):
11347db96d56Sopenharmony_ci    match cls.__dict__.get('__slots__'):
11357db96d56Sopenharmony_ci        case None:
11367db96d56Sopenharmony_ci            return
11377db96d56Sopenharmony_ci        case str(slot):
11387db96d56Sopenharmony_ci            yield slot
11397db96d56Sopenharmony_ci        # Slots may be any iterable, but we cannot handle an iterator
11407db96d56Sopenharmony_ci        # because it will already be (partially) consumed.
11417db96d56Sopenharmony_ci        case iterable if not hasattr(iterable, '__next__'):
11427db96d56Sopenharmony_ci            yield from iterable
11437db96d56Sopenharmony_ci        case _:
11447db96d56Sopenharmony_ci            raise TypeError(f"Slots of '{cls.__name__}' cannot be determined")
11457db96d56Sopenharmony_ci
11467db96d56Sopenharmony_ci
11477db96d56Sopenharmony_cidef _add_slots(cls, is_frozen, weakref_slot):
11487db96d56Sopenharmony_ci    # Need to create a new class, since we can't set __slots__
11497db96d56Sopenharmony_ci    #  after a class has been created.
11507db96d56Sopenharmony_ci
11517db96d56Sopenharmony_ci    # Make sure __slots__ isn't already set.
11527db96d56Sopenharmony_ci    if '__slots__' in cls.__dict__:
11537db96d56Sopenharmony_ci        raise TypeError(f'{cls.__name__} already specifies __slots__')
11547db96d56Sopenharmony_ci
11557db96d56Sopenharmony_ci    # Create a new dict for our new class.
11567db96d56Sopenharmony_ci    cls_dict = dict(cls.__dict__)
11577db96d56Sopenharmony_ci    field_names = tuple(f.name for f in fields(cls))
11587db96d56Sopenharmony_ci    # Make sure slots don't overlap with those in base classes.
11597db96d56Sopenharmony_ci    inherited_slots = set(
11607db96d56Sopenharmony_ci        itertools.chain.from_iterable(map(_get_slots, cls.__mro__[1:-1]))
11617db96d56Sopenharmony_ci    )
11627db96d56Sopenharmony_ci    # The slots for our class.  Remove slots from our base classes.  Add
11637db96d56Sopenharmony_ci    # '__weakref__' if weakref_slot was given, unless it is already present.
11647db96d56Sopenharmony_ci    cls_dict["__slots__"] = tuple(
11657db96d56Sopenharmony_ci        itertools.filterfalse(
11667db96d56Sopenharmony_ci            inherited_slots.__contains__,
11677db96d56Sopenharmony_ci            itertools.chain(
11687db96d56Sopenharmony_ci                # gh-93521: '__weakref__' also needs to be filtered out if
11697db96d56Sopenharmony_ci                # already present in inherited_slots
11707db96d56Sopenharmony_ci                field_names, ('__weakref__',) if weakref_slot else ()
11717db96d56Sopenharmony_ci            )
11727db96d56Sopenharmony_ci        ),
11737db96d56Sopenharmony_ci    )
11747db96d56Sopenharmony_ci
11757db96d56Sopenharmony_ci    for field_name in field_names:
11767db96d56Sopenharmony_ci        # Remove our attributes, if present. They'll still be
11777db96d56Sopenharmony_ci        #  available in _MARKER.
11787db96d56Sopenharmony_ci        cls_dict.pop(field_name, None)
11797db96d56Sopenharmony_ci
11807db96d56Sopenharmony_ci    # Remove __dict__ itself.
11817db96d56Sopenharmony_ci    cls_dict.pop('__dict__', None)
11827db96d56Sopenharmony_ci
11837db96d56Sopenharmony_ci    # Clear existing `__weakref__` descriptor, it belongs to a previous type:
11847db96d56Sopenharmony_ci    cls_dict.pop('__weakref__', None)  # gh-102069
11857db96d56Sopenharmony_ci
11867db96d56Sopenharmony_ci    # And finally create the class.
11877db96d56Sopenharmony_ci    qualname = getattr(cls, '__qualname__', None)
11887db96d56Sopenharmony_ci    cls = type(cls)(cls.__name__, cls.__bases__, cls_dict)
11897db96d56Sopenharmony_ci    if qualname is not None:
11907db96d56Sopenharmony_ci        cls.__qualname__ = qualname
11917db96d56Sopenharmony_ci
11927db96d56Sopenharmony_ci    if is_frozen:
11937db96d56Sopenharmony_ci        # Need this for pickling frozen classes with slots.
11947db96d56Sopenharmony_ci        if '__getstate__' not in cls_dict:
11957db96d56Sopenharmony_ci            cls.__getstate__ = _dataclass_getstate
11967db96d56Sopenharmony_ci        if '__setstate__' not in cls_dict:
11977db96d56Sopenharmony_ci            cls.__setstate__ = _dataclass_setstate
11987db96d56Sopenharmony_ci
11997db96d56Sopenharmony_ci    return cls
12007db96d56Sopenharmony_ci
12017db96d56Sopenharmony_ci
12027db96d56Sopenharmony_cidef dataclass(cls=None, /, *, init=True, repr=True, eq=True, order=False,
12037db96d56Sopenharmony_ci              unsafe_hash=False, frozen=False, match_args=True,
12047db96d56Sopenharmony_ci              kw_only=False, slots=False, weakref_slot=False):
12057db96d56Sopenharmony_ci    """Add dunder methods based on the fields defined in the class.
12067db96d56Sopenharmony_ci
12077db96d56Sopenharmony_ci    Examines PEP 526 __annotations__ to determine fields.
12087db96d56Sopenharmony_ci
12097db96d56Sopenharmony_ci    If init is true, an __init__() method is added to the class. If repr
12107db96d56Sopenharmony_ci    is true, a __repr__() method is added. If order is true, rich
12117db96d56Sopenharmony_ci    comparison dunder methods are added. If unsafe_hash is true, a
12127db96d56Sopenharmony_ci    __hash__() method is added. If frozen is true, fields may not be
12137db96d56Sopenharmony_ci    assigned to after instance creation. If match_args is true, the
12147db96d56Sopenharmony_ci    __match_args__ tuple is added. If kw_only is true, then by default
12157db96d56Sopenharmony_ci    all fields are keyword-only. If slots is true, a new class with a
12167db96d56Sopenharmony_ci    __slots__ attribute is returned.
12177db96d56Sopenharmony_ci    """
12187db96d56Sopenharmony_ci
12197db96d56Sopenharmony_ci    def wrap(cls):
12207db96d56Sopenharmony_ci        return _process_class(cls, init, repr, eq, order, unsafe_hash,
12217db96d56Sopenharmony_ci                              frozen, match_args, kw_only, slots,
12227db96d56Sopenharmony_ci                              weakref_slot)
12237db96d56Sopenharmony_ci
12247db96d56Sopenharmony_ci    # See if we're being called as @dataclass or @dataclass().
12257db96d56Sopenharmony_ci    if cls is None:
12267db96d56Sopenharmony_ci        # We're called with parens.
12277db96d56Sopenharmony_ci        return wrap
12287db96d56Sopenharmony_ci
12297db96d56Sopenharmony_ci    # We're called as @dataclass without parens.
12307db96d56Sopenharmony_ci    return wrap(cls)
12317db96d56Sopenharmony_ci
12327db96d56Sopenharmony_ci
12337db96d56Sopenharmony_cidef fields(class_or_instance):
12347db96d56Sopenharmony_ci    """Return a tuple describing the fields of this dataclass.
12357db96d56Sopenharmony_ci
12367db96d56Sopenharmony_ci    Accepts a dataclass or an instance of one. Tuple elements are of
12377db96d56Sopenharmony_ci    type Field.
12387db96d56Sopenharmony_ci    """
12397db96d56Sopenharmony_ci
12407db96d56Sopenharmony_ci    # Might it be worth caching this, per class?
12417db96d56Sopenharmony_ci    try:
12427db96d56Sopenharmony_ci        fields = getattr(class_or_instance, _FIELDS)
12437db96d56Sopenharmony_ci    except AttributeError:
12447db96d56Sopenharmony_ci        raise TypeError('must be called with a dataclass type or instance') from None
12457db96d56Sopenharmony_ci
12467db96d56Sopenharmony_ci    # Exclude pseudo-fields.  Note that fields is sorted by insertion
12477db96d56Sopenharmony_ci    # order, so the order of the tuple is as the fields were defined.
12487db96d56Sopenharmony_ci    return tuple(f for f in fields.values() if f._field_type is _FIELD)
12497db96d56Sopenharmony_ci
12507db96d56Sopenharmony_ci
12517db96d56Sopenharmony_cidef _is_dataclass_instance(obj):
12527db96d56Sopenharmony_ci    """Returns True if obj is an instance of a dataclass."""
12537db96d56Sopenharmony_ci    return hasattr(type(obj), _FIELDS)
12547db96d56Sopenharmony_ci
12557db96d56Sopenharmony_ci
12567db96d56Sopenharmony_cidef is_dataclass(obj):
12577db96d56Sopenharmony_ci    """Returns True if obj is a dataclass or an instance of a
12587db96d56Sopenharmony_ci    dataclass."""
12597db96d56Sopenharmony_ci    cls = obj if isinstance(obj, type) else type(obj)
12607db96d56Sopenharmony_ci    return hasattr(cls, _FIELDS)
12617db96d56Sopenharmony_ci
12627db96d56Sopenharmony_ci
12637db96d56Sopenharmony_cidef asdict(obj, *, dict_factory=dict):
12647db96d56Sopenharmony_ci    """Return the fields of a dataclass instance as a new dictionary mapping
12657db96d56Sopenharmony_ci    field names to field values.
12667db96d56Sopenharmony_ci
12677db96d56Sopenharmony_ci    Example usage::
12687db96d56Sopenharmony_ci
12697db96d56Sopenharmony_ci      @dataclass
12707db96d56Sopenharmony_ci      class C:
12717db96d56Sopenharmony_ci          x: int
12727db96d56Sopenharmony_ci          y: int
12737db96d56Sopenharmony_ci
12747db96d56Sopenharmony_ci      c = C(1, 2)
12757db96d56Sopenharmony_ci      assert asdict(c) == {'x': 1, 'y': 2}
12767db96d56Sopenharmony_ci
12777db96d56Sopenharmony_ci    If given, 'dict_factory' will be used instead of built-in dict.
12787db96d56Sopenharmony_ci    The function applies recursively to field values that are
12797db96d56Sopenharmony_ci    dataclass instances. This will also look into built-in containers:
12807db96d56Sopenharmony_ci    tuples, lists, and dicts.
12817db96d56Sopenharmony_ci    """
12827db96d56Sopenharmony_ci    if not _is_dataclass_instance(obj):
12837db96d56Sopenharmony_ci        raise TypeError("asdict() should be called on dataclass instances")
12847db96d56Sopenharmony_ci    return _asdict_inner(obj, dict_factory)
12857db96d56Sopenharmony_ci
12867db96d56Sopenharmony_ci
12877db96d56Sopenharmony_cidef _asdict_inner(obj, dict_factory):
12887db96d56Sopenharmony_ci    if _is_dataclass_instance(obj):
12897db96d56Sopenharmony_ci        result = []
12907db96d56Sopenharmony_ci        for f in fields(obj):
12917db96d56Sopenharmony_ci            value = _asdict_inner(getattr(obj, f.name), dict_factory)
12927db96d56Sopenharmony_ci            result.append((f.name, value))
12937db96d56Sopenharmony_ci        return dict_factory(result)
12947db96d56Sopenharmony_ci    elif isinstance(obj, tuple) and hasattr(obj, '_fields'):
12957db96d56Sopenharmony_ci        # obj is a namedtuple.  Recurse into it, but the returned
12967db96d56Sopenharmony_ci        # object is another namedtuple of the same type.  This is
12977db96d56Sopenharmony_ci        # similar to how other list- or tuple-derived classes are
12987db96d56Sopenharmony_ci        # treated (see below), but we just need to create them
12997db96d56Sopenharmony_ci        # differently because a namedtuple's __init__ needs to be
13007db96d56Sopenharmony_ci        # called differently (see bpo-34363).
13017db96d56Sopenharmony_ci
13027db96d56Sopenharmony_ci        # I'm not using namedtuple's _asdict()
13037db96d56Sopenharmony_ci        # method, because:
13047db96d56Sopenharmony_ci        # - it does not recurse in to the namedtuple fields and
13057db96d56Sopenharmony_ci        #   convert them to dicts (using dict_factory).
13067db96d56Sopenharmony_ci        # - I don't actually want to return a dict here.  The main
13077db96d56Sopenharmony_ci        #   use case here is json.dumps, and it handles converting
13087db96d56Sopenharmony_ci        #   namedtuples to lists.  Admittedly we're losing some
13097db96d56Sopenharmony_ci        #   information here when we produce a json list instead of a
13107db96d56Sopenharmony_ci        #   dict.  Note that if we returned dicts here instead of
13117db96d56Sopenharmony_ci        #   namedtuples, we could no longer call asdict() on a data
13127db96d56Sopenharmony_ci        #   structure where a namedtuple was used as a dict key.
13137db96d56Sopenharmony_ci
13147db96d56Sopenharmony_ci        return type(obj)(*[_asdict_inner(v, dict_factory) for v in obj])
13157db96d56Sopenharmony_ci    elif isinstance(obj, (list, tuple)):
13167db96d56Sopenharmony_ci        # Assume we can create an object of this type by passing in a
13177db96d56Sopenharmony_ci        # generator (which is not true for namedtuples, handled
13187db96d56Sopenharmony_ci        # above).
13197db96d56Sopenharmony_ci        return type(obj)(_asdict_inner(v, dict_factory) for v in obj)
13207db96d56Sopenharmony_ci    elif isinstance(obj, dict):
13217db96d56Sopenharmony_ci        return type(obj)((_asdict_inner(k, dict_factory),
13227db96d56Sopenharmony_ci                          _asdict_inner(v, dict_factory))
13237db96d56Sopenharmony_ci                         for k, v in obj.items())
13247db96d56Sopenharmony_ci    else:
13257db96d56Sopenharmony_ci        return copy.deepcopy(obj)
13267db96d56Sopenharmony_ci
13277db96d56Sopenharmony_ci
13287db96d56Sopenharmony_cidef astuple(obj, *, tuple_factory=tuple):
13297db96d56Sopenharmony_ci    """Return the fields of a dataclass instance as a new tuple of field values.
13307db96d56Sopenharmony_ci
13317db96d56Sopenharmony_ci    Example usage::
13327db96d56Sopenharmony_ci
13337db96d56Sopenharmony_ci      @dataclass
13347db96d56Sopenharmony_ci      class C:
13357db96d56Sopenharmony_ci          x: int
13367db96d56Sopenharmony_ci          y: int
13377db96d56Sopenharmony_ci
13387db96d56Sopenharmony_ci      c = C(1, 2)
13397db96d56Sopenharmony_ci      assert astuple(c) == (1, 2)
13407db96d56Sopenharmony_ci
13417db96d56Sopenharmony_ci    If given, 'tuple_factory' will be used instead of built-in tuple.
13427db96d56Sopenharmony_ci    The function applies recursively to field values that are
13437db96d56Sopenharmony_ci    dataclass instances. This will also look into built-in containers:
13447db96d56Sopenharmony_ci    tuples, lists, and dicts.
13457db96d56Sopenharmony_ci    """
13467db96d56Sopenharmony_ci
13477db96d56Sopenharmony_ci    if not _is_dataclass_instance(obj):
13487db96d56Sopenharmony_ci        raise TypeError("astuple() should be called on dataclass instances")
13497db96d56Sopenharmony_ci    return _astuple_inner(obj, tuple_factory)
13507db96d56Sopenharmony_ci
13517db96d56Sopenharmony_ci
13527db96d56Sopenharmony_cidef _astuple_inner(obj, tuple_factory):
13537db96d56Sopenharmony_ci    if _is_dataclass_instance(obj):
13547db96d56Sopenharmony_ci        result = []
13557db96d56Sopenharmony_ci        for f in fields(obj):
13567db96d56Sopenharmony_ci            value = _astuple_inner(getattr(obj, f.name), tuple_factory)
13577db96d56Sopenharmony_ci            result.append(value)
13587db96d56Sopenharmony_ci        return tuple_factory(result)
13597db96d56Sopenharmony_ci    elif isinstance(obj, tuple) and hasattr(obj, '_fields'):
13607db96d56Sopenharmony_ci        # obj is a namedtuple.  Recurse into it, but the returned
13617db96d56Sopenharmony_ci        # object is another namedtuple of the same type.  This is
13627db96d56Sopenharmony_ci        # similar to how other list- or tuple-derived classes are
13637db96d56Sopenharmony_ci        # treated (see below), but we just need to create them
13647db96d56Sopenharmony_ci        # differently because a namedtuple's __init__ needs to be
13657db96d56Sopenharmony_ci        # called differently (see bpo-34363).
13667db96d56Sopenharmony_ci        return type(obj)(*[_astuple_inner(v, tuple_factory) for v in obj])
13677db96d56Sopenharmony_ci    elif isinstance(obj, (list, tuple)):
13687db96d56Sopenharmony_ci        # Assume we can create an object of this type by passing in a
13697db96d56Sopenharmony_ci        # generator (which is not true for namedtuples, handled
13707db96d56Sopenharmony_ci        # above).
13717db96d56Sopenharmony_ci        return type(obj)(_astuple_inner(v, tuple_factory) for v in obj)
13727db96d56Sopenharmony_ci    elif isinstance(obj, dict):
13737db96d56Sopenharmony_ci        return type(obj)((_astuple_inner(k, tuple_factory), _astuple_inner(v, tuple_factory))
13747db96d56Sopenharmony_ci                          for k, v in obj.items())
13757db96d56Sopenharmony_ci    else:
13767db96d56Sopenharmony_ci        return copy.deepcopy(obj)
13777db96d56Sopenharmony_ci
13787db96d56Sopenharmony_ci
13797db96d56Sopenharmony_cidef make_dataclass(cls_name, fields, *, bases=(), namespace=None, init=True,
13807db96d56Sopenharmony_ci                   repr=True, eq=True, order=False, unsafe_hash=False,
13817db96d56Sopenharmony_ci                   frozen=False, match_args=True, kw_only=False, slots=False,
13827db96d56Sopenharmony_ci                   weakref_slot=False):
13837db96d56Sopenharmony_ci    """Return a new dynamically created dataclass.
13847db96d56Sopenharmony_ci
13857db96d56Sopenharmony_ci    The dataclass name will be 'cls_name'.  'fields' is an iterable
13867db96d56Sopenharmony_ci    of either (name), (name, type) or (name, type, Field) objects. If type is
13877db96d56Sopenharmony_ci    omitted, use the string 'typing.Any'.  Field objects are created by
13887db96d56Sopenharmony_ci    the equivalent of calling 'field(name, type [, Field-info])'.::
13897db96d56Sopenharmony_ci
13907db96d56Sopenharmony_ci      C = make_dataclass('C', ['x', ('y', int), ('z', int, field(init=False))], bases=(Base,))
13917db96d56Sopenharmony_ci
13927db96d56Sopenharmony_ci    is equivalent to::
13937db96d56Sopenharmony_ci
13947db96d56Sopenharmony_ci      @dataclass
13957db96d56Sopenharmony_ci      class C(Base):
13967db96d56Sopenharmony_ci          x: 'typing.Any'
13977db96d56Sopenharmony_ci          y: int
13987db96d56Sopenharmony_ci          z: int = field(init=False)
13997db96d56Sopenharmony_ci
14007db96d56Sopenharmony_ci    For the bases and namespace parameters, see the builtin type() function.
14017db96d56Sopenharmony_ci
14027db96d56Sopenharmony_ci    The parameters init, repr, eq, order, unsafe_hash, and frozen are passed to
14037db96d56Sopenharmony_ci    dataclass().
14047db96d56Sopenharmony_ci    """
14057db96d56Sopenharmony_ci
14067db96d56Sopenharmony_ci    if namespace is None:
14077db96d56Sopenharmony_ci        namespace = {}
14087db96d56Sopenharmony_ci
14097db96d56Sopenharmony_ci    # While we're looking through the field names, validate that they
14107db96d56Sopenharmony_ci    # are identifiers, are not keywords, and not duplicates.
14117db96d56Sopenharmony_ci    seen = set()
14127db96d56Sopenharmony_ci    annotations = {}
14137db96d56Sopenharmony_ci    defaults = {}
14147db96d56Sopenharmony_ci    for item in fields:
14157db96d56Sopenharmony_ci        if isinstance(item, str):
14167db96d56Sopenharmony_ci            name = item
14177db96d56Sopenharmony_ci            tp = 'typing.Any'
14187db96d56Sopenharmony_ci        elif len(item) == 2:
14197db96d56Sopenharmony_ci            name, tp, = item
14207db96d56Sopenharmony_ci        elif len(item) == 3:
14217db96d56Sopenharmony_ci            name, tp, spec = item
14227db96d56Sopenharmony_ci            defaults[name] = spec
14237db96d56Sopenharmony_ci        else:
14247db96d56Sopenharmony_ci            raise TypeError(f'Invalid field: {item!r}')
14257db96d56Sopenharmony_ci
14267db96d56Sopenharmony_ci        if not isinstance(name, str) or not name.isidentifier():
14277db96d56Sopenharmony_ci            raise TypeError(f'Field names must be valid identifiers: {name!r}')
14287db96d56Sopenharmony_ci        if keyword.iskeyword(name):
14297db96d56Sopenharmony_ci            raise TypeError(f'Field names must not be keywords: {name!r}')
14307db96d56Sopenharmony_ci        if name in seen:
14317db96d56Sopenharmony_ci            raise TypeError(f'Field name duplicated: {name!r}')
14327db96d56Sopenharmony_ci
14337db96d56Sopenharmony_ci        seen.add(name)
14347db96d56Sopenharmony_ci        annotations[name] = tp
14357db96d56Sopenharmony_ci
14367db96d56Sopenharmony_ci    # Update 'ns' with the user-supplied namespace plus our calculated values.
14377db96d56Sopenharmony_ci    def exec_body_callback(ns):
14387db96d56Sopenharmony_ci        ns.update(namespace)
14397db96d56Sopenharmony_ci        ns.update(defaults)
14407db96d56Sopenharmony_ci        ns['__annotations__'] = annotations
14417db96d56Sopenharmony_ci
14427db96d56Sopenharmony_ci    # We use `types.new_class()` instead of simply `type()` to allow dynamic creation
14437db96d56Sopenharmony_ci    # of generic dataclasses.
14447db96d56Sopenharmony_ci    cls = types.new_class(cls_name, bases, {}, exec_body_callback)
14457db96d56Sopenharmony_ci
14467db96d56Sopenharmony_ci    # Apply the normal decorator.
14477db96d56Sopenharmony_ci    return dataclass(cls, init=init, repr=repr, eq=eq, order=order,
14487db96d56Sopenharmony_ci                     unsafe_hash=unsafe_hash, frozen=frozen,
14497db96d56Sopenharmony_ci                     match_args=match_args, kw_only=kw_only, slots=slots,
14507db96d56Sopenharmony_ci                     weakref_slot=weakref_slot)
14517db96d56Sopenharmony_ci
14527db96d56Sopenharmony_ci
14537db96d56Sopenharmony_cidef replace(obj, /, **changes):
14547db96d56Sopenharmony_ci    """Return a new object replacing specified fields with new values.
14557db96d56Sopenharmony_ci
14567db96d56Sopenharmony_ci    This is especially useful for frozen classes.  Example usage::
14577db96d56Sopenharmony_ci
14587db96d56Sopenharmony_ci      @dataclass(frozen=True)
14597db96d56Sopenharmony_ci      class C:
14607db96d56Sopenharmony_ci          x: int
14617db96d56Sopenharmony_ci          y: int
14627db96d56Sopenharmony_ci
14637db96d56Sopenharmony_ci      c = C(1, 2)
14647db96d56Sopenharmony_ci      c1 = replace(c, x=3)
14657db96d56Sopenharmony_ci      assert c1.x == 3 and c1.y == 2
14667db96d56Sopenharmony_ci    """
14677db96d56Sopenharmony_ci
14687db96d56Sopenharmony_ci    # We're going to mutate 'changes', but that's okay because it's a
14697db96d56Sopenharmony_ci    # new dict, even if called with 'replace(obj, **my_changes)'.
14707db96d56Sopenharmony_ci
14717db96d56Sopenharmony_ci    if not _is_dataclass_instance(obj):
14727db96d56Sopenharmony_ci        raise TypeError("replace() should be called on dataclass instances")
14737db96d56Sopenharmony_ci
14747db96d56Sopenharmony_ci    # It's an error to have init=False fields in 'changes'.
14757db96d56Sopenharmony_ci    # If a field is not in 'changes', read its value from the provided obj.
14767db96d56Sopenharmony_ci
14777db96d56Sopenharmony_ci    for f in getattr(obj, _FIELDS).values():
14787db96d56Sopenharmony_ci        # Only consider normal fields or InitVars.
14797db96d56Sopenharmony_ci        if f._field_type is _FIELD_CLASSVAR:
14807db96d56Sopenharmony_ci            continue
14817db96d56Sopenharmony_ci
14827db96d56Sopenharmony_ci        if not f.init:
14837db96d56Sopenharmony_ci            # Error if this field is specified in changes.
14847db96d56Sopenharmony_ci            if f.name in changes:
14857db96d56Sopenharmony_ci                raise ValueError(f'field {f.name} is declared with '
14867db96d56Sopenharmony_ci                                 'init=False, it cannot be specified with '
14877db96d56Sopenharmony_ci                                 'replace()')
14887db96d56Sopenharmony_ci            continue
14897db96d56Sopenharmony_ci
14907db96d56Sopenharmony_ci        if f.name not in changes:
14917db96d56Sopenharmony_ci            if f._field_type is _FIELD_INITVAR and f.default is MISSING:
14927db96d56Sopenharmony_ci                raise ValueError(f"InitVar {f.name!r} "
14937db96d56Sopenharmony_ci                                 'must be specified with replace()')
14947db96d56Sopenharmony_ci            changes[f.name] = getattr(obj, f.name)
14957db96d56Sopenharmony_ci
14967db96d56Sopenharmony_ci    # Create the new object, which calls __init__() and
14977db96d56Sopenharmony_ci    # __post_init__() (if defined), using all of the init fields we've
14987db96d56Sopenharmony_ci    # added and/or left in 'changes'.  If there are values supplied in
14997db96d56Sopenharmony_ci    # changes that aren't fields, this will correctly raise a
15007db96d56Sopenharmony_ci    # TypeError.
15017db96d56Sopenharmony_ci    return obj.__class__(**changes)
1502