Skip to content

Commit

Permalink
Ensure nested list is created when inserting '.0'
Browse files Browse the repository at this point in the history
Fixes issue #8
  • Loading branch information
jsbueno committed Sep 18, 2024
1 parent f6c6168 commit 51fd981
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 7 deletions.
34 changes: 27 additions & 7 deletions extradict/nested_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ def merge(self, data, path=""):
def __setitem__(self, key: str, value: T.Any):
return self._setitem(key, self.unwrap(value), merging=False)

def _setitem(self, key: str, value: T.Any, merging: bool):
def _setitem(self, key: str, value: T.Any, merging: bool=False):
# cyclomatic complexity is my bitch
if isinstance(value, (_NestedDict, _NestedList)):
value = value.data
Expand All @@ -162,7 +162,15 @@ def _setitem(self, key: str, value: T.Any, merging: bool):

if key not in self.data:
if subpath:
self.data[key] = {}
prefix_subpath, postfix_subpath = self._get_next_component(subpath)
self.data[key] = [] if prefix_subpath == "0" else {}
#if :
#self.data[key] = []
#if postfix_subpath is not None:
#value = NestedData({postfix_subpath: value})
#self.data[key].append(value)
#else:
#self.data[key] = {}
self[key]._setitem(subpath, value, merging)
else:
if isinstance(value, Mapping) and _should_be_a_sequence(value):
Expand All @@ -180,7 +188,7 @@ def _setitem(self, key: str, value: T.Any, merging: bool):
else:
self[key] = {}
if not merging:
self[key][subpath] = value
self[key]._setitem(subpath, value, merging)
return
if isinstance(self[key], Sequence):
self[key].merge(value, subpath)
Expand Down Expand Up @@ -274,7 +282,7 @@ def __getitem__(self, index):
return wrapped[subpath]
return wrapped

def __setitem__(self, index, item):
def __setitem__(self, index, item, allow_growing=False):
if isinstance(index, slice):
self.data[index] = item
return
Expand All @@ -289,12 +297,19 @@ def __setitem__(self, index, item):
else:
self[i] = item
return
index = int(index)
if allow_growing and index == len(self.data):
next_comp = {}
prefix_subpath, _ = self._get_next_component(subpath)
if prefix_subpath == "0":
next_comp = []
self.append(next_comp)
if subpath is None:
self.data[int(index)] = (
self.data[index] = (
item if not isinstance(item, NestedData) else item.data
)
else:
self.wrap(self[index])[subpath] = item
self.wrap(self[index])._setitem(subpath, item)

def __delitem__(self, index):
if isinstance(index, slice):
Expand All @@ -317,6 +332,11 @@ def insert(self, index, item):
int(index), item if not isinstance(item, NestedData) else item.data
)

def _setitem(self, index, value, merging=False):
# provides simmetry to _NestedDict, so that some codepaths
# can be simplified
return self.__setitem__(index, value, allow_growing=True)

def merge(self, data, path=None):
data = self.unwrap(data)
if path in (None, ""):
Expand Down Expand Up @@ -410,7 +430,7 @@ class NestedData(ABC):
The first tool available is the ability to merge mappings with extra keys
into existing nested mappings, without deleting non colidng keys:
into existing nested mappings, without deleting non coliding keys:
a "person.address" key that would contain "city" but no "street" or "zip-code"
can be updated with: `record["person"].merge({"address": {"street": "5th ave", "zip-code": "000000"}})`
preserving the "person.address.city" value in the process.
Expand Down
33 changes: 33 additions & 0 deletions tests/test_nested_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -439,3 +439,36 @@ def test_nested_data_can_handle_path_components_as_tuples_3():
a["person", "address"].append("test")
assert a["person", "address", "0"]
assert a["person", "address", 0]


def test_nested_data_inserting_composite_key_with_0_should_create_list():
# as of 0.7b1 this is creating a dictionary with a "0" string as Key
# check issue #8
a = NestedData()
a["list.0"] = 23
assert a.data == {"list": [23]}
a = NestedData({"list.0": 1, "list.1": 2})
assert a.data == {"list": [1, 2]}


def test_nested_data_inserting_intermediate_composite_key_with_0_should_create_list():
# as of 0.7b1 this is creating a dictionary with a "0" string as Key
# check issue #8
a = NestedData()
a["list.0.test"] = 23
assert a.data == {"list": [{"test": 23}]}

def test_nested_data_inserting_intermediate_composite_keys_with_consecutive_0_should_create_lists():
# as of 0.7b1 this is creating a dictionary with a "0" string as Key
# check issue #8
a = NestedData()
a["list.0.0.test"] = 23
assert a.data == {"list": [[{"test": 23}]]}

def test_nested_data_inserting_composite_key_with_1_should_create_dict():
# as of 0.7b1 this is creating a dictionary with a "0" string as Key
# check issue #8
a = NestedData()
a["list.1"] = 42
assert a.data == {"list": {"1": 42}}

0 comments on commit 51fd981

Please sign in to comment.