wyfo / apischema

JSON (de)serialization, GraphQL and JSON schema generation using Python typing.

Home Page:https://wyfo.github.io/apischema/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

`as_str` deserialization fails if `__init__` has return annotation

kevinheavey opened this issue · comments

Here's a strange one:

If we use as_str on a class where the __init__ method has the return annotation -> None (or any other return annotation, but any other annotation would be wrong), then the deserialize function fails with apischema.visitor.Unsupported.

Minimal example:

from apischema import deserialize
from apischema.conversions import as_str


class StrHolder:
    def __init__(self, val: str) -> None:
        self.val = val

    def __str__(self) -> str:
        return self.val


as_str(StrHolder)

res = deserialize(StrHolder, "foo")

The above fails with apischema.visitor.Unsupported: <class '__main__.StrHolder'>

If we remove the -> None then it works fine:

from apischema import deserialize
from apischema.conversions import as_str


class StrHolder:
    def __init__(self, val: str):
        self.val = val

    def __str__(self) -> str:
        return self.val


as_str(StrHolder)

res = deserialize(StrHolder, "foo")

Omitting the -> None is fine as a workaround; the worst part is that it doesn't make sense and is very had to track down 😅

Indeed, it was strange. To explain briefly, conversions need to extract the source and target types from the converter when they are not provided explicitly. In the case where the converter is a type, it is directly set as the target, and its __init__ (or __new__) method is used to get the type of the argument. However, there was a bug which made __init__ return type override the conversion target, so deserialization conversion was registered for None instead of StrHolder.