Repository: yukinarit/pyserde
Pull request #634 (2025-02-14 13:49:52)

Refactor generated function


Patch:
diff --git a/docs/en/faq.md b/docs/en/faq.md
index 875b8ff..fee7b9b 100644
--- a/docs/en/faq.md
+++ b/docs/en/faq.md
@@ -26,7 +26,7 @@ Loading simple.Foo from examples.
 --------------------------------------------------
           Functions generated by pyserde
 --------------------------------------------------
-def to_iter(obj, reuse_instances=True, convert_sets=False):
+def to_tuple(obj, reuse_instances=True, convert_sets=False):
     if reuse_instances is Ellipsis:
         reuse_instances = True
     if convert_sets is Ellipsis:
diff --git a/docs/ja/faq.md b/docs/ja/faq.md
index 0e5920a..bb84c89 100644
--- a/docs/ja/faq.md
+++ b/docs/ja/faq.md
@@ -26,7 +26,7 @@ Loading simple.Foo from examples.
 --------------------------------------------------
           Functions generated by pyserde
 --------------------------------------------------
-def to_iter(obj, reuse_instances=True, convert_sets=False):
+def to_tuple(obj, reuse_instances=True, convert_sets=False):
     if reuse_instances is Ellipsis:
         reuse_instances = True
     if convert_sets is Ellipsis:
diff --git a/serde/core.py b/serde/core.py
index 30d7a9b..51a486a 100644
--- a/serde/core.py
+++ b/serde/core.py
@@ -70,9 +70,9 @@ logger = logging.getLogger("serde")
 SERDE_SCOPE = "__serde__"
 
 # main function keys
-FROM_ITER = "from_iter"
+FROM_TUPLE = "from_tuple"
 FROM_DICT = "from_dict"
-TO_ITER = "to_iter"
+TO_TUPLE = "to_tuple"
 TO_DICT = "to_dict"
 TYPE_CHECK = "typecheck"
 
@@ -687,7 +687,7 @@ class Field(Generic[T]):
         return conv(self, case or self.case)
 
     def supports_default(self) -> bool:
-        return not getattr(self, "iterbased", False) and (
+        return not getattr(self, "named", False) and (
             has_default(self) or has_default_factory(self)
         )
 
diff --git a/serde/de.py b/serde/de.py
index 569148d..e8cc976 100644
--- a/serde/de.py
+++ b/serde/de.py
@@ -63,7 +63,7 @@ from .core import (
     GLOBAL_CLASS_DESERIALIZER,
     ClassDeserializer,
     FROM_DICT,
-    FROM_ITER,
+    FROM_TUPLE,
     SERDE_SCOPE,
     CACHE,
     UNION_DE_PREFIX,
@@ -231,8 +231,6 @@ def deserialize(
             serde_beartype = beartype(conf=BeartypeConf(violation_type=SerdeError))
             serde_beartype(cls)
 
-        g: dict[str, Any] = {}
-
         # Create a scope storage used by serde.
         # Each class should get own scope. Child classes can not share scope with parent class.
         # That's why we need the "scope.cls is not cls" check.
@@ -248,27 +246,29 @@ def deserialize(
         )
 
         # Set some globals for all generated functions
-        g["cls"] = cls
-        g["serde_scope"] = scope
-        g["SerdeError"] = SerdeError
-        g["UserError"] = UserError
-        g["raise_unsupported_type"] = raise_unsupported_type
-        g["typename"] = typename
-        g["ensure"] = ensure
-        g["typing"] = typing
-        g["collections"] = collections
-        g["Literal"] = Literal
-        g["from_obj"] = from_obj
-        g["get_generic_arg"] = get_generic_arg
-        g["is_instance"] = is_instance
-        g["TypeCheck"] = TypeCheck
-        g["disabled"] = disabled
-        g["coerce_object"] = coerce_object
-        g["_exists_by_aliases"] = _exists_by_aliases
-        g["_get_by_aliases"] = _get_by_aliases
-        g["class_deserializers"] = class_deserializers
-        g["BeartypeCallHintParamViolation"] = BeartypeCallHintParamViolation
-        g["is_bearable"] = is_bearable
+        g: dict[str, Any] = {
+            "BeartypeCallHintParamViolation": BeartypeCallHintParamViolation,
+            "class_deserializers": class_deserializers,
+            "cls": cls,
+            "coerce_object": coerce_object,
+            "collections": collections,
+            "disabled": disabled,
+            "get_generic_arg": get_generic_arg,
+            "from_obj": from_obj,
+            "ensure": ensure,
+            "is_bearable": is_bearable,
+            "is_instance": is_instance,
+            "Literal": Literal,
+            "raise_unsupported_type": raise_unsupported_type,
+            "SerdeError": SerdeError,
+            "serde_scope": scope,
+            "TypeCheck": TypeCheck,
+            "typename": typename,
+            "typing": typing,
+            "UserError": UserError,
+            "_exists_by_aliases": _exists_by_aliases,
+            "_get_by_aliases": _get_by_aliases,
+        }
         if deserializer:
             g["serde_legacy_custom_class_deserializer"] = functools.partial(
                 serde_legacy_custom_class_deserializer, custom=deserializer
@@ -323,8 +323,8 @@ def deserialize(
 
         add_func(
             scope,
-            FROM_ITER,
-            render_from_iter(cls, deserializer, type_check, class_deserializer=class_deserializer),
+            FROM_TUPLE,
+            render_from_tuple(cls, deserializer, type_check, class_deserializer=class_deserializer),
             g,
         )
         add_func(
@@ -419,7 +419,7 @@ def from_obj(c: type[T], o: Any, named: bool, reuse_instances: Optional[bool]) -
 
     def deserializable_to_obj(cls: type[T]) -> T:
         serde_scope: Scope = getattr(cls, SERDE_SCOPE)
-        func_name = FROM_DICT if named else FROM_ITER
+        func_name = FROM_DICT if named else FROM_TUPLE
         res = serde_scope.funcs[func_name](
             cls, maybe_generic=maybe_generic, data=o, reuse_instances=reuse_instances
         )
@@ -583,8 +583,8 @@ class DeField(Field[T]):
     index: int = 0
     """ Field index """
 
-    iterbased: bool = False
-    """ Iterater based deserializer or not """
+    named: bool = False
+    """ True: deserialize to dict, False: deserialize to tuple """
 
     def __getitem__(self, n: int) -> Union[DeField[Any], InnerField[Any]]:
         """
@@ -619,7 +619,7 @@ class DeField(Field[T]):
                 self.name,
                 datavar=self.datavar,
                 index=self.index,
-                iterbased=self.iterbased,
+                named=self.named,
                 **opts,
             )
 
@@ -654,7 +654,7 @@ class DeField(Field[T]):
             * data property returns "data["field_name"]".
         """
 
-        if self.iterbased:
+        if self.named:
             return f"{self.datavar}[{self.index}]"
         elif is_union(self.type) and type(None) in get_args(self.type):
             return f'{self.datavar}.get("{self.conv_name()}")'
@@ -666,7 +666,7 @@ class DeField(Field[T]):
         self.datavar = d
 
     def data_or(self) -> str:
-        if self.iterbased:
+        if self.named:
             return self.data
         else:
             return f'{self.datavar}.get("{self.conv_name()}")'
@@ -784,7 +784,7 @@ class Renderer:
             index = find_generic_arg(self.cls, arg.type)
             res = (
                 f"from_obj(get_generic_arg(maybe_generic, maybe_generic_type_vars, "
-                f"variable_type_args, {index}), {arg.data}, named={not arg.iterbased}, "
+                f"variable_type_args, {index}), {arg.data}, named={not arg.named}, "
                 "reuse_instances=reuse_instances)"
             )
         elif is_literal(arg.type):
@@ -837,7 +837,7 @@ class Renderer:
             # Because the field is flattened
             # e.g. "data" will be used as variable name.
             assert arg.datavar
-            if arg.iterbased:
+            if arg.named:
                 var = f"{arg.datavar}[{arg.index}:]"
             else:
                 var = arg.datavar
@@ -861,7 +861,7 @@ class Renderer:
         Render rvalue for Optional.
         """
         inner = arg[0]
-        if arg.iterbased:
+        if arg.named:
             exists = f"{arg.data} is not None"
         elif arg.flatten:
             # Check nullabilities of all nested fields.
@@ -1032,7 +1032,7 @@ def to_arg(f: DeField[T], index: int, rename_all: Optional[str] = None) -> DeFie
 
 def to_iter_arg(f: DeField[T], *args: Any, **kwargs: Any) -> DeField[T]:
     f = to_arg(f, *args, **kwargs)
-    f.iterbased = True
+    f.named = True
     return f
 
 
@@ -1151,14 +1151,14 @@ def {{func}}(cls=cls, maybe_generic=None, maybe_generic_type_vars=None, data=Non
 )
 
 
-def render_from_iter(
+def render_from_tuple(
     cls: type[Any],
     legacy_class_deserializer: Optional[DeserializeFunc] = None,
     type_check: TypeCheck = strict,
     class_deserializer: Optional[ClassDeserializer] = None,
 ) -> str:
     renderer = Renderer(
-        FROM_ITER,
+        FROM_TUPLE,
         cls=cls,
         legacy_class_deserializer=legacy_class_deserializer,
         suppress_coerce=(not type_check.is_coerce()),
@@ -1167,7 +1167,7 @@ def render_from_iter(
     )
     fields = list(filter(renderable, defields(cls)))
     res = jinja2_env.get_template("iter").render(
-        func=FROM_ITER,
+        func=FROM_TUPLE,
         serde_scope=getattr(cls, SERDE_SCOPE),
         fields=fields,
         cls_type_vars=get_type_var_names(cls),
diff --git a/serde/se.py b/serde/se.py
index c1b8250..0ec5251 100644
--- a/serde/se.py
+++ b/serde/se.py
@@ -57,7 +57,7 @@ from .core import (
     CACHE,
     SERDE_SCOPE,
     TO_DICT,
-    TO_ITER,
+    TO_TUPLE,
     UNION_SE_PREFIX,
     DefaultTagging,
     Field,
@@ -202,8 +202,6 @@ def serialize(
             serde_beartype = beartype(conf=BeartypeConf(violation_type=SerdeError))
             serde_beartype(cls)
 
-        g: dict[str, Any] = {}
-
         # Create a scope storage used by serde.
         # Each class should get own scope. Child classes can not share scope with parent class.
         # That's why we need the "scope.cls is not cls" check.
@@ -221,22 +219,24 @@ def serialize(
         )
 
         # Set some globals for all generated functions
-        g["cls"] = cls
-        g["copy"] = copy
-        g["serde_scope"] = scope
-        g["SerdeError"] = SerdeError
-        g["raise_unsupported_type"] = raise_unsupported_type
-        g["enum_value"] = enum_value
-        g["is_dataclass"] = is_dataclass
-        g["typename"] = typename  # used in union functions
-        g["is_instance"] = is_instance  # used in union functions
-        g["to_obj"] = to_obj
-        g["typing"] = typing
-        g["Literal"] = Literal
-        g["TypeCheck"] = TypeCheck
-        g["disabled"] = disabled
-        g["coerce_object"] = coerce_object
-        g["class_serializers"] = class_serializers
+        g: dict[str, Any] = {
+            "class_serializers": class_serializers,
+            "cls": cls,
+            "coerce_object": coerce_object,
+            "copy": copy,
+            "disabled": disabled,
+            "enum_value": enum_value,
+            "is_dataclass": is_dataclass,
+            "is_instance": is_instance,
+            "Literal": Literal,
+            "raise_unsupported_type": raise_unsupported_type,
+            "SerdeError": SerdeError,
+            "serde_scope": scope,
+            "to_obj": to_obj,
+            "typename": typename,
+            "typing": typing,
+            "TypeCheck": TypeCheck,
+        }
         if serializer:
             g["serde_legacy_custom_class_serializer"] = functools.partial(
                 serde_legacy_custom_class_serializer, custom=serializer
@@ -270,7 +270,7 @@ def serialize(
 
         add_func(
             scope,
-            TO_ITER,
+            TO_TUPLE,
             render_to_tuple(cls, serializer, type_check, serialize_class_var, class_serializer),
             g,
         )
@@ -340,7 +340,7 @@ def to_obj(
 ) -> Any:
     def serializable_to_obj(object: Any) -> Any:
         serde_scope: Scope = getattr(object, SERDE_SCOPE)
-        func_name = TO_DICT if named else TO_ITER
+        func_name = TO_DICT if named else TO_TUPLE
         return serde_scope.funcs[func_name](
             object,
             reuse_instances=reuse_instances,
@@ -635,7 +635,7 @@ def render_to_tuple(
     class_serializer: Optional[ClassSerializer] = None,
 ) -> str:
     renderer = Renderer(
-        TO_ITER,
+        TO_TUPLE,
         legacy_class_serializer,
         suppress_coerce=(not type_check.is_coerce()),
         serialize_class_var=serialize_class_var,
@@ -643,7 +643,7 @@ def render_to_tuple(
         class_name=typename(cls),
     )
     return jinja2_env.get_template("iter").render(
-        func=TO_ITER,
+        func=TO_TUPLE,
         serde_scope=getattr(cls, SERDE_SCOPE),
         fields=sefields(cls, serialize_class_var),
         type_check=type_check,


Test patch:
diff --git a/tests/test_de.py b/tests/test_de.py
index 6348608..2905238 100644
--- a/tests/test_de.py
+++ b/tests/test_de.py
@@ -42,7 +42,7 @@ def test_render_primitives() -> None:
     rendered = Renderer("foo").render(DeField(int, "int_field", datavar="data", case="camelcase"))
     assert rendered == 'coerce_object("None", "int_field", int, data["intField"])'
 
-    rendered = Renderer("foo").render(DeField(int, "i", datavar="data", index=1, iterbased=True))
+    rendered = Renderer("foo").render(DeField(int, "i", datavar="data", index=1, named=True))
     assert rendered == 'coerce_object("None", "i", int, data[1])'
 
 
@@ -66,7 +66,7 @@ def test_render_tuple() -> None:
     rendered_foo = f"Foo.__serde__.funcs['foo'](data=data[\"d\"][3], {kwargs})"
     assert rendered == f"({rendered_str}, {rendered_int}, {rendered_lst}, {rendered_foo},)"
 
-    field = DeField(tuple[str, int, list[int], Foo], "d", datavar="data", index=0, iterbased=True)
+    field = DeField(tuple[str, int, list[int], Foo], "d", datavar="data", index=0, named=True)
     rendered = Renderer("foo").render(field)
     rendered_str = 'coerce_object("None", "data[0][0]", str, data[0][0])'
     rendered_int = 'coerce_object("None", "data[0][1]", int, data[0][1])'
diff --git a/tests/test_se.py b/tests/test_se.py
index a82e379..44021cc 100644
--- a/tests/test_se.py
+++ b/tests/test_se.py
@@ -2,7 +2,7 @@ from serde import asdict, astuple, serialize, to_dict, to_tuple
 from serde.json import to_json
 from serde.msgpack import to_msgpack
 from serde.se import SeField, Renderer
-from serde.core import TO_ITER
+from serde.core import TO_TUPLE
 
 from . import data
 from .data import (
@@ -141,40 +141,40 @@ kwargs = "reuse_instances=reuse_instances, convert_sets=convert_sets"
 
 
 def test_render_primitives() -> None:
-    rendered = Renderer(TO_ITER).render(SeField(int, "i"))
+    rendered = Renderer(TO_TUPLE).render(SeField(int, "i"))
     assert rendered == 'coerce_object("None", "i", int, i)'
 
 
 def test_render_list() -> None:
 
-    rendered = Renderer(TO_ITER).render(SeField(list[int], "l"))
+    rendered = Renderer(TO_TUPLE).render(SeField(list[int], "l"))
     assert rendered == '[coerce_object("None", "v", int, v) for v in l]'
 
-    rendered = Renderer(TO_ITER).render(SeField(list[Foo], "foo"))
-    assert rendered == f"[v.__serde__.funcs['to_iter'](v, {kwargs}) for v in foo]"
+    rendered = Renderer(TO_TUPLE).render(SeField(list[Foo], "foo"))
+    assert rendered == f"[v.__serde__.funcs['to_tuple'](v, {kwargs}) for v in foo]"
 
 
 def test_render_dict() -> None:
-    rendered = Renderer(TO_ITER).render(SeField(dict[str, Foo], "foo"))
+    rendered = Renderer(TO_TUPLE).render(SeField(dict[str, Foo], "foo"))
     rendered_key = 'coerce_object("None", "k", str, k)'
-    rendered_val = f"v.__serde__.funcs['to_iter'](v, {kwargs})"
+    rendered_val = f"v.__serde__.funcs['to_tuple'](v, {kwargs})"
     assert rendered == f"{{{rendered_key}: {rendered_val} for k, v in foo.items()}}"
 
-    rendered = Renderer(TO_ITER).render(SeField(dict[Foo, Foo], "foo"))
-    rendered_key = f"k.__serde__.funcs['to_iter'](k, {kwargs})"
-    rendered_val = f"v.__serde__.funcs['to_iter'](v, {kwargs})"
+    rendered = Renderer(TO_TUPLE).render(SeField(dict[Foo, Foo], "foo"))
+    rendered_key = f"k.__serde__.funcs['to_tuple'](k, {kwargs})"
+    rendered_val = f"v.__serde__.funcs['to_tuple'](v, {kwargs})"
     assert rendered == f"{{{rendered_key}: {rendered_val} for k, v in foo.items()}}"
 
 
 def test_render_tuple() -> None:
-    rendered = Renderer(TO_ITER).render(SeField(tuple[str, Foo, int], "foo"))
+    rendered = Renderer(TO_TUPLE).render(SeField(tuple[str, Foo, int], "foo"))
     rendered_str = 'coerce_object("None", "foo[0]", str, foo[0])'
-    rendered_foo = f"foo[1].__serde__.funcs['to_iter'](foo[1], {kwargs})"
+    rendered_foo = f"foo[1].__serde__.funcs['to_tuple'](foo[1], {kwargs})"
     rendered_int = 'coerce_object("None", "foo[2]", int, foo[2])'
     assert rendered == f"({rendered_str}, {rendered_foo}, {rendered_int},)"
 
 
 def test_render_dataclass() -> None:
-    rendered = Renderer(TO_ITER).render(SeField(Foo, "foo"))
-    rendered_foo = f"foo.__serde__.funcs['to_iter'](foo, {kwargs})"
+    rendered = Renderer(TO_TUPLE).render(SeField(Foo, "foo"))
+    rendered_foo = f"foo.__serde__.funcs['to_tuple'](foo, {kwargs})"
     assert rendered_foo == rendered