Skip to content

Incorrect _build_value_for_collection for non-dict, tuple or list data #292

@francois-rozet

Description

@francois-rozet

When the data type is a collection but not a dict, tuple or list, _build_value_for_collection breaks either silently or loudly. For example,

from typing import Mapping
from dacite.core import _build_value_for_collection

class MyMap(Mapping):
    def __init__(self, length):
        self.length = int(length)
    def __getitem__(self, key):
        return key**2
    def __iter__(self):
        return iter(range(self.length))
    def __len__(self):
        return self.length

# raises TypeError: int() argument ...
_build_value_for_collection(dict[int, int], MyMap(3), None)
from dacite.core import _build_value_for_collection

# returns a string '<generator object _build_value_for_collection.<locals>.<genexpr> at 0x10507e440>'
_build_value_for_collection(list[str], "ab", None)

The issue is caused by the loose data type check clauses here

dacite/dacite/core.py

Lines 146 to 162 in 9898ccb

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):
item_type = extract_generic(collection, defaults=(Any, Any))[1]
return data_type((key, _build_value(type_=item_type, data=value, config=config)) for key, value in data.items())
elif 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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions