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