Edit on GitHub

serde.de

This module provides deserialize, is_deserializable from_dict, from_tuple and classes and functions associated with deserialization.

   1"""
   2This module provides `deserialize`, `is_deserializable` `from_dict`, `from_tuple` and classes
   3and functions associated with deserialization.
   4"""
   5
   6from __future__ import annotations
   7import abc
   8import itertools
   9import collections
  10import dataclasses
  11import functools
  12import typing
  13import jinja2
  14from collections.abc import Callable, Sequence, Iterable
  15
  16from beartype import beartype, BeartypeConf
  17from beartype.door import is_bearable
  18from beartype.roar import BeartypeCallHintParamViolation
  19from dataclasses import dataclass, is_dataclass
  20from typing import overload, TypeVar, Generic, Any, Optional, Union, Literal, Iterator
  21from typing_extensions import dataclass_transform
  22
  23from .compat import (
  24    SerdeError,
  25    SerdeSkip,
  26    T,
  27    UserError,
  28    find_generic_arg,
  29    get_args,
  30    get_generic_arg,
  31    get_origin,
  32    get_type_var_names,
  33    is_any,
  34    is_bare_dict,
  35    is_bare_list,
  36    is_bare_set,
  37    is_bare_tuple,
  38    is_datetime,
  39    is_default_dict,
  40    is_dict,
  41    is_ellipsis,
  42    is_enum,
  43    is_frozen_set,
  44    is_generic,
  45    is_list,
  46    is_literal,
  47    is_none,
  48    is_opt,
  49    is_primitive,
  50    is_primitive_subclass,
  51    is_set,
  52    is_str_serializable,
  53    is_tuple,
  54    is_union,
  55    is_variable_tuple,
  56    is_pep695_type_alias,
  57    iter_literals,
  58    iter_types,
  59    iter_unions,
  60    type_args,
  61    typename,
  62)
  63from .core import (
  64    GLOBAL_CLASS_DESERIALIZER,
  65    ClassDeserializer,
  66    FROM_DICT,
  67    FROM_ITER,
  68    SERDE_SCOPE,
  69    CACHE,
  70    UNION_DE_PREFIX,
  71    DefaultTagging,
  72    Field,
  73    disabled,
  74    Scope,
  75    Tagging,
  76    TypeCheck,
  77    add_func,
  78    coerce_object,
  79    strict,
  80    has_default,
  81    has_default_factory,
  82    ensure,
  83    fields,
  84    is_instance,
  85    literal_func_name,
  86    logger,
  87    raise_unsupported_type,
  88    union_func_name,
  89)
  90
  91# Lazy numpy imports to improve startup time
  92
  93__all__ = ["deserialize", "is_deserializable", "from_dict", "from_tuple"]
  94
  95
  96# Lazy numpy import wrappers to improve startup time
  97def _is_numpy_array(typ: Any) -> bool:
  98    from .numpy import is_numpy_array
  99
 100    return is_numpy_array(typ)
 101
 102
 103def _is_numpy_scalar(typ: Any) -> bool:
 104    from .numpy import is_numpy_scalar
 105
 106    return is_numpy_scalar(typ)
 107
 108
 109def _is_numpy_jaxtyping(typ: Any) -> bool:
 110    from .numpy import is_numpy_jaxtyping
 111
 112    return is_numpy_jaxtyping(typ)
 113
 114
 115DeserializeFunc = Callable[[type[Any], Any], Any]
 116""" Interface of Custom deserialize function. """
 117
 118
 119def serde_legacy_custom_class_deserializer(
 120    cls: type[Any], datavar: Any, value: Any, custom: DeserializeFunc, default: Callable[[], Any]
 121) -> Any:
 122    """
 123    Handle custom deserialization. Use default deserialization logic if it receives `SerdeSkip`
 124    exception.
 125
 126    :param cls: Type of the field.
 127    :param datavar: The whole variable to deserialize from. e.g. "data"
 128    :param value: The value for the field. e.g. "data['i']"
 129    :param custom: Custom deserialize function.
 130    :param default: Default deserialize function.
 131    """
 132    try:
 133        return custom(cls, value)
 134    except SerdeSkip:
 135        return default()
 136
 137
 138def default_deserializer(_cls: type[Any], obj: Any) -> Any:
 139    """
 140    Marker function to tell serde to use the default deserializer. It's used when custom
 141    deserializer is specified at the class but you want to override a field with the default
 142    deserializer.
 143    """
 144
 145
 146def _get_by_aliases(
 147    d: dict[str, str], aliases: list[str], raise_error: bool = True
 148) -> Optional[str]:
 149    if not aliases:
 150        if raise_error:
 151            raise KeyError("Tried all aliases, but key not found")
 152        else:
 153            return None
 154    if aliases[0] in d:
 155        return d[aliases[0]]
 156    else:
 157        return _get_by_aliases(d, aliases[1:], raise_error=raise_error)
 158
 159
 160def _exists_by_aliases(d: dict[str, str], aliases: list[str]) -> bool:
 161    for alias in aliases:
 162        if alias in d:
 163            return True
 164    return False
 165
 166
 167def _make_deserialize(
 168    cls_name: str,
 169    fields: list[Any],
 170    *args: Any,
 171    rename_all: Optional[str] = None,
 172    reuse_instances_default: bool = True,
 173    convert_sets_default: bool = False,
 174    deserializer: Optional[DeserializeFunc] = None,
 175    type_check: TypeCheck = strict,
 176    class_deserializer: Optional[ClassDeserializer] = None,
 177    **kwargs: Any,
 178) -> type[Any]:
 179    """
 180    Create a deserializable class programatically.
 181    """
 182    C: type[Any] = dataclasses.make_dataclass(cls_name, fields, *args, **kwargs)
 183    C = deserialize(
 184        C,
 185        rename_all=rename_all,
 186        reuse_instances_default=reuse_instances_default,
 187        convert_sets_default=convert_sets_default,
 188        **kwargs,
 189    )
 190    return C
 191
 192
 193# The `deserialize` function can call itself recursively when it needs to generate code for
 194# unmarked dataclasses. To avoid infinite recursion, this array remembers types for which code is
 195# currently being generated.
 196GENERATION_STACK = []
 197
 198
 199@dataclass_transform()
 200def deserialize(
 201    _cls: Optional[type[T]] = None,
 202    rename_all: Optional[str] = None,
 203    reuse_instances_default: bool = True,
 204    convert_sets_default: bool = False,
 205    deserializer: Optional[DeserializeFunc] = None,
 206    tagging: Tagging = DefaultTagging,
 207    type_check: TypeCheck = strict,
 208    class_deserializer: Optional[ClassDeserializer] = None,
 209    deny_unknown_fields: bool = False,
 210    **kwargs: Any,
 211) -> type[T]:
 212    """
 213    A dataclass with this decorator is deserializable from any of the data formats supported
 214    by pyserde.
 215
 216    >>> from serde import deserialize
 217    >>> from serde.json import from_json
 218    >>>
 219    >>> @deserialize
 220    ... class Foo:
 221    ...     i: int
 222    ...     s: str
 223    ...     f: float
 224    ...     b: bool
 225    >>>
 226    >>> from_json(Foo, '{"i": 10, "s": "foo", "f": 100.0, "b": true}')
 227    Foo(i=10, s='foo', f=100.0, b=True)
 228    """
 229
 230    stack = []
 231
 232    def wrap(cls: type[T]) -> type[T]:
 233        if cls in stack:
 234            return cls
 235        stack.append(cls)
 236
 237        tagging.check()
 238
 239        # If no `dataclass` found in the class, dataclassify it automatically.
 240        if not is_dataclass(cls):
 241            dataclass(cls)
 242
 243        if type_check.is_strict():
 244            serde_beartype = beartype(conf=BeartypeConf(violation_type=SerdeError))
 245            serde_beartype(cls)
 246
 247        g: dict[str, Any] = {}
 248
 249        # Create a scope storage used by serde.
 250        # Each class should get own scope. Child classes can not share scope with parent class.
 251        # That's why we need the "scope.cls is not cls" check.
 252        scope: Optional[Scope] = getattr(cls, SERDE_SCOPE, None)
 253        if scope is None or scope.cls is not cls:
 254            scope = Scope(cls, reuse_instances_default=reuse_instances_default)
 255            setattr(cls, SERDE_SCOPE, scope)
 256
 257        class_deserializers: list[ClassDeserializer] = list(
 258            itertools.chain(
 259                GLOBAL_CLASS_DESERIALIZER, [class_deserializer] if class_deserializer else []
 260            )
 261        )
 262
 263        # Set some globals for all generated functions
 264        g["cls"] = cls
 265        g["serde_scope"] = scope
 266        g["SerdeError"] = SerdeError
 267        g["UserError"] = UserError
 268        g["raise_unsupported_type"] = raise_unsupported_type
 269        g["typename"] = typename
 270        g["ensure"] = ensure
 271        g["typing"] = typing
 272        g["collections"] = collections
 273        g["Literal"] = Literal
 274        g["from_obj"] = from_obj
 275        g["get_generic_arg"] = get_generic_arg
 276        g["is_instance"] = is_instance
 277        g["TypeCheck"] = TypeCheck
 278        g["disabled"] = disabled
 279        g["coerce_object"] = coerce_object
 280        g["_exists_by_aliases"] = _exists_by_aliases
 281        g["_get_by_aliases"] = _get_by_aliases
 282        g["class_deserializers"] = class_deserializers
 283        g["BeartypeCallHintParamViolation"] = BeartypeCallHintParamViolation
 284        g["is_bearable"] = is_bearable
 285        if deserializer:
 286            g["serde_legacy_custom_class_deserializer"] = functools.partial(
 287                serde_legacy_custom_class_deserializer, custom=deserializer
 288            )
 289
 290        # Collect types used in the generated code.
 291        for typ in iter_types(cls):
 292            # When we encounter a dataclass not marked with deserialize, then also generate
 293            # deserialize functions for it.
 294            if is_dataclass_without_de(typ) and typ is not cls:
 295                # We call deserialize and not wrap to make sure that we will use the default serde
 296                # configuration for generating the deserialization function.
 297                deserialize(typ)
 298
 299            # We don't want to add primitive class e.g "str" into the scope, but primitive
 300            # compatible types such as IntEnum and a subclass of primitives are added,
 301            # so that generated code can use those types.
 302            if is_primitive(typ) and not is_enum(typ) and not is_primitive_subclass(typ):
 303                continue
 304
 305            if is_generic(typ):
 306                g[typename(typ)] = get_origin(typ)
 307            else:
 308                g[typename(typ)] = typ
 309
 310        # render all union functions
 311        for union in iter_unions(cls):
 312            union_args = type_args(union)
 313            add_func(
 314                scope,
 315                union_func_name(UNION_DE_PREFIX, union_args),
 316                render_union_func(cls, union_args, tagging),
 317                g,
 318            )
 319
 320        # render literal functions
 321        for literal in iter_literals(cls):
 322            literal_args = type_args(literal)
 323            add_func(
 324                scope, literal_func_name(literal_args), render_literal_func(cls, literal_args), g
 325            )
 326
 327        # Collect default values and default factories used in the generated code.
 328        for f in defields(cls):
 329            assert f.name
 330            if has_default(f):
 331                scope.defaults[f.name] = f.default
 332            elif has_default_factory(f):
 333                scope.defaults[f.name] = f.default_factory
 334            if f.deserializer:
 335                g[f.deserializer.name] = f.deserializer
 336
 337        add_func(
 338            scope,
 339            FROM_ITER,
 340            render_from_iter(cls, deserializer, type_check, class_deserializer=class_deserializer),
 341            g,
 342        )
 343        add_func(
 344            scope,
 345            FROM_DICT,
 346            render_from_dict(
 347                cls,
 348                rename_all,
 349                deserializer,
 350                type_check,
 351                class_deserializer=class_deserializer,
 352                deny_unknown_fields=deny_unknown_fields,
 353            ),
 354            g,
 355        )
 356
 357        logger.debug(f"{typename(cls)}: {SERDE_SCOPE} {scope}")
 358
 359        stack.pop()
 360        return cls
 361
 362    if _cls is None:
 363        return wrap  # type: ignore
 364
 365    if _cls in GENERATION_STACK:
 366        return _cls
 367
 368    GENERATION_STACK.append(_cls)
 369    try:
 370        return wrap(_cls)
 371    finally:
 372        GENERATION_STACK.pop()
 373
 374
 375def is_deserializable(instance_or_class: Any) -> bool:
 376    """
 377    Test if an instance or class is deserializable.
 378
 379    >>> @deserialize
 380    ... class Foo:
 381    ...     pass
 382    >>>
 383    >>> is_deserializable(Foo)
 384    True
 385    """
 386    return hasattr(instance_or_class, SERDE_SCOPE)
 387
 388
 389def is_dataclass_without_de(cls: type[Any]) -> bool:
 390    if not dataclasses.is_dataclass(cls):
 391        return False
 392    if not hasattr(cls, SERDE_SCOPE):
 393        return True
 394    scope: Optional[Scope] = getattr(cls, SERDE_SCOPE)
 395    if not scope:
 396        return True
 397    return FROM_DICT not in scope.funcs
 398
 399
 400class Deserializer(Generic[T], metaclass=abc.ABCMeta):
 401    """
 402    `Deserializer` base class. Subclass this to customize deserialize behaviour.
 403
 404    See `serde.json.JsonDeserializer` and `serde.msgpack.MsgPackDeserializer` for example usage.
 405    """
 406
 407    @classmethod
 408    @abc.abstractmethod
 409    def deserialize(cls, data: T, **opts: Any) -> Any:
 410        """
 411        deserialize `data` into an object typically `dict`, `list` or `tuple`.
 412
 413        For example, `serde.json.JsonDeserializer` takes json string and deserialize
 414        into an object. `serde.msgpack.MsgPackDeserializer` takes msgpack bytes and
 415        deserialize into an object.
 416        """
 417        raise NotImplementedError
 418
 419
 420def from_obj(c: type[T], o: Any, named: bool, reuse_instances: Optional[bool]) -> T:
 421    """
 422    Deserialize from an object into an instance of the type specified as arg `c`.
 423    `c` can be either primitive type, `list`, `tuple`, `dict` or `deserialize` class.
 424    """
 425
 426    res: Any
 427
 428    # It is possible that the parser already generates the correct data type requested
 429    # by the caller. Hence, it should be checked early to avoid doing anymore work.
 430    if type(o) is c:
 431        return o
 432
 433    def deserializable_to_obj(cls: type[T]) -> T:
 434        serde_scope: Scope = getattr(cls, SERDE_SCOPE)
 435        func_name = FROM_DICT if named else FROM_ITER
 436        res = serde_scope.funcs[func_name](
 437            cls, maybe_generic=maybe_generic, data=o, reuse_instances=reuse_instances
 438        )
 439        return res  # type: ignore
 440
 441    if is_union(c) and not is_opt(c):
 442        # If a class in the argument is a non-dataclass class e.g. Union[Foo, Bar],
 443        # pyserde generates a wrapper (de)serializable dataclass on the fly,
 444        # and use it to deserialize into the object.
 445        return CACHE.deserialize_union(c, o)
 446
 447    if is_generic(c):
 448        # Store subscripted generic type such as Foo[Bar] in "maybe_generic",
 449        # and store origin type such as Foo in "c". Since subscripted generics
 450        # are not a subclass of "type", use "c" for type inspection, and pass
 451        # "maybe_generic" in deserialize functions.
 452        maybe_generic = c
 453        c = get_origin(c)  # type: ignore
 454    else:
 455        maybe_generic = c
 456    try:
 457        thisfunc = functools.partial(from_obj, named=named, reuse_instances=reuse_instances)
 458        if is_dataclass_without_de(c):
 459            # Do not automatically implement beartype if dataclass without serde decorator
 460            # is passed, because it is surprising for users
 461            # See https://github.com/yukinarit/pyserde/issues/480
 462            deserialize(c, type_check=disabled)
 463            res = deserializable_to_obj(c)
 464        elif is_deserializable(c):
 465            res = deserializable_to_obj(c)
 466        elif is_opt(c):
 467            if o is None:
 468                res = None
 469            else:
 470                res = thisfunc(type_args(c)[0], o)
 471        elif is_list(c):
 472            if is_bare_list(c):
 473                res = list(o)
 474            else:
 475                res = [thisfunc(type_args(c)[0], e) for e in o]
 476        elif is_set(c):
 477            if is_bare_set(c):
 478                res = set(o)
 479            elif is_frozen_set(c):
 480                res = frozenset(thisfunc(type_args(c)[0], e) for e in o)
 481            else:
 482                res = {thisfunc(type_args(c)[0], e) for e in o}
 483        elif is_tuple(c):
 484            if is_bare_tuple(c) or is_variable_tuple(c):
 485                res = tuple(e for e in o)
 486            else:
 487                res = tuple(thisfunc(type_args(c)[i], e) for i, e in enumerate(o))
 488        elif is_dict(c):
 489            if is_bare_dict(c):
 490                res = o
 491            elif is_default_dict(c):
 492                f = DeField(c, "")
 493                v = f.value_field()
 494                origin = get_origin(v.type)
 495                res = collections.defaultdict(
 496                    origin if origin else v.type,
 497                    {
 498                        thisfunc(type_args(c)[0], k): thisfunc(type_args(c)[1], v)
 499                        for k, v in o.items()
 500                    },
 501                )
 502            else:
 503                res = {
 504                    thisfunc(type_args(c)[0], k): thisfunc(type_args(c)[1], v) for k, v in o.items()
 505                }
 506        elif _is_numpy_array(c):
 507            from .numpy import deserialize_numpy_array_direct
 508
 509            res = deserialize_numpy_array_direct(c, o)
 510        elif is_datetime(c):
 511            res = c.fromisoformat(o)
 512        elif is_any(c) or is_ellipsis(c):
 513            res = o
 514        else:
 515            res = c(o)  # type: ignore
 516
 517        return res  # type: ignore
 518
 519    except UserError as e:
 520        raise e.inner from None
 521
 522    except Exception as e:
 523        raise SerdeError(e) from None
 524
 525
 526@overload
 527def from_dict(cls: type[T], o: dict[str, Any], reuse_instances: Optional[bool] = None) -> T: ...
 528
 529
 530@overload
 531def from_dict(cls: Any, o: dict[str, Any], reuse_instances: Optional[bool] = None) -> Any: ...
 532
 533
 534def from_dict(cls: Any, o: dict[str, Any], reuse_instances: Optional[bool] = None) -> Any:
 535    """
 536    Deserialize dictionary into object.
 537
 538    >>> @deserialize
 539    ... class Foo:
 540    ...     i: int
 541    ...     s: str = 'foo'
 542    ...     f: float = 100.0
 543    ...     b: bool = True
 544    >>>
 545    >>> from_dict(Foo, {'i': 10, 's': 'foo', 'f': 100.0, 'b': True})
 546    Foo(i=10, s='foo', f=100.0, b=True)
 547
 548    You can pass any type supported by pyserde. For example,
 549
 550    >>> lst = [{'i': 10, 's': 'foo', 'f': 100.0, 'b': True},
 551    ...        {'i': 20, 's': 'foo', 'f': 100.0, 'b': True}]
 552    >>> from_dict(list[Foo], lst)
 553    [Foo(i=10, s='foo', f=100.0, b=True), Foo(i=20, s='foo', f=100.0, b=True)]
 554    """
 555    return from_obj(cls, o, named=True, reuse_instances=reuse_instances)
 556
 557
 558@overload
 559def from_tuple(cls: type[T], o: Any, reuse_instances: Optional[bool] = None) -> T: ...
 560
 561
 562@overload
 563def from_tuple(cls: Any, o: Any, reuse_instances: Optional[bool] = None) -> Any: ...
 564
 565
 566def from_tuple(cls: Any, o: Any, reuse_instances: Optional[bool] = None) -> Any:
 567    """
 568    Deserialize tuple into object.
 569
 570    >>> @deserialize
 571    ... class Foo:
 572    ...     i: int
 573    ...     s: str = 'foo'
 574    ...     f: float = 100.0
 575    ...     b: bool = True
 576    >>>
 577    >>> from_tuple(Foo, (10, 'foo', 100.0, True))
 578    Foo(i=10, s='foo', f=100.0, b=True)
 579
 580    You can pass any type supported by pyserde. For example,
 581
 582    >>> lst = [(10, 'foo', 100.0, True), (20, 'foo', 100.0, True)]
 583    >>> from_tuple(list[Foo], lst)
 584    [Foo(i=10, s='foo', f=100.0, b=True), Foo(i=20, s='foo', f=100.0, b=True)]
 585    """
 586    return from_obj(cls, o, named=False, reuse_instances=reuse_instances)
 587
 588
 589@dataclass
 590class DeField(Field[T]):
 591    """
 592    Represents a field of dataclass.
 593    """
 594
 595    datavar: Optional[str] = None
 596    """ Name of variable which is passed in the deserialize API """
 597
 598    index: int = 0
 599    """ Field index """
 600
 601    iterbased: bool = False
 602    """ Iterater based deserializer or not """
 603
 604    def __getitem__(self, n: int) -> Union[DeField[Any], InnerField[Any]]:
 605        """
 606        Get inner `Field` from current `Field`.
 607
 608        `InnerField` is returned if self is of any standard collection e.g. list.
 609        `DeField` is returned if self is Optional.
 610        """
 611        typ = type_args(self.type)[n]
 612        opts: dict[str, Any] = {
 613            "kw_only": self.kw_only,
 614            "case": self.case,
 615            "alias": self.alias,
 616            "rename": self.rename,
 617            "skip": self.skip,
 618            "skip_if": self.skip_if,
 619            "skip_if_false": self.skip_if_false,
 620            "skip_if_default": self.skip_if_default,
 621            "serializer": self.serializer,
 622            "deserializer": self.deserializer,
 623            "flatten": self.flatten,
 624            "parent": self.parent,
 625        }
 626        if is_list(self.type) or is_dict(self.type) or is_set(self.type):
 627            return InnerField(typ, "v", datavar="v", **opts)
 628        elif is_tuple(self.type):
 629            return InnerField(typ, f"{self.data}[{n}]", datavar=f"{self.data}[{n}]", **opts)
 630        else:
 631            # For Optional etc.
 632            return DeField(
 633                typ,
 634                self.name,
 635                datavar=self.datavar,
 636                index=self.index,
 637                iterbased=self.iterbased,
 638                **opts,
 639            )
 640
 641    def key_field(self) -> DeField[Any]:
 642        """
 643        Get inner key field for dict like class.
 644        """
 645        k = self[0]
 646        k.name = "k"
 647        k.datavar = "k"
 648        return k
 649
 650    def value_field(self) -> DeField[Any]:
 651        """
 652        Get inner value field for dict like class.
 653        """
 654        return self[1]
 655
 656    @property
 657    def data(self) -> str:
 658        """
 659        Renders the variable name that possesses the data.
 660
 661        e.g. tuple
 662            * datavar property returns "data"
 663            * data property returns "data[0]".
 664        e.g. Optional
 665            * datavar property returns "data"
 666            * data property returns "data.get("field_name")".
 667        For other types
 668            * datavar property returns "data"
 669            * data property returns "data["field_name"]".
 670        """
 671
 672        if self.iterbased:
 673            return f"{self.datavar}[{self.index}]"
 674        elif is_union(self.type) and type(None) in get_args(self.type):
 675            return f'{self.datavar}.get("{self.conv_name()}")'
 676        else:
 677            return f'{self.datavar}["{self.conv_name()}"]'
 678
 679    @data.setter
 680    def data(self, d: str) -> None:
 681        self.datavar = d
 682
 683    def data_or(self) -> str:
 684        if self.iterbased:
 685            return self.data
 686        else:
 687            return f'{self.datavar}.get("{self.conv_name()}")'
 688
 689
 690@dataclass
 691class InnerField(DeField[T]):
 692    """
 693    Field of Inner type. The purpose of this class is to override "data" method
 694    for inner type codegen.
 695
 696    e.g.
 697      T of list[T]
 698      V of dict[K, V]
 699      T of Optional[T]
 700    """
 701
 702    @property
 703    def data(self) -> str:
 704        return self.datavar or ""
 705
 706    @data.setter
 707    def data(self, d: str) -> None:
 708        self.datavar = d
 709
 710
 711def defields(cls: type[Any]) -> list[DeField[Any]]:
 712    return fields(DeField, cls)
 713
 714
 715@dataclass
 716class Renderer:
 717    """
 718    Render rvalue for code generation.
 719    """
 720
 721    func: str
 722    cls: Optional[type[Any]] = None
 723    legacy_class_deserializer: Optional[DeserializeFunc] = None
 724    import_numpy: bool = False
 725    suppress_coerce: bool = False
 726    """ Disable type coercing in codegen """
 727    class_deserializer: Optional[ClassDeserializer] = None
 728    class_name: Optional[str] = None
 729
 730    def render(self, arg: DeField[Any]) -> str:
 731        """
 732        Render rvalue
 733        """
 734        implemented_methods: dict[type[Any], int] = {}
 735        class_deserializers: Iterable[ClassDeserializer] = itertools.chain(
 736            GLOBAL_CLASS_DESERIALIZER, [self.class_deserializer] if self.class_deserializer else []
 737        )
 738        for n, class_deserializer in enumerate(class_deserializers):
 739            for method in class_deserializer.__class__.deserialize.methods:  # type: ignore
 740                implemented_methods[get_args(method.signature.types[1])[0]] = n
 741
 742        custom_deserializer_available = arg.type in implemented_methods
 743        if custom_deserializer_available and not arg.deserializer:
 744            res = (
 745                f"class_deserializers[{implemented_methods[arg.type]}].deserialize("
 746                f"{typename(arg.type)}, {arg.data})"
 747            )
 748        elif arg.deserializer and arg.deserializer.inner is not default_deserializer:
 749            res = self.custom_field_deserializer(arg)
 750        elif is_generic(arg.type):
 751            arg.type_args = list(get_args(arg.type))
 752            origin = get_origin(arg.type)
 753            assert origin
 754            arg.type = origin
 755            res = self.render(arg)
 756        elif is_dataclass(arg.type):
 757            res = self.dataclass(arg)
 758        elif is_opt(arg.type):
 759            res = self.opt(arg)
 760        elif is_list(arg.type):
 761            res = self.list(arg)
 762        elif is_set(arg.type):
 763            res = self.set(arg)
 764        elif is_dict(arg.type):
 765            res = self.dict(arg)
 766        elif is_tuple(arg.type):
 767            res = self.tuple(arg)
 768        elif is_enum(arg.type):
 769            res = self.enum(arg)
 770        elif _is_numpy_scalar(arg.type):
 771            from .numpy import deserialize_numpy_scalar
 772
 773            self.import_numpy = True
 774            res = deserialize_numpy_scalar(arg)
 775        elif _is_numpy_array(arg.type):
 776            from .numpy import deserialize_numpy_array
 777
 778            self.import_numpy = True
 779            res = deserialize_numpy_array(arg)
 780        elif _is_numpy_jaxtyping(arg.type):
 781            from .numpy import deserialize_numpy_jaxtyping_array
 782
 783            self.import_numpy = True
 784            res = deserialize_numpy_jaxtyping_array(arg)
 785        elif is_union(arg.type):
 786            res = self.union_func(arg)
 787        elif is_str_serializable(arg.type):
 788            res = f"({self.c_tor_with_check(arg)}) if reuse_instances else {self.c_tor(arg)}"
 789        elif is_datetime(arg.type):
 790            from_iso = f"{typename(arg.type)}.fromisoformat({arg.data})"
 791            res = f"({arg.data} if isinstance({arg.data}, {typename(arg.type)}) else {from_iso}) \
 792                    if reuse_instances else {from_iso}"
 793        elif is_none(arg.type):
 794            res = "None"
 795        elif is_any(arg.type) or is_ellipsis(arg.type):
 796            res = arg.data
 797        elif is_pep695_type_alias(arg.type):
 798            res = self.render(DeField(name=arg.name, type=arg.type.__value__, datavar=arg.datavar))
 799        elif is_primitive(arg.type):
 800            # For subclasses for primitives e.g. class FooStr(str), coercing is always enabled
 801            res = self.primitive(arg, not is_primitive_subclass(arg.type))
 802        elif isinstance(arg.type, TypeVar):
 803            if not self.cls:
 804                raise SerdeError("Missing cls")
 805            index = find_generic_arg(self.cls, arg.type)
 806            res = (
 807                f"from_obj(get_generic_arg(maybe_generic, maybe_generic_type_vars, "
 808                f"variable_type_args, {index}), {arg.data}, named={not arg.iterbased}, "
 809                "reuse_instances=reuse_instances)"
 810            )
 811        elif is_literal(arg.type):
 812            res = self.literal(arg)
 813        else:
 814            return f"raise_unsupported_type({arg.data})"
 815
 816        if arg.supports_default():
 817            res = self.default(arg, res)
 818
 819        if (
 820            self.legacy_class_deserializer
 821            and not arg.deserializer
 822            and not custom_deserializer_available
 823        ):
 824            # Rerender the code for default deserializer.
 825            default = Renderer(
 826                self.func, self.cls, None, suppress_coerce=self.suppress_coerce
 827            ).render(arg)
 828            return self.custom_class_deserializer(arg, default)
 829        else:
 830            return res
 831
 832    def custom_field_deserializer(self, arg: DeField[Any]) -> str:
 833        """
 834        Render rvalue for the field with custom deserializer.
 835        """
 836        if not arg.deserializer:
 837            raise SerdeError("Missing custom field deserializer")
 838        return f"{arg.deserializer.name}({arg.data})"
 839
 840    def custom_class_deserializer(self, arg: DeField[Any], code: str) -> str:
 841        """
 842        Render custom class deserializer.
 843        """
 844        # The function takes a closure in order to execute the default value lazily.
 845        return (
 846            "serde_legacy_custom_class_deserializer("
 847            f"{typename(arg.type)}, "
 848            f"{arg.datavar}, "
 849            f"{arg.data_or()}, "
 850            f"default=lambda: {code})"
 851        )
 852
 853    def dataclass(self, arg: DeField[Any]) -> str:
 854        if not arg.flatten:
 855            # e.g. "data['field']" will be used as variable name.
 856            var = arg.data
 857        else:
 858            # Because the field is flattened
 859            # e.g. "data" will be used as variable name.
 860            assert arg.datavar
 861            if arg.iterbased:
 862                var = f"{arg.datavar}[{arg.index}:]"
 863            else:
 864                var = arg.datavar
 865
 866        type_args_str = [str(t).lstrip("~") for t in arg.type_args] if arg.type_args else None
 867
 868        opts = (
 869            "maybe_generic=maybe_generic, maybe_generic_type_vars=maybe_generic_type_vars, "
 870            f"variable_type_args={type_args_str}, reuse_instances=reuse_instances"
 871        )
 872
 873        if arg.is_self_referencing():
 874            class_name = "cls"
 875        else:
 876            class_name = typename(arg.type)
 877
 878        return f"{class_name}.{SERDE_SCOPE}.funcs['{self.func}'](data={var}, {opts})"
 879
 880    def opt(self, arg: DeField[Any]) -> str:
 881        """
 882        Render rvalue for Optional.
 883        """
 884        inner = arg[0]
 885        if arg.iterbased:
 886            exists = f"{arg.data} is not None"
 887        elif arg.flatten:
 888            # Check nullabilities of all nested fields.
 889            exists = " and ".join(
 890                [
 891                    f'{arg.datavar}.get("{f.name}") is not None'
 892                    for f in dataclasses.fields(inner.type)
 893                ]
 894            )
 895        else:
 896            name = arg.conv_name()
 897            if arg.alias:
 898                aliases = (f'"{s}"' for s in [name, *arg.alias])
 899                get = f"_get_by_aliases(data, [{','.join(aliases)}], raise_error=False)"
 900            else:
 901                get = f'{arg.datavar}.get("{name}")'
 902            exists = f"{get} is not None"
 903        return f"({self.render(inner)}) if {exists} else None"
 904
 905    def list(self, arg: DeField[Any]) -> str:
 906        """
 907        Render rvalue for list.
 908        """
 909        if is_bare_list(arg.type):
 910            return f"list({arg.data})"
 911        else:
 912            return f"[{self.render(arg[0])} for v in {arg.data}]"
 913
 914    def set(self, arg: DeField[Any]) -> str:
 915        """
 916        Render rvalue for set.
 917        """
 918        if is_bare_set(arg.type):
 919            return f"set({arg.data})"
 920        elif is_frozen_set(arg.type):
 921            return f"frozenset({self.render(arg[0])} for v in {arg.data})"
 922        else:
 923            return f"set({self.render(arg[0])} for v in {arg.data})"
 924
 925    def tuple(self, arg: DeField[Any]) -> str:
 926        """
 927        Render rvalue for tuple.
 928        """
 929        if is_bare_tuple(arg.type):
 930            return f"tuple({arg.data})"
 931        elif is_variable_tuple(arg.type):
 932            earg = arg[0]
 933            earg.datavar = "v"
 934            return f"tuple({self.render(earg)} for v in {arg.data})"
 935        else:
 936            values = []
 937            for i, _typ in enumerate(type_args(arg.type)):
 938                inner = arg[i]
 939                values.append(self.render(inner))
 940            return f'({", ".join(values)},)'  # trailing , is required for single element tuples
 941
 942    def dict(self, arg: DeField[Any]) -> str:
 943        """
 944        Render rvalue for dict.
 945        """
 946        if is_bare_dict(arg.type):
 947            return arg.data
 948        elif is_default_dict(arg.type):
 949            k = arg.key_field()
 950            v = arg.value_field()
 951            origin = get_origin(v.type)
 952            if origin:
 953                # When the callable type is of generic type e.g list.
 954                # Get origin type "list" from "list[X]".
 955                callable = origin.__name__
 956            else:
 957                # When the callable type is non generic type e.g int, Foo.
 958                callable = v.type.__name__
 959            return f"collections.defaultdict({callable}, \
 960                    {{{self.render(k)}: {self.render(v)} for k, v in {arg.data}.items()}})"
 961        else:
 962            k = arg.key_field()
 963            v = arg.value_field()
 964            return f"{{{self.render(k)}: {self.render(v)} for k, v in {arg.data}.items()}}"
 965
 966    def enum(self, arg: DeField[Any]) -> str:
 967        return f"{typename(arg.type)}({self.primitive(arg)})"
 968
 969    def primitive(self, arg: DeField[Any], suppress_coerce: bool = False) -> str:
 970        """
 971        Render rvalue for primitives.
 972
 973        * `suppress_coerce`: Overrides "suppress_coerce" in the Renderer's field
 974        """
 975        typ = typename(arg.type)
 976        dat = arg.data
 977        if arg.alias:
 978            aliases = (f'"{s}"' for s in [arg.name, *arg.alias])
 979            dat = f"_get_by_aliases(data, [{','.join(aliases)}])"
 980        if self.suppress_coerce and suppress_coerce:
 981            return dat
 982        else:
 983            assert arg.name
 984            escaped_arg_name = arg.name.replace('"', '\\"')
 985            return f'coerce_object("{self.class_name}", "{escaped_arg_name}", {typ}, {dat})'
 986
 987    def c_tor(self, arg: DeField[Any]) -> str:
 988        return f"{typename(arg.type)}({arg.data})"
 989
 990    def c_tor_with_check(self, arg: DeField[Any], ctor: Optional[str] = None) -> str:
 991        if ctor is None:
 992            ctor = self.c_tor(arg)
 993        return f"{arg.data} if isinstance({arg.data}, {typename(arg.type)}) else {ctor}"
 994
 995    def union_func(self, arg: DeField[Any]) -> str:
 996        func_name = union_func_name(UNION_DE_PREFIX, type_args(arg.type))
 997        return (
 998            f"serde_scope.funcs['{func_name}']("
 999            "cls=cls, "
1000            f"data={arg.data}, "
1001            "reuse_instances=reuse_instances)"
1002        )
1003
1004    def literal(self, arg: DeField[Any]) -> str:
1005        func_name = literal_func_name(type_args(arg.type))
1006        return (
1007            f"serde_scope.funcs['{func_name}']("
1008            "cls=cls, "
1009            f"data={arg.data}, "
1010            "reuse_instances=reuse_instances)"
1011        )
1012
1013    def default(self, arg: DeField[Any], code: str) -> str:
1014        """
1015        Renders supplying default value during deserialization.
1016        """
1017
1018        def get_aliased_fields(arg: Field[Any]) -> Iterator[str]:
1019            return (f'"{s}"' for s in [arg.name, *arg.alias])
1020
1021        if arg.flatten:
1022            # When a field has the `flatten` attribute, iterate over its dataclass fields.
1023            # This ensures that the code checks keys in the data while considering aliases.
1024            flattened = []
1025            for subarg in defields(arg.type):
1026                if subarg.alias:
1027                    aliases = get_aliased_fields(subarg)
1028                    flattened.append(f'_exists_by_aliases({arg.datavar}, [{",".join(aliases)}])')
1029                else:
1030                    flattened.append(f'"{subarg.name}" in {arg.datavar}')
1031            exists = " and ".join(flattened)
1032        else:
1033            if arg.alias:
1034                aliases = get_aliased_fields(arg)
1035                exists = f'_exists_by_aliases({arg.datavar}, [{",".join(aliases)}])'
1036            else:
1037                exists = f'"{arg.conv_name()}" in {arg.datavar}'
1038
1039        if has_default(arg):
1040            return f'({code}) if {exists} else serde_scope.defaults["{arg.name}"]'
1041        elif has_default_factory(arg):
1042            return f'({code}) if {exists} else serde_scope.defaults["{arg.name}"]()'
1043        else:
1044            return code
1045
1046
1047def to_arg(f: DeField[T], index: int, rename_all: Optional[str] = None) -> DeField[T]:
1048    f.index = index
1049    f.data = "data"
1050    f.case = f.case or rename_all
1051    return f
1052
1053
1054def to_iter_arg(f: DeField[T], *args: Any, **kwargs: Any) -> DeField[T]:
1055    f = to_arg(f, *args, **kwargs)
1056    f.iterbased = True
1057    return f
1058
1059
1060def renderable(f: DeField[Any]) -> bool:
1061    return f.init
1062
1063
1064jinja2_env = jinja2.Environment(
1065    loader=jinja2.DictLoader(
1066        {
1067            "iter": """
1068def {{func}}(cls=cls, maybe_generic=None, maybe_generic_type_vars=None, data=None,
1069             variable_type_args=None, reuse_instances=None):
1070  if reuse_instances is None:
1071    reuse_instances = {{serde_scope.reuse_instances_default}}
1072
1073  maybe_generic_type_vars = maybe_generic_type_vars or {{cls_type_vars}}
1074
1075  {% for f in fields %}
1076  __{{f.name}} = {{rvalue(arg(f,loop.index-1))}}
1077  {% endfor %}
1078
1079  try:
1080    return cls(
1081      {% for f in fields %}
1082      __{{f.name}},
1083      {% endfor %}
1084    )
1085  except BeartypeCallHintParamViolation as e:
1086    raise SerdeError(e)
1087  except Exception as e:
1088    raise UserError(e)
1089""",
1090            "dict": """
1091def {{func}}(cls=cls, maybe_generic=None, maybe_generic_type_vars=None, data=None,
1092             variable_type_args=None, reuse_instances=None):
1093  if reuse_instances is None:
1094    reuse_instances = {{serde_scope.reuse_instances_default}}
1095
1096  {% if deny_unknown_fields %}
1097  known_fields = {{ known_fields }}
1098  unknown_fields = set((data or {}).keys()) - known_fields
1099  if unknown_fields:
1100    raise SerdeError(f'unknown fields: {unknown_fields}, expected one of {known_fields}')
1101  {% endif %}
1102
1103  maybe_generic_type_vars = maybe_generic_type_vars or {{cls_type_vars}}
1104
1105  {% for f in fields %}
1106  __{{f.name}} = {{rvalue(arg(f,loop.index-1))}}
1107  {% endfor %}
1108
1109  try:
1110    return cls(
1111    {% for f in fields %}
1112    {% if f.kw_only %}
1113    {{f.name}}=__{{f.name}},
1114    {% else %}
1115    __{{f.name}},
1116    {% endif %}
1117    {% endfor %}
1118    )
1119  except BeartypeCallHintParamViolation as e:
1120    raise SerdeError(e)
1121  except Exception as e:
1122    raise UserError(e)
1123""",
1124            "union": """
1125def {{func}}(cls=cls, maybe_generic=None, maybe_generic_type_vars=None, data=None,
1126             variable_type_args=None, reuse_instances = {{serde_scope.reuse_instances_default}}):
1127  errors = []
1128  {% for t in union_args %}
1129  try:
1130    # create fake dict so we can reuse the normal render function
1131    {% if tagging.is_external() and is_taggable(t)  %}
1132    ensure("{{typename(t)}}" in data , "'{{typename(t)}}' key is not present")
1133    fake_dict = {"fake_key": data["{{typename(t)}}"]}
1134
1135    {% elif tagging.is_internal() and is_taggable(t) %}
1136    ensure("{{tagging.tag}}" in data , "'{{tagging.tag}}' key is not present")
1137    ensure("{{typename(t)}}" == data["{{tagging.tag}}"], "tag '{{typename(t)}}' isn't found")
1138    fake_dict = {"fake_key": data}
1139
1140    {% elif tagging.is_adjacent() and is_taggable(t) %}
1141    ensure("{{tagging.tag}}" in data , "'{{tagging.tag}}' key is not present")
1142    ensure("{{tagging.content}}" in data , "'{{tagging.content}}' key is not present")
1143    ensure("{{typename(t)}}" == data["{{tagging.tag}}"], "tag '{{typename(t)}}' isn't found")
1144    fake_dict = {"fake_key": data["{{tagging.content}}"]}
1145
1146    {% else %}
1147    fake_dict = {"fake_key": data}
1148    {% endif %}
1149
1150    {% if is_primitive(t) or is_none(t) %}
1151    if not isinstance(fake_dict["fake_key"], {{typename(t)}}):
1152        raise Exception("Not a type of {{typename(t)}}")
1153    {% endif %}
1154    res = {{rvalue(arg(t))}}
1155    ensure(is_bearable(res, {{typename(t)}}), "object is not of type '{{typename(t)}}'")
1156    return res
1157  except Exception as e:
1158    errors.append(f" Failed to deserialize into {{typename(t)}}: {e}")
1159  {% endfor %}
1160  raise SerdeError("Can not deserialize " + repr(data) + " of type " + \
1161          typename(type(data)) + " into {{union_name}}.\\nReasons:\\n" + "\\n".join(errors))
1162""",
1163            "literal": """
1164def {{func}}(cls=cls, maybe_generic=None, maybe_generic_type_vars=None, data=None,
1165             variable_type_args=None, reuse_instances = {{serde_scope.reuse_instances_default}}):
1166  if data in ({%- for v in literal_args -%}{{repr(v)}},{%- endfor -%}):
1167    return data
1168  raise SerdeError("Can not deserialize " + repr(data) + " as {{literal_name}}.")
1169  """,
1170        }
1171    )
1172)
1173
1174
1175def render_from_iter(
1176    cls: type[Any],
1177    legacy_class_deserializer: Optional[DeserializeFunc] = None,
1178    type_check: TypeCheck = strict,
1179    class_deserializer: Optional[ClassDeserializer] = None,
1180) -> str:
1181    renderer = Renderer(
1182        FROM_ITER,
1183        cls=cls,
1184        legacy_class_deserializer=legacy_class_deserializer,
1185        suppress_coerce=(not type_check.is_coerce()),
1186        class_deserializer=class_deserializer,
1187        class_name=typename(cls),
1188    )
1189    fields = list(filter(renderable, defields(cls)))
1190    res = jinja2_env.get_template("iter").render(
1191        func=FROM_ITER,
1192        serde_scope=getattr(cls, SERDE_SCOPE),
1193        fields=fields,
1194        cls_type_vars=get_type_var_names(cls),
1195        rvalue=renderer.render,
1196        arg=to_iter_arg,
1197    )
1198
1199    if renderer.import_numpy:
1200        res = "import numpy\n" + res
1201
1202    return res
1203
1204
1205def get_known_fields(f: DeField[Any], rename_all: Optional[str]) -> list[str]:
1206    names: list[str] = [f.conv_name(rename_all)]
1207    return names + f.alias
1208
1209
1210def render_from_dict(
1211    cls: type[Any],
1212    rename_all: Optional[str] = None,
1213    legacy_class_deserializer: Optional[DeserializeFunc] = None,
1214    type_check: TypeCheck = strict,
1215    class_deserializer: Optional[ClassDeserializer] = None,
1216    deny_unknown_fields: bool = False,
1217) -> str:
1218    renderer = Renderer(
1219        FROM_DICT,
1220        cls=cls,
1221        legacy_class_deserializer=legacy_class_deserializer,
1222        suppress_coerce=(not type_check.is_coerce()),
1223        class_deserializer=class_deserializer,
1224        class_name=typename(cls),
1225    )
1226    fields = list(filter(renderable, defields(cls)))
1227    known_fields = set(
1228        itertools.chain.from_iterable([get_known_fields(f, rename_all) for f in fields])
1229    )
1230    res = jinja2_env.get_template("dict").render(
1231        func=FROM_DICT,
1232        serde_scope=getattr(cls, SERDE_SCOPE),
1233        fields=fields,
1234        type_check=type_check,
1235        cls_type_vars=get_type_var_names(cls),
1236        rvalue=renderer.render,
1237        arg=functools.partial(to_arg, rename_all=rename_all),
1238        deny_unknown_fields=deny_unknown_fields,
1239        known_fields=known_fields,
1240    )
1241
1242    if renderer.import_numpy:
1243        res = "import numpy\n" + res
1244
1245    return res
1246
1247
1248def render_union_func(
1249    cls: type[Any], union_args: Sequence[type[Any]], tagging: Tagging = DefaultTagging
1250) -> str:
1251    union_name = f"Union[{', '.join([typename(a) for a in union_args])}]"
1252
1253    renderer = Renderer(FROM_DICT, cls=cls, suppress_coerce=True)
1254    return jinja2_env.get_template("union").render(
1255        func=union_func_name(UNION_DE_PREFIX, union_args),
1256        serde_scope=getattr(cls, SERDE_SCOPE),
1257        union_args=union_args,
1258        union_name=union_name,
1259        tagging=tagging,
1260        is_taggable=Tagging.is_taggable,
1261        arg=lambda x: DeField(x, datavar="fake_dict", name="fake_key"),
1262        rvalue=renderer.render,
1263        is_primitive=is_primitive,
1264        is_none=is_none,
1265        typename=typename,
1266    )
1267
1268
1269def render_literal_func(
1270    cls: type[Any], literal_args: Sequence[Any], tagging: Tagging = DefaultTagging
1271) -> str:
1272    literal_name = f"Literal[{', '.join([repr(a) for a in literal_args])}]"
1273    return jinja2_env.get_template("literal").render(
1274        func=literal_func_name(literal_args),
1275        serde_scope=getattr(cls, SERDE_SCOPE),
1276        literal_args=literal_args,
1277        literal_name=literal_name,
1278        tagging=tagging,
1279        is_taggable=Tagging.is_taggable,
1280        repr=repr,
1281        type=type,
1282    )
@dataclass_transform()
def deserialize( _cls: Optional[type[~T]] = None, rename_all: Optional[str] = None, reuse_instances_default: bool = True, convert_sets_default: bool = False, deserializer: Optional[Callable[[type[Any], Any], Any]] = None, tagging: serde.core.Tagging = Tagging(tag=None, content=None, kind=<Kind.External: 1>), type_check: serde.core.TypeCheck = TypeCheck(kind=<Kind.Strict: 3>), class_deserializer: Optional[serde.ClassDeserializer] = None, deny_unknown_fields: bool = False, **kwargs: Any) -> type[~T]:
200@dataclass_transform()
201def deserialize(
202    _cls: Optional[type[T]] = None,
203    rename_all: Optional[str] = None,
204    reuse_instances_default: bool = True,
205    convert_sets_default: bool = False,
206    deserializer: Optional[DeserializeFunc] = None,
207    tagging: Tagging = DefaultTagging,
208    type_check: TypeCheck = strict,
209    class_deserializer: Optional[ClassDeserializer] = None,
210    deny_unknown_fields: bool = False,
211    **kwargs: Any,
212) -> type[T]:
213    """
214    A dataclass with this decorator is deserializable from any of the data formats supported
215    by pyserde.
216
217    >>> from serde import deserialize
218    >>> from serde.json import from_json
219    >>>
220    >>> @deserialize
221    ... class Foo:
222    ...     i: int
223    ...     s: str
224    ...     f: float
225    ...     b: bool
226    >>>
227    >>> from_json(Foo, '{"i": 10, "s": "foo", "f": 100.0, "b": true}')
228    Foo(i=10, s='foo', f=100.0, b=True)
229    """
230
231    stack = []
232
233    def wrap(cls: type[T]) -> type[T]:
234        if cls in stack:
235            return cls
236        stack.append(cls)
237
238        tagging.check()
239
240        # If no `dataclass` found in the class, dataclassify it automatically.
241        if not is_dataclass(cls):
242            dataclass(cls)
243
244        if type_check.is_strict():
245            serde_beartype = beartype(conf=BeartypeConf(violation_type=SerdeError))
246            serde_beartype(cls)
247
248        g: dict[str, Any] = {}
249
250        # Create a scope storage used by serde.
251        # Each class should get own scope. Child classes can not share scope with parent class.
252        # That's why we need the "scope.cls is not cls" check.
253        scope: Optional[Scope] = getattr(cls, SERDE_SCOPE, None)
254        if scope is None or scope.cls is not cls:
255            scope = Scope(cls, reuse_instances_default=reuse_instances_default)
256            setattr(cls, SERDE_SCOPE, scope)
257
258        class_deserializers: list[ClassDeserializer] = list(
259            itertools.chain(
260                GLOBAL_CLASS_DESERIALIZER, [class_deserializer] if class_deserializer else []
261            )
262        )
263
264        # Set some globals for all generated functions
265        g["cls"] = cls
266        g["serde_scope"] = scope
267        g["SerdeError"] = SerdeError
268        g["UserError"] = UserError
269        g["raise_unsupported_type"] = raise_unsupported_type
270        g["typename"] = typename
271        g["ensure"] = ensure
272        g["typing"] = typing
273        g["collections"] = collections
274        g["Literal"] = Literal
275        g["from_obj"] = from_obj
276        g["get_generic_arg"] = get_generic_arg
277        g["is_instance"] = is_instance
278        g["TypeCheck"] = TypeCheck
279        g["disabled"] = disabled
280        g["coerce_object"] = coerce_object
281        g["_exists_by_aliases"] = _exists_by_aliases
282        g["_get_by_aliases"] = _get_by_aliases
283        g["class_deserializers"] = class_deserializers
284        g["BeartypeCallHintParamViolation"] = BeartypeCallHintParamViolation
285        g["is_bearable"] = is_bearable
286        if deserializer:
287            g["serde_legacy_custom_class_deserializer"] = functools.partial(
288                serde_legacy_custom_class_deserializer, custom=deserializer
289            )
290
291        # Collect types used in the generated code.
292        for typ in iter_types(cls):
293            # When we encounter a dataclass not marked with deserialize, then also generate
294            # deserialize functions for it.
295            if is_dataclass_without_de(typ) and typ is not cls:
296                # We call deserialize and not wrap to make sure that we will use the default serde
297                # configuration for generating the deserialization function.
298                deserialize(typ)
299
300            # We don't want to add primitive class e.g "str" into the scope, but primitive
301            # compatible types such as IntEnum and a subclass of primitives are added,
302            # so that generated code can use those types.
303            if is_primitive(typ) and not is_enum(typ) and not is_primitive_subclass(typ):
304                continue
305
306            if is_generic(typ):
307                g[typename(typ)] = get_origin(typ)
308            else:
309                g[typename(typ)] = typ
310
311        # render all union functions
312        for union in iter_unions(cls):
313            union_args = type_args(union)
314            add_func(
315                scope,
316                union_func_name(UNION_DE_PREFIX, union_args),
317                render_union_func(cls, union_args, tagging),
318                g,
319            )
320
321        # render literal functions
322        for literal in iter_literals(cls):
323            literal_args = type_args(literal)
324            add_func(
325                scope, literal_func_name(literal_args), render_literal_func(cls, literal_args), g
326            )
327
328        # Collect default values and default factories used in the generated code.
329        for f in defields(cls):
330            assert f.name
331            if has_default(f):
332                scope.defaults[f.name] = f.default
333            elif has_default_factory(f):
334                scope.defaults[f.name] = f.default_factory
335            if f.deserializer:
336                g[f.deserializer.name] = f.deserializer
337
338        add_func(
339            scope,
340            FROM_ITER,
341            render_from_iter(cls, deserializer, type_check, class_deserializer=class_deserializer),
342            g,
343        )
344        add_func(
345            scope,
346            FROM_DICT,
347            render_from_dict(
348                cls,
349                rename_all,
350                deserializer,
351                type_check,
352                class_deserializer=class_deserializer,
353                deny_unknown_fields=deny_unknown_fields,
354            ),
355            g,
356        )
357
358        logger.debug(f"{typename(cls)}: {SERDE_SCOPE} {scope}")
359
360        stack.pop()
361        return cls
362
363    if _cls is None:
364        return wrap  # type: ignore
365
366    if _cls in GENERATION_STACK:
367        return _cls
368
369    GENERATION_STACK.append(_cls)
370    try:
371        return wrap(_cls)
372    finally:
373        GENERATION_STACK.pop()

A dataclass with this decorator is deserializable from any of the data formats supported by pyserde.

>>> from serde import deserialize
>>> from serde.json import from_json
>>>
>>> @deserialize
... class Foo:
...     i: int
...     s: str
...     f: float
...     b: bool
>>>
>>> from_json(Foo, '{"i": 10, "s": "foo", "f": 100.0, "b": true}')
Foo(i=10, s='foo', f=100.0, b=True)
def is_deserializable(instance_or_class: Any) -> bool:
376def is_deserializable(instance_or_class: Any) -> bool:
377    """
378    Test if an instance or class is deserializable.
379
380    >>> @deserialize
381    ... class Foo:
382    ...     pass
383    >>>
384    >>> is_deserializable(Foo)
385    True
386    """
387    return hasattr(instance_or_class, SERDE_SCOPE)

Test if an instance or class is deserializable.

>>> @deserialize
... class Foo:
...     pass
>>>
>>> is_deserializable(Foo)
True
def from_dict( cls: Any, o: dict[str, typing.Any], reuse_instances: Optional[bool] = None) -> Any:
535def from_dict(cls: Any, o: dict[str, Any], reuse_instances: Optional[bool] = None) -> Any:
536    """
537    Deserialize dictionary into object.
538
539    >>> @deserialize
540    ... class Foo:
541    ...     i: int
542    ...     s: str = 'foo'
543    ...     f: float = 100.0
544    ...     b: bool = True
545    >>>
546    >>> from_dict(Foo, {'i': 10, 's': 'foo', 'f': 100.0, 'b': True})
547    Foo(i=10, s='foo', f=100.0, b=True)
548
549    You can pass any type supported by pyserde. For example,
550
551    >>> lst = [{'i': 10, 's': 'foo', 'f': 100.0, 'b': True},
552    ...        {'i': 20, 's': 'foo', 'f': 100.0, 'b': True}]
553    >>> from_dict(list[Foo], lst)
554    [Foo(i=10, s='foo', f=100.0, b=True), Foo(i=20, s='foo', f=100.0, b=True)]
555    """
556    return from_obj(cls, o, named=True, reuse_instances=reuse_instances)

Deserialize dictionary into object.

>>> @deserialize
... class Foo:
...     i: int
...     s: str = 'foo'
...     f: float = 100.0
...     b: bool = True
>>>
>>> from_dict(Foo, {'i': 10, 's': 'foo', 'f': 100.0, 'b': True})
Foo(i=10, s='foo', f=100.0, b=True)

You can pass any type supported by pyserde. For example,

>>> lst = [{'i': 10, 's': 'foo', 'f': 100.0, 'b': True},
...        {'i': 20, 's': 'foo', 'f': 100.0, 'b': True}]
>>> from_dict(list[Foo], lst)
[Foo(i=10, s='foo', f=100.0, b=True), Foo(i=20, s='foo', f=100.0, b=True)]
def from_tuple(cls: Any, o: Any, reuse_instances: Optional[bool] = None) -> Any:
567def from_tuple(cls: Any, o: Any, reuse_instances: Optional[bool] = None) -> Any:
568    """
569    Deserialize tuple into object.
570
571    >>> @deserialize
572    ... class Foo:
573    ...     i: int
574    ...     s: str = 'foo'
575    ...     f: float = 100.0
576    ...     b: bool = True
577    >>>
578    >>> from_tuple(Foo, (10, 'foo', 100.0, True))
579    Foo(i=10, s='foo', f=100.0, b=True)
580
581    You can pass any type supported by pyserde. For example,
582
583    >>> lst = [(10, 'foo', 100.0, True), (20, 'foo', 100.0, True)]
584    >>> from_tuple(list[Foo], lst)
585    [Foo(i=10, s='foo', f=100.0, b=True), Foo(i=20, s='foo', f=100.0, b=True)]
586    """
587    return from_obj(cls, o, named=False, reuse_instances=reuse_instances)

Deserialize tuple into object.

>>> @deserialize
... class Foo:
...     i: int
...     s: str = 'foo'
...     f: float = 100.0
...     b: bool = True
>>>
>>> from_tuple(Foo, (10, 'foo', 100.0, True))
Foo(i=10, s='foo', f=100.0, b=True)

You can pass any type supported by pyserde. For example,

>>> lst = [(10, 'foo', 100.0, True), (20, 'foo', 100.0, True)]
>>> from_tuple(list[Foo], lst)
[Foo(i=10, s='foo', f=100.0, b=True), Foo(i=20, s='foo', f=100.0, b=True)]