diff --git a/newsfragments/2867.bugfix.rst b/newsfragments/2867.bugfix.rst new file mode 100644 index 0000000000..88444738e7 --- /dev/null +++ b/newsfragments/2867.bugfix.rst @@ -0,0 +1 @@ +fix dict_to_namedtuple unable to handle empty dict as input diff --git a/tests/core/utilities/test_abi.py b/tests/core/utilities/test_abi.py index 3df9d04888..35f7cc47ee 100644 --- a/tests/core/utilities/test_abi.py +++ b/tests/core/utilities/test_abi.py @@ -10,6 +10,7 @@ get_aligned_abi_inputs, get_tuple_type_str_parts, map_abi_data, + recursive_dict_to_namedtuple, ) from web3._utils.normalizers import ( BASE_RETURN_NORMALIZERS, @@ -357,3 +358,27 @@ def test_map_abi_data(types, data, funcs, expected): def test_exact_length_bytes_encoder_raises_on_non_multiples_of_8_bit_size(arg): with pytest.raises(ValueError, match="multiple of 8"): _ = ExactLengthBytesEncoder(None, data_byte_size=2, value_bit_size=arg) + + +@pytest.mark.parametrize( + "input, expected_output", + [ + ({"a": 1, "b": 2}, "ABIDecodedNamedTuple(a=1, b=2)"), + ({"a": 0}, "ABIDecodedNamedTuple(a=0)"), + ({"a": None}, "ABIDecodedNamedTuple(a=None)"), + ({"a": False}, "ABIDecodedNamedTuple(a=False)"), + ({}, "ABIDecodedNamedTuple()"), + ({"a": {}}, "ABIDecodedNamedTuple(a=ABIDecodedNamedTuple())"), + ({"a": []}, "ABIDecodedNamedTuple(a=[])"), + ({"a": [0]}, "ABIDecodedNamedTuple(a=[0])"), + ({"a": [{}]}, "ABIDecodedNamedTuple(a=[ABIDecodedNamedTuple()])"), + ( + {"a": {"b": {}}}, + "ABIDecodedNamedTuple(a=ABIDecodedNamedTuple(b=ABIDecodedNamedTuple()))", + ), + ], +) +def test_recursive_dict_to_namedtuple(input, expected_output): + named_tuple_output = recursive_dict_to_namedtuple(input) + output_repr = named_tuple_output.__repr__() + assert output_repr == expected_output diff --git a/web3/_utils/abi.py b/web3/_utils/abi.py index 22687de849..d1bb479c80 100644 --- a/web3/_utils/abi.py +++ b/web3/_utils/abi.py @@ -957,7 +957,7 @@ def _dict_to_namedtuple( if not isinstance(value, dict): return value - keys, values = zip(*value.items()) + keys, values = zip(*value.items()) if value else ((), ()) return abi_decoded_namedtuple_factory(keys)(values) return recursive_map(_dict_to_namedtuple, data)