`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
.