Skip to content

Allow structuring union types of primitives that don't need any conversion #278

@phiresky

Description

@phiresky
  • cattrs version: current master
  • Python version: 3.10
  • Operating System: Linux
  • Let me know when you get annoyed by my issues ;)

Description

cattrs supports passing through primitives as well as the type Literal["foo", "bar"]

I have three examples of types that cattrs currently does not support:

  • Union[int, typing.Literal["foo"]]
  • Union[Literal["a", "b"], Literal["c", "d"]]
  • T2 = NewType("T2", str) then Literal["train", "test"] | T2)

I think cattrs should pass through all forms of combinations of primitives, literals, and primitive newtypes.

Here's an implementation that works for me:

def is_primitive_or_primitive_union(t: Any) -> bool:
    """returns true if given type is something that doesn't need ser/deser"""
    if t in (str, bytes, int, float, bool):
        return True
    origin = typing.get_origin(t)
    if origin is typing.Literal:
        return True
    if (basetype := cattrs._compat.get_newtype_base(t)) is not None:
        return is_primitive_or_primitive_union(basetype)
    if origin in (types.UnionType, typing.Union):
        return all(is_primitive_or_primitive_union(ty) for ty in typing.get_args(t))



[...]

 _converter.register_structure_hook_func(
    is_primitive_or_primitive_union, lambda v, ty: v
)


if __name__ == "__main__":
    T2 = NewType("T2", str)
    print(is_primitive_or_primitive_union(Union[int, typing.Literal["silu"]]))
    print(is_primitive_or_primitive_union(Union[Literal["a", "b"], Literal["c", "d"]]))
    print(is_primitive_or_primitive_union(Literal["train", "val", "test"] | T2))

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions