practically all of my dataclasses use "init=False" in their definitions, e.g.:
@dataclass(init=False)
class MyClass:
id: str
timestamp: str
event_type: int
This works nicely except that dacite.core.from_dict does not honour the "init=False" flag and invokes create_instance with fields in init_values alone.
Whether a field should become part of the init_values depends on the field's "init" attribute only. If it is True, the field is part of the initial ones, otherwise it is part of post init values.
Just to serve as a reminder, here is dacite.dataclasses.create_instance:
def create_instance(data_class: Type[T], init_values: Data, post_init_values: Data) -> T:
instance = data_class(**init_values)
for key, value in post_init_values.items():
setattr(instance, key, value)
return instance
If a dataclass uses init=False but individual fields do not, that results in an exception:
instance = data_class(**init_values)
TypeError: object() takes no parameters
The exception makes sense because there is no __init__ defined for the class so it is object's __init__ that is called above. Hence the exception.
My point is that if there is a class-level init=False then the logic in from_dict should take it into account. That is, with that flag set to False, all of the fields should go to post_init_values. In this way, create_instance, will not attempt to invoke a missing __init__ method.
The implementation of it can be very simple. At the top of from_dict, add:
is_class_init_false = data_class.__dataclass_params__.init is False
Then, at the below, right before create_instance is called, add this (or a variation thereof if you prefer shorter and less explicit branches):
if is_class_init_false:
post_init_values[field.name] = value
else:
if field.init:
init_values[field.name] = value
else:
post_init_values[field.name] = value
I will not have time to submit a PR. I am leaving the code here for someone else to do it.
Good day,
I am using dacite 1.6.0.
practically all of my dataclasses use "init=False" in their definitions, e.g.:
This works nicely except that dacite.core.from_dict does not honour the "init=False" flag and invokes create_instance with fields in init_values alone.
Whether a field should become part of the init_values depends on the field's "init" attribute only. If it is True, the field is part of the initial ones, otherwise it is part of post init values.
Just to serve as a reminder, here is dacite.dataclasses.create_instance:
If a dataclass uses init=False but individual fields do not, that results in an exception:
The exception makes sense because there is no
__init__
defined for the class so it is object's__init__
that is called above. Hence the exception.My point is that if there is a class-level init=False then the logic in from_dict should take it into account. That is, with that flag set to False, all of the fields should go to post_init_values. In this way, create_instance, will not attempt to invoke a missing
__init__
method.The implementation of it can be very simple. At the top of from_dict, add:
Then, at the below, right before create_instance is called, add this (or a variation thereof if you prefer shorter and less explicit branches):
I will not have time to submit a PR. I am leaving the code here for someone else to do it.
Regards.