Skip to content

Commit

Permalink
Fix parsing of values in lists (#7)
Browse files Browse the repository at this point in the history
  • Loading branch information
BenjaminPelletier authored Mar 30, 2023
1 parent c0efa3e commit b4776a9
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 12 deletions.
15 changes: 7 additions & 8 deletions src/implicitdict/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,14 +159,13 @@ def _parse_value(value, value_type: Type):
# Type is generic
arg_types = get_args(value_type)
if generic_type is list:
if get_origin(arg_types[0]) is list:
return value
elif issubclass(arg_types[0], ImplicitDict):
# value is a list of some kind of ImplicitDict values
return [ImplicitDict.parse(item, arg_types[0]) for item in value]
else:
# value is a list of non-ImplicitDict values
return value
try:
value_list = [v for v in value]
except TypeError as e:
if "not iterable" in str(e):
raise ValueError(f"Cannot parse non-iterable value '{value}' of type '{type(value).__name__}' into list type '{value_type}'")
raise
return [_parse_value(v, arg_types[0]) for v in value_list]

elif generic_type is dict:
# value is a dict of some kind
Expand Down
49 changes: 49 additions & 0 deletions tests/test_containers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
from typing import List, Optional

from implicitdict import ImplicitDict


class MySpecialClass(str):
@property
def is_special(self) -> bool:
return True


class MyContainers(ImplicitDict):
single_value: MySpecialClass
value_list: List[MySpecialClass]
optional_list: Optional[List[MySpecialClass]]
optional_value_list: List[Optional[MySpecialClass]]
list_of_lists: List[List[MySpecialClass]]


def test_container_item_value_casting():
containers: MyContainers = ImplicitDict.parse(
{
"single_value": "foo",
"value_list": ["value1", "value2"],
"optional_list": ["bar"],
"optional_value_list": ["baz", None],
"list_of_lists": [["list1v1", "list1v2"], ["list2v1"]]
}, MyContainers)

assert containers.single_value.is_special

assert len(containers.value_list) == 2
for v in containers.value_list:
assert v.is_special

assert len(containers.optional_list) == 1
assert containers.optional_list[0].is_special

assert len(containers.optional_value_list) == 2
for v in containers.optional_value_list:
assert (v is None) or v.is_special

assert len(containers.list_of_lists) == 2
assert len(containers.list_of_lists[0]) == 2
for v in containers.list_of_lists[0]:
assert v.is_special
assert len(containers.list_of_lists[1]) == 1
for v in containers.list_of_lists[1]:
assert v.is_special
2 changes: 1 addition & 1 deletion tests/test_mutability.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def test_mutability_from_parse():
assert data.primitive != primitive

primitive_list[1] = 'three'
assert data.list_of_primitives[1] == 'three'
assert data.list_of_primitives[1] == 'two' # <-- lists are reconstructed with `parse`

generic_dict['level1'] = 'bar'
assert data.generic_dict['level1'] == 'foo' # <-- dicts are reconstructed with `parse`
Expand Down
6 changes: 3 additions & 3 deletions tests/test_normal_usage.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ def test_nested_structures():
'my_list': [{'foo': 'one'}, {'foo': 'two'}],
'my_list_2': [[1, 2], [3, 4, 5]],
'my_list_3': [[[1, 2, 3], [4, 5]], [[6], [7], [8]], [[9, 10]]],
'my_dict': {'foo': 1.23, 'bar': 4.56}
'my_dict': {'foo': [1.23], 'bar': [4.56]}
}
data: NestedStructures = ImplicitDict.parse(src_dict, NestedStructures)

Expand Down Expand Up @@ -153,5 +153,5 @@ def test_nested_structures():
assert data.my_list_3[2][0][1] == 10

assert len(data.my_dict) == 2
assert data.my_dict['foo'] == 1.23
assert data.my_dict['bar'] == 4.56
assert data.my_dict['foo'] == [1.23]
assert data.my_dict['bar'] == [4.56]

0 comments on commit b4776a9

Please sign in to comment.