Skip to content

Dictionary matching errors with object type key #252

@ali-raza-zaidi

Description

@ali-raza-zaidi

Describe the bug
When trying to deserialize a dictionary into a dataclass, if the class structure includes a dictionary with its key being an object, then a WrongTypeError exception is raised.

To Reproduce

from dataclasses import dataclass
from dacite import Config, from_dict
from bson import ObjectId


@dataclass
class NiceObj:
    a: str
    b: str


@dataclass
class Foo:
    d: dict[ObjectId, NiceObj]


tc = from_dict(Foo, {'d': {'4142434445464748494a4b4c': {"a": "1", "b": "2"}}}, config=Config(cast=[ObjectId]))

print(tc)

Expected behavior
In Dacite 1.7.0, this correctly gives the output

Foo(d={ObjectId('4142434445464748494a4b4c'): NiceObj(a='1', b='2')})

but in v1.8.0+ it outputs the following error

dacite.exceptions.WrongTypeError: wrong value type for field "d" - should be "dict" instead of value "{'4142434445464748494a4b4c': NiceObj(a='1', b='2')}" of type "dict"

Environment

  • Python version: 3.11.4
  • dacite version: 1.8.0

Additional context

def _build_value_for_collection(collection: Type, data: Any, config: Config) -> Any:
    data_type = data.__class__
    if isinstance(data, Mapping) and is_subclass(collection, Mapping):
        key_type, item_type = extract_generic(collection, defaults=(Any, Any))
        return data_type(
            (_build_value(type_=key_type, data=key, config=config), # Modified this line
             _build_value(type_=item_type, data=value, config=config))
            for key, value in data.items())
    elif isinstance(data, tuple) and is_subclass(collection, tuple):
        if not data:
            return data_type()
        types = extract_generic(collection)
        if len(types) == 2 and types[1] == Ellipsis:
            return data_type(_build_value(type_=types[0], data=item, config=config) for item in data)
        return data_type(
            _build_value(type_=type_, data=item, config=config) for item, type_ in zip_longest(data, types)
        )
    elif isinstance(data, Collection) and is_subclass(collection, Collection):
        item_type = extract_generic(collection, defaults=(Any,))[0]
        return data_type(_build_value(type_=item_type, data=item, config=config) for item in data)
    return data

helped. I essentially added a line to recursive build the key in addition to the value that was already being done in the isinstance(data, Mapping) and is_subclass(collection, Mapping) condition. This was also noted in #217 (comment)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions