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