# Source code for dataclass_wizard.serial_json

    import json
    import logging
    from dataclasses import dataclass, MISSING

    from .abstractions import AbstractJSONWizard
    from .bases_meta import BaseJSONWizardMeta, LoadMeta, DumpMeta, register_type
    from .class_helper import call_meta_initializer_if_needed
    from .constants import PACKAGE_NAME
    from .loader_selection import asdict, fromdict, fromlist
    from .log import enable_library_debug_logging
    from .type_def import dataclass_transform
    # noinspection PyProtectedMember
    from .utils.dataclass_compat import (_create_fn,
                                         _dataclass_needs_refresh,
                                         _set_new_attribute)

    def _str_fn():
        return _create_fn('__str__',
                          ('self',),
                          ['return self.to_json(indent=2)'])

    def _first_declared_attr_in_mro(cls, name: str):
        """First `name` found in MRO (excluding cls); else None."""
        for base in cls.__mro__[1:]:
            attr = base.__dict__.get(name, MISSING)
            if attr is not MISSING:
                return attr
        return None

    def _set_from_dict_and_to_dict_if_needed(cls):
        """
        Pin default dispatchers on subclasses.

        Codegen is lazy; if a base later gets a specialised
        `from_dict` / `to_dict`, subclasses would inherit it.
        Defining defaults in `cls.__dict__` blocks that.
        """
        if 'from_dict' not in cls.__dict__:
            inherited = _first_declared_attr_in_mro(cls, 'from_dict')
            if getattr(inherited, '__func__', None) is fromdict:
                cls.from_dict = classmethod(fromdict)

        if 'to_dict' not in cls.__dict__:
            inherited = _first_declared_attr_in_mro(cls, 'to_dict')
            if inherited is asdict:
                cls.to_dict = asdict

    # noinspection PyShadowingBuiltins
    def _configure_wizard_class(cls,
                                str=True,
                                debug=False,
                                case=None,
                                dump_case=None,
                                load_case=None,
                                _key_transform=None,
                                _v1_default=False):
        load_meta_kwargs = {}

        if case is not None:
            _v1_default = True
            load_meta_kwargs['v1_case'] = case

        if dump_case is not None:
            _v1_default = True
            load_meta_kwargs['v1_dump_case'] = dump_case

        if load_case is not None:
            _v1_default = True
            load_meta_kwargs['v1_load_case'] = load_case

        if _v1_default:
            load_meta_kwargs['v1'] = True

        if _key_transform is not None:
            DumpMeta(key_transform=_key_transform).bind_to(cls)

        if debug:
            # minimum logging level for logs by this library
            lvl = logging.DEBUG if isinstance(debug, bool) else debug
            # enable library logging
            enable_library_debug_logging(lvl)
            # set `v1_debug` flag for the class's Meta
            load_meta_kwargs['v1_debug'] = lvl

        if load_meta_kwargs:
            LoadMeta(**load_meta_kwargs).bind_to(cls)

        # Calls the Meta initializer when inner :class:`Meta` is sub-classed.
        call_meta_initializer_if_needed(cls)

        # Add a `__str__` method to the subclass, if needed
        if str:
            _set_new_attribute(cls, '__str__', _str_fn())

        # Add `from_dict` and `to_dict` methods to the subclass, if needed
        _set_from_dict_and_to_dict_if_needed(cls)

    @dataclass_transform()
    class DataclassWizard(AbstractJSONWizard):

        __slots__ = ()

        class Meta(BaseJSONWizardMeta):

            __slots__ = ()

            __is_inner_meta__ = True

            def __init_subclass__(cls):
                return cls._init_subclass()

        register_type = classmethod(register_type)

        @classmethod
        def from_json(cls, string, *,
                      decoder=json.loads,
                      **decoder_kwargs):

            o = decoder(string, **decoder_kwargs)

            return fromdict(cls, o) if isinstance(o, dict) else fromlist(cls, o)

        from_list = classmethod(fromlist)

        from_dict = classmethod(fromdict)

        to_dict = asdict

        def to_json(self, *,
                    encoder=json.dumps,
                    **encoder_kwargs):

            return encoder(asdict(self), **encoder_kwargs)

        @classmethod
        def list_to_json(cls,
                         instances,
                         encoder=json.dumps,
                         **encoder_kwargs):

            list_of_dict = [asdict(o, cls=cls) for o in instances]

            return encoder(list_of_dict, **encoder_kwargs)

        # noinspection PyShadowingBuiltins
        def __init_subclass__(cls,
                              str=False,
                              debug=False,
                              case=None,
                              dump_case=None,
                              load_case=None,
                              _key_transform=None,
                              _v1_default=True,
                              _apply_dataclass=True,
                              **dc_kwargs):

            super().__init_subclass__()

            # skip classes provided by this library.
            if cls.__module__.startswith(f'{PACKAGE_NAME}.'):
                return

            # Apply the @dataclass decorator.
            if _apply_dataclass and _dataclass_needs_refresh(cls):
                # noinspection PyArgumentList
                dataclass(cls, **dc_kwargs)

            _configure_wizard_class(cls, str, debug, case, dump_case, load_case,
                                    _key_transform, _v1_default)

    # noinspection PyAbstractClass

    class JSONSerializable(DataclassWizard):

        __slots__ = ()

        # noinspection PyShadowingBuiltins
        def __init_subclass__(cls,
                              str=True,
                              debug=False,
                              case=None,
                              dump_case=None,
                              load_case=None,
                              _key_transform=None,
                              _v1_default=False,
                              _apply_dataclass=False,
                              **_):

            super().__init_subclass__(str, debug, case, dump_case, load_case,
                                      _key_transform, _v1_default, _apply_dataclass)

    def _str_pprint_fn():
        from pprint import pformat

        def __str__(self):
            return pformat(self, width=70)

        return __str__

    # A handy alias in case it comes in useful to anyone :)
    JSONWizard = JSONSerializable

    class JSONPyWizard(JSONWizard):
        """Helper for JSONWizard that ensures dumping to JSON keeps keys as-is."""

        # noinspection PyShadowingBuiltins
        def __init_subclass__(cls,
                              str=True,
                              debug=False,
                              case=None,
                              dump_case=None,
                              load_case=None,
                              _key_transform=None,
                              _v1_default=False,
                              _apply_dataclass=False,
                              **_):
            """Bind child class to DumpMeta with no key transformation."""

            # Call JSONSerializable.__init_subclass__()
            # set `key_transform_with_dump` for the class's Meta
            super().__init_subclass__(False, debug, case, dump_case, load_case, 'NONE',
                                      _v1_default, _apply_dataclass)

            # Add a `__str__` method to the subclass, if needed
            if str:
                _set_new_attribute(cls, '__str__', _str_pprint_fn())