Open antonagestam opened 4 years ago
Hi @antonagestam - it sounds like a reasonable feature. I will be more than happy to receive PR :)
@konradhalas Awesome, unfortunately it's not likely that I'll have time to spend on this anytime soon, just in case anyone else wants to work on this in the meanwhile.
@antonagestam sure, I will add it to my roadmap :)
Hello,
I'd also like to see this feature in some near future. In v1.7.0. this could be potentially implemented with the following change:
index 6971f11..e2f5a2b 100644
--- a/dacite/types.py
+++ b/dacite/types.py
@@ -1,4 +1,5 @@
from dataclasses import InitVar
+from enum import Enum
from typing import (
Type,
Any,
@@ -12,6 +13,7 @@ from typing import (
List,
Tuple,
cast as typing_cast,
+ get_args,
)
T = TypeVar("T", bound=Any)
@@ -49,6 +51,11 @@ def transform_value(
)
item_cls = extract_generic(target_type, defaults=(Any,))[0]
return collection_cls(transform_value(type_hooks, cast, item_cls, item) for item in value)
+ if is_literal(target_type):
+ for literal_arg in get_args(target_type):
+ for cast_type in cast:
+ if isinstance(literal_arg, Enum) and isinstance(literal_arg, cast_type):
+ value = cast_type(value)
return value
If you think it's fine, I can submit a PR with few tests.
I had to implement this as type hooks. It would be great if this could be supported natively and @miknet's proposal looks pretty good.
Has there been any progress on this feature?
For anyone else who needs this in the meantime, here's an example of how to do it with type_hooks like @emosenkis mentioned.
from dataclasses import dataclass
import enum
from typing import Literal
import dacite
class ContactType(enum.Enum):
member = "Member"
contact = "Contact"
@dataclass
class Contact:
contactType: ContactType
LiteralContactMember = Literal[ContactType.member]
@dataclass
class Member(Contact):
contactType: LiteralContactMember
def transform_literal(v):
if ContactType(v) != ContactType.member:
raise ValueError(f'Invalid ContactType "{v}" supplied for {LiteralContactMember}')
return v
config = dacite.Config(
check_types=False,
type_hooks={LiteralContactMember: transform_literal},
)
I ran into a case where I'm modeling API responses like this, simplified:
dacite enables me to make sure that objects returned from a certain endpoint are
Member
s and not anyContact
, by looking at the contactType field. Now, I'm finding myself also wanting to use the"Member"
and"Contact"
strings in a few other places and so it would be nice to introduce an enum for them. Literals support enum values, so these would be valid models as well:However, dacite doesn't currently recognize that the literal contains an enum value and won't try to cast string values to their enum equivalents. I realize that this might be a pretty complicated thing to ask for, but it would be nice to see this implemented. If you think this is a behavior that makes sense I'd be willing to give a shot at implementing this.
To clarify, the feature would be to try and apply matching classes from
cast=[...]
in the config.