# Source code for dataclass_wizard.v1.models

    import hashlib
    import sys
    import types
    from collections import defaultdict, deque
    from dataclasses import MISSING, Field as _Field
    from datetime import datetime, date, time, tzinfo, timezone, timedelta
    from typing import TYPE_CHECKING, Any, TypedDict, cast
    from zoneinfo import ZoneInfo, ZoneInfoNotFoundError

    from .decorators import setup_recursive_safe_function
    from ..constants import PY310_OR_ABOVE, PY311_OR_ABOVE, PY314_OR_ABOVE
    from ..log import LOG
    from ..type_def import DefFactory, ExplicitNull, PyNotRequired, NoneType
    from ..utils.function_builder import FunctionBuilder
    from ..utils.object_path import split_object_path
    from ..utils.typing_compat import get_origin_v2

    if TYPE_CHECKING:  # pragma: no cover
        from ..bases import META

    # UTC Time Zone
    if PY311_OR_ABOVE:
        # https://docs.python.org/3/library/datetime.html#datetime.UTC
        from datetime import UTC
    else:
        UTC: timezone = timezone.utc

    # UTC time zone (no offset)
    ZERO: timedelta = timedelta(0)

    _BUILTIN_COLLECTION_TYPES = frozenset({
        list,
        set,
        dict,
        tuple,
        frozenset,
    })

    # FIXME: Python 3.9 doesn't have `types.EllipsisType` or `types.NotImplementedType`
    EllipsisType = getattr(types, 'EllipsisType', type(Ellipsis))
    NotImplementedType = getattr(types, 'NotImplementedType', type(NotImplemented))

    LEAF_TYPES_NO_BYTES = frozenset({
        # Common JSON Serializable types
        NoneType,
        bool,
        int,
        float,
        str,
        # Other common types
        complex,
        # exclude bytes, since the serialization process is slightly different
        # Other types that are also unaffected by deepcopy
        EllipsisType,
        NotImplementedType,
        types.CodeType,
        types.BuiltinFunctionType,
        types.FunctionType,
        type,
        range,
        property,
    })

    # Atomic immutable types which don't require any recursive handling and for which deepcopy
    # returns the same object. We can provide a fast-path for these types in asdict and astuple.
    #
    # Credits: `_ATOMIC_TYPES` from `dataclasses.py`
    LEAF_TYPES = LEAF_TYPES_NO_BYTES | {bytes}

    SEQUENCE_ORIGINS = frozenset({
        list,
        tuple,
        set,
        frozenset,
        deque
    })

    MAPPING_ORIGINS = frozenset({
        dict,
        defaultdict
    })

    def get_zoneinfo(key: str) -> ZoneInfo:
        try:
            return ZoneInfo(key)
        except ZoneInfoNotFoundError:
            if sys.platform.startswith('win'):
                try:
                    import tzdata  # noqa: F401
                except Exception:
                    raise ZoneInfoNotFoundError(
                        f'No time zone found with key {key!r}. '
                        'On Windows, install tzdata or install Dataclass Wizard with the tz extra:\n'
                        '    pip install dataclass-wizard[tz]'
                    ) from None
                else:
                    return ZoneInfo(key)
            raise

    def ensure_type_ref(extras, tp, *, name=None, prefix='', is_builtin=False) -> str:
        """
        Return a safe symbol name for `tp` to use in generated code.

        Adds entries to `extras['locals']` only when required (non-builtins,
        non-collection literals, and cases where a stable local alias is needed).
        """
        if tp is NoneType:
            return 'None'

        if name is None:
            name = tp.__name__

        # Common built-in collections: always use the literal names directly.
        if tp in _BUILTIN_COLLECTION_TYPES:
            return name

        mod = tp.__module__

        # Builtins: can be referenced directly without injecting into locals.
        # Includes str/int/float/bool/bytes and also built-in collection types.
        if mod == 'builtins':
            return name

        if is_builtin or mod == 'collections':
            LOG.debug('Ensuring %s=%s', name, name)
            extras['locals'].setdefault(name, tp)
            return name

        _locals = extras['locals']

        # If the type name is safe and not used yet, inject it.
        # You may want stricter collision checks here.
        if name not in _locals:
            _locals[name] = tp
            return name

        # Collision: create a unique alias.
        # TODO might need to handle `var_name`
        alias = f'{prefix}{name}'
        LOG.debug('Adding %s=%s', alias, name)
        _locals.setdefault(alias, tp)

        return alias

    class TypeInfo:

        __slots__ = (
            # type origin (ex. `List[str]` -> `List`)
            'origin',
            # type arguments (ex. `Dict[str, int]` -> `(str, int)`)
            'args',
            # name of type origin (ex. `List[str]` -> 'list')
            'name',
            # index of iteration, *only* unique within the scope of a field assignment!
            'i',
            # index of field within the dataclass, *guaranteed* to be unique.
            'field_i',
            # prefix of value in assignment (prepended to `i`),
            # defaults to 'v' if not specified.
            'prefix',
            # index of assignment (ex. `2 -> v1[2]`, *or* a string `"key" -> v4["key"]`)
            'index',
            # explicit value name (overrides prefix + index)
            'val_name',
            # optional attribute, that indicates if we should wrap the
            # assignment with `name` -- ex. `(1, 2)` -> `deque((1, 2))`
            '_wrapped',
            # optional attribute, that indicates if we are currently in Optional,
            # e.g. `typing.Optional[...]` *or* `typing.Union[T, ...*T2, None]`
            '_in_opt',
        )

        def __init__(self, origin,
                     args=None,
                     name=None,
                     i=1,
                     field_i=1,
                     prefix='v',
                     val_name=None,
                     index=None):

            self.name = name
            self.origin = origin
            self.args = args
            self.i = i
            self.field_i = field_i
            self.prefix = prefix
            self.val_name = val_name
            self.index = index

        def replace(self, **changes):
            # Validate that `instance` is an instance of the class
            # if not isinstance(instance, TypeInfo):
            #     raise TypeError(f"Expected an instance of {TypeInfo.__name__}, got {type(instance).__name__}")

            # Extract current values from __slots__
            current_values = {slot: getattr(self, slot)
                              for slot in TypeInfo.__slots__
                              if not slot.startswith('_')}

            if ((new_idx := changes.get('index')) is not None
                and (curr_idx := current_values['index']) is not None):
                if isinstance(curr_idx, (int, str)):
                    changes['index'] = (curr_idx, new_idx)
                else:
                    changes['index'] = curr_idx + (new_idx, )

            # Apply the changes
            current_values.update(changes)

            # Create and return a new instance with updated attributes
            # noinspection PyArgumentList
            return TypeInfo(**current_values)

        @property
        def in_optional(self):
            return getattr(self, '_in_opt', False)

        # noinspection PyUnresolvedReferences
        @in_optional.setter
        def in_optional(self, value):
            # noinspection PyAttributeOutsideInit
            self._in_opt = value

        @staticmethod
        def ensure_in_locals(extras, *tps, **name_to_tp):
            names = [ensure_type_ref(extras, tp) for tp in tps]

            for name, tp in name_to_tp.items():
                extras['locals'].setdefault(name, tp)

            return names

        def type_name(self, extras, bound=None):
            """Return type name as string (useful for `Union` type checks)"""
            if self.name is None:
                self.name = get_origin_v2(self.origin).__name__

            return self._wrap_inner(
                extras, force=True, bound=bound)

        def v(self):
            val_name = self.val_name
            if val_name is None:
                val_name = f'{self.prefix}{self.i}'
            idx = self.index
            if idx is None:
                return val_name
            else:
                if isinstance(idx, (int, str)):
                    return f'{val_name}[{idx}]'
                return f"{val_name}{''.join(f'[{i}]' for i in idx)}"

        def v_for_def(self):
            """
            Returns a safe value for function `def` statements (e.g., no
            dot (.) or indices [])
            """
            return f'{self.prefix}{self.i}'

        def v_and_next(self):
            next_i = self.i + 1
            return self.v(), f'{self.prefix}{next_i}', next_i

        def v_and_next_k_v(self):
            next_i = self.i + 1
            return self.v(), f'k{next_i}', f'v{next_i}', next_i

        def wrap_dd(self, default_factory: DefFactory, result: str, extras):
            tn = self._wrap_inner(extras, is_builtin=True, bound=defaultdict)
            tn_df = self._wrap_inner(extras, default_factory)
            result = f'{tn}({tn_df}, {result})'
            setattr(self, '_wrapped', result)
            return self

        def multi_wrap(self, extras, prefix='', *result, force=False):
            tn = self._wrap_inner(extras, prefix=prefix, force=force)
            if tn is not None:
                result = [f'{tn}({r})' for r in result]

            return result

        def wrap(self, result: str, extras, force=False, prefix='', bound=None):
            tn = self._wrap_inner(extras, prefix=prefix, force=force, bound=bound)
            if tn is not None:
                result = f'{tn}({result})'

            setattr(self, '_wrapped', result)
            return self

        def wrap_builtin(self, bound, result, extras):
            tn = self._wrap_inner(extras, is_builtin=True, bound=bound)
            result = f'{tn}({result})'

            setattr(self, '_wrapped', result)
            return self

        def _wrap_inner(self, extras,
                        tp=None,
                        prefix='',
                        is_builtin=False,
                        force=False,
                        bound=None) -> 'str | None':

            if tp is None:
                tp = self.origin
                name = self.name
                return_name = force
            else:
                name = 'None' if tp is NoneType else tp.__name__
                return_name = True

            # If the type is the bound itself, treat it as "builtin" in naming
            # (i.e., don't generate unique alias)
            #
            # This ensures we don't create a "unique" name
            # if it's a non-subclass, e.g. ensures we end
            # up with `date` instead of `date_123`.
            if bound is not None:
                is_builtin = tp is bound

            if tp not in _BUILTIN_COLLECTION_TYPES:
                return ensure_type_ref(
                    extras,
                    tp,
                    name=name,
                    prefix=prefix,
                    is_builtin=is_builtin,
                )

            return name if return_name else None

        def __str__(self):
            return getattr(self, '_wrapped', '')

        def __repr__(self):  # pragma: no cover
            items = ', '.join([f'{v}={getattr(self, v)!r}'
                               for v in self.__slots__
                               if not v.startswith('_')])

            return f'{self.__class__.__name__}({items})'

    class Extras(TypedDict):
        """
        "Extra" config that can be used in the load / dump process.
        """
        config: 'META'
        cls: type
        cls_name: str
        fn_gen: FunctionBuilder
        locals: dict[str, Any]
        pattern: PyNotRequired['PatternBase']
        recursion_guard: dict[type, str]

    class PatternBase:

        __slots__ = ('base',
                     'patterns',
                     'tz_info',
                     '_repr')

        def __init__(self, base, patterns=None, tz_info=None):
            self.base = base
            if patterns is not None:
                self.patterns = patterns
            if tz_info is not None:
                self.tz_info = tz_info

        def with_tz(self, tz_info: tzinfo):  # pragma: no cover
            self.tz_info = tz_info
            return self

        def __getitem__(self, patterns):
            if (tz_info := getattr(self, 'tz_info', None)) is ...:
                # expect time zone as first argument
                tz_info, *patterns = patterns
                if isinstance(tz_info, str):
                    tz_info = get_zoneinfo(tz_info)
            else:
                patterns = (patterns, ) if patterns.__class__ is str else patterns

            return PatternBase(
                self.base,
                patterns,
                tz_info,
            )

        def __call__(self, *patterns):
            return self.__getitem__(patterns)

        @setup_recursive_safe_function(add_cls=False)
        def load_to_pattern(self, tp, extras):
            from .type_conv import as_datetime_v1, as_date_v1, as_time_v1

            v = tp.v()

            pb = cast(PatternBase, tp.origin)
            patterns = pb.patterns
            tz_info = getattr(pb, 'tz_info', None)
            __base__ = pb.base

            tn = __base__.__name__

            fn_gen = extras['fn_gen']
            _locals = extras['locals']

            is_datetime \
                = is_date \
                = is_time \
                = is_subclass_date \
                = is_subclass_time \
                = is_subclass_datetime = False

            if tz_info is not None:
                _locals['__tz'] = tz_info
                has_tz = True
                tz_part = '.replace(tzinfo=__tz)'
            else:
                has_tz = False
                tz_part = ''

            if __base__ is datetime:
                is_datetime = True
            elif __base__ is date:
                is_date = True
            elif __base__ is time:
                is_time = True
                _locals['cls'] = time
            elif issubclass(__base__, datetime):
                is_datetime = is_subclass_datetime = True
            elif issubclass(__base__, date):
                is_date = is_subclass_date = True
                _locals['cls'] = __base__
            elif issubclass(__base__, time):
                is_time = is_subclass_time = True
                _locals['cls'] = __base__

            _fromisoformat = f'__{tn}_fromisoformat'
            _fromtimestamp = f'__{tn}_fromtimestamp'

            name_to_func = {
                _fromisoformat: __base__.fromisoformat,
            }
            if is_subclass_datetime:
                _strptime = f'__{tn}_strptime'
                name_to_func[_strptime] = __base__.strptime
            else:
                _strptime = f'__datetime_strptime'
                name_to_func[_strptime] = datetime.strptime

            if is_datetime:
                _as_func = '__as_datetime'
                _as_func_args = f'{v}, {_fromtimestamp}, __tz' if has_tz else f'{v}, {_fromtimestamp}'
                name_to_func[_as_func] = as_datetime_v1
                # `datetime` has a `fromtimestamp` method
                name_to_func[_fromtimestamp] = __base__.fromtimestamp
                end_part = ''
            elif is_date:
                _as_func = '__as_date'
                _as_func_args = f'{v}, {_fromtimestamp}'
                name_to_func[_as_func] = as_date_v1
                # `date` has a `fromtimestamp` method
                name_to_func[_fromtimestamp] = __base__.fromtimestamp
                end_part = '.date()'
            else:
                _as_func = '__as_time'
                _as_func_args = f'{v}, cls'
                name_to_func[_as_func] = as_time_v1
                end_part = '.timetz()' if has_tz else '.time()'

            tp.ensure_in_locals(extras, **name_to_func)

            if PY311_OR_ABOVE:
                _parse_iso_string = f'{_fromisoformat}({v}){tz_part}'
                errors_to_except = (TypeError, )
            else:  # pragma: no cover
                _parse_iso_string = f"{_fromisoformat}({v}.replace('Z', '+00:00', 1)){tz_part}"
                errors_to_except = (AttributeError, TypeError)
            # temp fix for Python 3.11+, since `time.fromisoformat` is updated
            # to support more formats, such as "-" and "+" in strings.
            if (is_time and
                    any('-' in s or '+' in s for s in patterns)):

                for p in patterns:
                    # Try to parse with `datetime.strptime` first
                    with fn_gen.try_():
                        if is_subclass_time:
                            tz_arg = '__tz, ' if has_tz else ''

                            fn_gen.add_line(f'__dt = {_strptime}({v}, {p!r})')
                            fn_gen.add_line('return cls('
                                            '__dt.hour, '
                                            '__dt.minute, '
                                            '__dt.second, '
                                            '__dt.microsecond, '
                                            f'{tz_arg}fold=__dt.fold)')
                        else:
                            fn_gen.add_line(f'return {_strptime}({v}, {p!r}){tz_part}{end_part}')
                    with fn_gen.except_(Exception):
                        fn_gen.add_line('pass')
                # If that doesn't work, fallback to `time.fromisoformat`
                with fn_gen.try_():
                    fn_gen.add_line(f'return {_parse_iso_string}')
                with fn_gen.except_multi(*errors_to_except):
                    fn_gen.add_line(f'return {_as_func}({_as_func_args})')
                with fn_gen.except_(ValueError):
                    fn_gen.add_line('pass')
            # Optimized parsing logic (default)
            else:
                # Try to parse with `{base_type}.fromisoformat` first
                with fn_gen.try_():
                    fn_gen.add_line(f'return {_parse_iso_string}')
                with fn_gen.except_multi(*errors_to_except):
                    fn_gen.add_line(f'return {_as_func}({_as_func_args})')
                with fn_gen.except_(ValueError):
                    # If that doesn't work, fallback to `datetime.strptime`
                    for p in patterns:
                        with fn_gen.try_():
                            if is_subclass_date:
                                fn_gen.add_line(f'__dt = {_strptime}({v}, {p!r})')
                                fn_gen.add_line('return cls('
                                                '__dt.year, '
                                                '__dt.month, '
                                                '__dt.day)')
                            elif is_subclass_time:
                                fn_gen.add_line(f'__dt = {_strptime}({v}, {p!r})')
                                tz_arg = '__tz, ' if has_tz else ''

                                fn_gen.add_line('return cls('
                                                '__dt.hour, '
                                                '__dt.minute, '
                                                '__dt.second, '
                                                '__dt.microsecond, '
                                                f'{tz_arg}fold=__dt.fold)')
                            else:
                                fn_gen.add_line(f'return {_strptime}({v}, {p!r}){tz_part}{end_part}')
                        with fn_gen.except_(Exception):
                            fn_gen.add_line('pass')
            # Raise a helpful error if we are unable to parse
            # the date string with the provided patterns.
            fn_gen.add_line(
                f'raise ValueError(f"Unable to parse the string \'{{{v}}}\' '
                f'with the provided patterns: {patterns!r}")')

        def __repr__(self):
            # Short path: Temporary state / placeholder
            if self.base is ...:
                return '...'

            if (_repr := getattr(self, '_repr', None)) is not None:
                return _repr

            # Create a stable hash of the patterns
            # noinspection PyTypeChecker
            pat = hashlib.md5(str(self.patterns).encode('utf-8')).hexdigest()

            # Directly use the hash as part of the identifier
            self._repr = _repr = f'{self.base.__name__}_{pat}'

            return _repr

    # noinspection PyTypeChecker
    Pattern = PatternBase(...)
    # noinspection PyTypeChecker
    AwarePattern = PatternBase(..., tz_info=...)
    # noinspection PyTypeChecker
    UTCPattern = PatternBase(..., tz_info=UTC)

    # noinspection PyTypeChecker
    DatePattern = PatternBase(date)
    # noinspection PyTypeChecker
    DateTimePattern = PatternBase(datetime)
    # noinspection PyTypeChecker
    TimePattern = PatternBase(time)

    # noinspection PyTypeChecker
    AwareDateTimePattern = PatternBase(datetime, tz_info=...)
    # noinspection PyTypeChecker
    AwareTimePattern = PatternBase(time, tz_info=...)

    # noinspection PyTypeChecker
    UTCDateTimePattern = PatternBase(datetime, tz_info=UTC)
    # noinspection PyTypeChecker
    UTCTimePattern = PatternBase(time, tz_info=UTC)

    def _normalize_alias_path_args(all_paths, load, dump):
        """Normalize `AliasPath` arguments and canonicalize path values."""
        if load is not None:
            all_paths = load
            load = None
            dump = ExplicitNull

        elif dump is not None:
            all_paths = dump
            dump = None
            load = ExplicitNull

        if isinstance(all_paths, str):
            all_paths = (split_object_path(all_paths),)
        else:
            all_paths = tuple([
                split_object_path(a) if isinstance(a, str) else a
                for a in all_paths
            ])

        return all_paths, load, dump

    def _normalize_alias_args(default, default_factory, all_aliases, load, dump, env):
        """Normalize `Alias` arguments and canonicalize alias values."""

        if default is not MISSING and default_factory is not MISSING:
            raise ValueError('cannot specify both default and default_factory')

        if all_aliases:
            load = dump = all_aliases

        elif load is not None and isinstance(load, str):
            load = (load,)

        elif env is not None:
            if isinstance(env, str):
                env = (env,)
            elif env is True:
                env = load

        return all_aliases, load, dump, env

    # Instances of Field are only ever created from within this module,
    # and only from the field() function, although Field instances are
    # exposed externally as (conceptually) read-only objects.
    #
    # name and type are filled in after the fact, not in __init__.
    # They're not known at the time this class is instantiated, but it's
    # convenient if they're available later.

    # noinspection PyPep8Naming,PyShadowingBuiltins

    def Env(*load,
            default=MISSING,
            default_factory=MISSING,
            init=True, repr=True,
            hash=None, compare=True, metadata=None,
            **field_kwargs):

        # noinspection PyTypeChecker
        return Alias(
            env=load,
            default=default,
            default_factory=default_factory,
            init=init,
            repr=repr,
            hash=hash,
            compare=compare,
            metadata=metadata,
            **field_kwargs,
        )

    # In Python 3.14, dataclasses adds a new parameter to the :class:`Field`
    # constructor: `doc`
    #
    # Ref: https://docs.python.org/3.14/library/dataclasses.html#dataclasses.field
    if PY314_OR_ABOVE:
        # noinspection PyPep8Naming,PyShadowingBuiltins
        def Alias(
            *all,
            load=None,
            dump=None,
            env=None,
            skip=False,
            default=MISSING,
            default_factory=MISSING,
            init=True,
            repr=True,
            hash=None,
            compare=True,
            metadata=None,
            kw_only=False,
            doc=None,
        ):

            all, load, dump, env = _normalize_alias_args(default, default_factory, all, load, dump, env)

            return Field(
                load,
                dump,
                env,
                skip,
                None,
                default,
                default_factory,
                init,
                repr,
                hash,
                compare,
                metadata,
                kw_only,
                doc,
            )

        # noinspection PyPep8Naming,PyShadowingBuiltins
        def AliasPath(
            *all,
            load=None,
            dump=None,
            skip=False,
            default=MISSING,
            default_factory=MISSING,
            init=True,
            repr=True,
            hash=None,
            compare=True,
            metadata=None,
            kw_only=False,
            doc=None,
        ):
            all, load, dump = _normalize_alias_path_args(all, load, dump)

            return Field(
                load,
                dump,
                load,
                skip,
                all,
                default,
                default_factory,
                init,
                repr,
                hash,
                compare,
                metadata,
                kw_only,
                doc,
            )

        class Field(_Field):

            __slots__ = ("load_alias", "dump_alias", "env_vars", "skip", "path")

            # noinspection PyShadowingBuiltins
            def __init__(
                self,
                load_alias,
                dump_alias,
                env_vars,
                skip,
                path,
                default,
                default_factory,
                init,
                repr,
                hash,
                compare,
                metadata,
                kw_only,
                doc=None,
            ):

                # noinspection PyArgumentList
                super().__init__(
                    default,
                    default_factory,
                    init,
                    repr,
                    hash,
                    compare,
                    metadata,
                    kw_only,
                    doc,
                )

                self.load_alias = load_alias
                self.dump_alias = dump_alias
                self.env_vars = env_vars
                self.skip = skip
                self.path = path

    # In Python 3.10, dataclasses adds a new parameter to the :class:`Field`
    # constructor: `kw_only`
    #
    # Ref: https://docs.python.org/3.10/library/dataclasses.html#dataclasses.dataclass
    elif PY310_OR_ABOVE:  # pragma: no cover

        # noinspection PyPep8Naming,PyShadowingBuiltins
        def Alias(*all,
                  load=None,
                  dump=None,
                  env=None,
                  skip=False,
                  default=MISSING,
                  default_factory=MISSING,
                  init=True, repr=True,
                  hash=None, compare=True,
                  metadata=None, kw_only=False):

            all, load, dump, env = _normalize_alias_args(default, default_factory, all, load, dump, env)

            return Field(
                load,
                dump,
                env,
                skip,
                None,
                default,
                default_factory,
                init,
                repr,
                hash,
                compare,
                metadata,
                kw_only,
            )

        # noinspection PyPep8Naming,PyShadowingBuiltins
        def AliasPath(*all,
                      load=None,
                      dump=None,
                      skip=False,
                      default=MISSING,
                      default_factory=MISSING,
                      init=True, repr=True,
                      hash=None, compare=True,
                      metadata=None, kw_only=False):
            all, load, dump = _normalize_alias_path_args(all, load, dump)

            return Field(
                load,
                dump,
                load,
                skip,
                all,
                default,
                default_factory,
                init,
                repr,
                hash,
                compare,
                metadata,
                kw_only,
            )

        class Field(_Field):

            __slots__ = ('load_alias',
                         'dump_alias',
                         'env_vars',
                         'skip',
                         'path')

            # noinspection PyShadowingBuiltins
            def __init__(self,
                         load_alias, dump_alias, env_vars, skip, path,
                         default, default_factory, init, repr, hash, compare,
                         metadata, kw_only):

                super().__init__(default, default_factory, init, repr, hash,
                                 compare, metadata, kw_only)

                if path is not None:
                    if isinstance(path, str):
                        path = split_object_path(path) if path else (path, )

                self.load_alias = load_alias
                self.dump_alias = dump_alias
                self.env_vars = env_vars
                self.skip = skip
                self.path = path

    else:  # pragma: no cover
        # noinspection PyPep8Naming,PyShadowingBuiltins

        def Alias(*all,
                  load=None,
                  dump=None,
                  env=None,
                  skip=False,
                  default=MISSING,
                  default_factory=MISSING,
                  init=True, repr=True,
                  hash=None, compare=True, metadata=None):

            all, load, dump, env = _normalize_alias_args(default, default_factory, all, load, dump, env)

            return Field(
                load,
                dump,
                env,
                skip,
                None,
                default,
                default_factory,
                init,
                repr,
                hash,
                compare,
                metadata,
            )

        # noinspection PyPep8Naming,PyShadowingBuiltins

        def AliasPath(*all,
                      load=None,
                      dump=None,
                      skip=False,
                      default=MISSING,
                      default_factory=MISSING,
                      init=True, repr=True,
                      hash=None, compare=True,
                      metadata=None):
            all, load, dump = _normalize_alias_path_args(all, load, dump)

            return Field(
                load,
                dump,
                load,
                skip,
                all,
                default,
                default_factory,
                init,
                repr,
                hash,
                compare,
                metadata,
            )

        class Field(_Field):

            __slots__ = ('load_alias',
                         'dump_alias',
                         'env_vars',
                         'skip',
                         'path')

            # noinspection PyArgumentList,PyShadowingBuiltins
            def __init__(self,
                         load_alias, dump_alias, env_vars, skip, path,
                         default, default_factory, init, repr, hash, compare,
                         metadata):

                super().__init__(default, default_factory, init, repr, hash,
                                 compare, metadata)

                if path is not None:
                    if isinstance(path, str):
                        path = split_object_path(path) if path else (path,)

                self.load_alias = load_alias
                self.dump_alias = dump_alias
                self.env_vars = env_vars
                self.skip = skip
                self.path = path

    Alias.__doc__ = """
        Maps one or more JSON key names to a dataclass field.

        This function acts as an alias for ``dataclasses.field(...)``, with additional
        support for associating a field with one or more JSON keys. It customizes
        serialization and deserialization behavior, including handling keys with
        varying cases or alternative names.

        The mapping is case-sensitive; JSON keys must match exactly (e.g., ``myField``
        will not match ``myfield``). If multiple keys are provided, the first one
        is used as the default for serialization.

        :param all: One or more JSON key names to associate with the dataclass field.
        :type all: str
        :param load: Key(s) to use for deserialization. Defaults to ``all`` if not specified.
        :type load: str | Sequence[str] | None
        :param dump: Key to use for serialization. Defaults to the first key in ``all``.
        :type dump: str | None
        :param skip: If ``True``, the field is excluded during serialization. Defaults to ``False``.
        :type skip: bool
        :param default: Default value for the field. Cannot be used with ``default_factory``.
        :type default: Any
        :param default_factory: Callable to generate the default value. Cannot be used with ``default``.
        :type default_factory: Callable[[], Any]
        :param init: Whether the field is included in the generated ``__init__`` method. Defaults to ``True``.
        :type init: bool
        :param repr: Whether the field appears in the ``__repr__`` output. Defaults to ``True``.
        :type repr: bool
        :param hash: Whether the field is included in the ``__hash__`` method. Defaults to ``None``.
        :type hash: bool
        :param compare: Whether the field is included in comparison methods. Defaults to ``True``.
        :type compare: bool
        :param metadata: Additional metadata for the field. Defaults to ``None``.
        :type metadata: dict
        :param kw_only: If ``True``, the field is keyword-only. Defaults to ``False``.
        :type kw_only: bool
        :return: A dataclass field with additional mappings to one or more JSON keys.
        :rtype: Field

        **Examples**

        **Example 1** -- Mapping multiple key names to a field::

            from dataclasses import dataclass

            from dataclass_wizard import LoadMeta, fromdict
            from dataclass_wizard.v1 import Alias

            @dataclass
            class Example:
                my_field: str = Alias('key1', 'key2', default="default_value")

            LoadMeta(v1=True).bind_to(Example)

            print(fromdict(Example, {'key2': 'a value!'}))
            #> Example(my_field='a value!')

        **Example 2** -- Skipping a field during serialization::

            from dataclasses import dataclass

            from dataclass_wizard import JSONPyWizard
            from dataclass_wizard.v1 import Alias

            @dataclass
            class Example(JSONPyWizard):
                class _(JSONPyWizard.Meta):
                    v1 = True

                my_field: str = Alias('key', skip=True)

            ex = Example.from_dict({'key': 'some value'})
            print(ex)                  #> Example(my_field='a value!')
            assert ex.to_dict() == {}  #> True
    """

    AliasPath.__doc__ = """
        Creates a dataclass field mapped to one or more nested JSON paths.

        This function acts as an alias for ``dataclasses.field(...)``, with additional
        functionality to associate a field with one or more nested JSON paths,
        including complex or deeply nested structures.

        The mapping is case-sensitive, meaning that JSON keys must match exactly
        (e.g., "myField" will not match "myfield"). Nested paths can include dot
        notations or bracketed syntax for accessing specific indices or keys.

        :param all: One or more nested JSON paths to associate with
            the dataclass field (e.g., ``a.b.c`` or ``a["nested"]["key"]``).
        :type all: PathType | str
        :param load: Path(s) to use for deserialization. Defaults to ``all`` if not specified.
        :type load: PathType | str | None
        :param dump: Path(s) to use for serialization. Defaults to ``all`` if not specified.
        :type dump: PathType | str | None
        :param skip: If True, the field is excluded during serialization. Defaults to False.
        :type skip: bool
        :param default: Default value for the field. Cannot be used with ``default_factory``.
        :type default: Any
        :param default_factory: A callable to generate the default value. Cannot be used with ``default``.
        :type default_factory: Callable[[], Any]
        :param init: Whether the field is included in the generated ``__init__`` method. Defaults to True.
        :type init: bool
        :param repr: Whether the field appears in the ``__repr__`` output. Defaults to True.
        :type repr: bool
        :param hash: Whether the field is included in the ``__hash__`` method. Defaults to None.
        :type hash: bool
        :param compare: Whether the field is included in comparison methods. Defaults to True.
        :type compare: bool
        :param metadata: Additional metadata for the field. Defaults to None.
        :type metadata: dict
        :param kw_only: If True, the field is keyword-only. Defaults to False.
        :type kw_only: bool
        :return: A dataclass field with additional mapping to one or more nested JSON paths.
        :rtype: Field

        **Examples**

        **Example 1** -- Mapping multiple nested paths to a field::

            from dataclasses import dataclass

            from dataclass_wizard import fromdict, LoadMeta
            from dataclass_wizard.v1 import AliasPath

            @dataclass
            class Example:
                my_str: str = AliasPath('a.b.c.1', 'x.y["-1"].z', default="default_value")

            LoadMeta(v1=True).bind_to(Example)

            # Maps nested paths ('a', 'b', 'c', 1) and ('x', 'y', '-1', 'z')
            # to the `my_str` attribute. '-1' is treated as a literal string key,
            # not an index, for the second path.

            print(fromdict(Example, {'x': {'y': {'-1': {'z': 'some_value'}}}}))
            #> Example(my_str='some_value')

        **Example 2** -- Using Annotated::

            from dataclasses import dataclass
            from typing import Annotated

            from dataclass_wizard import JSONPyWizard
            from dataclass_wizard.v1 import AliasPath

            @dataclass
            class Example(JSONPyWizard):
                class _(JSONPyWizard.Meta):
                    v1 = True

                my_str: Annotated[str, AliasPath('my."7".nested.path.-321')]

            ex = Example.from_dict({'my': {'7': {'nested': {'path': {-321: 'Test'}}}}})
            print(ex)  #> Example(my_str='Test')
    """

    Field.__doc__ = """
        Alias to a :class:`dataclasses.Field`, but one which also represents a
        mapping of one or more JSON key names to a dataclass field.

        See the docs on the :func:`Alias` and :func:`AliasPath` for more info.
    """