konradhalas / dacite

Simple creation of data classes from dictionaries.
MIT License
1.72k stars 106 forks source link

Dacite will put an `int` into an `Optional[float]` field but not a `float | None` field. #245

Open aquirdTurtle opened 11 months ago

aquirdTurtle commented 11 months ago

Summary Apologies if this is logged somewhere else. Dacite will put an int into an Optional[float] field but not a float | None field. ... To Reproduce

from typing import Optional
from dacite.core import from_dict
from dataclasses import dataclass

@dataclass
class foo:
    bar: Optional[float]

@dataclass
class zen:
    zoo: float | None

print(from_dict(foo, dict(bar=5))) # foo(bar=5)
print(from_dict(zen, dict(zoo=5))) # error

Where the error from the second print statement is

Traceback (most recent call last):
  File "/home/mbrown/code/abraxas/local/t.py", line 51, in <module>
    print(from_dict(zen, dict(zoo=5)))
  File "/home/mbrown/miniconda3/envs/abraxas-env/lib/python3.10/site-packages/dacite/core.py", line 68, in from_dict
    raise WrongTypeError(field_path=field.name, field_type=field.type, value=value)
dacite.exceptions.WrongTypeError: wrong value type for field "zoo" - should be "float | None" instead of value "5" of type "int"

This seems to be because of dacite's implementation of is_instance not being consistent with isinstance

from dacite.typing import is_instance
print(isinstance(5, float | None)) # false
print(isinstance(5, Optional[float])) # false
print(is_instance(5, float | None)) # false
print(is_instance(5, Optional[float])) # true

...

Expected behavior Probably both should fail. But at least they should be consistent. ...

Environment