diff --git a/benedict/core/remove.py b/benedict/core/remove.py index a92bec73..b034cfb9 100644 --- a/benedict/core/remove.py +++ b/benedict/core/remove.py @@ -6,16 +6,19 @@ from benedict.utils import type_util +def _remove_deep_value(value: Any, keys_list: list[Any]) -> None: + if type_util.is_dict(value): + _remove_deep(value, keys_list) + elif type_util.is_list_or_tuple(value): + for item in value: + _remove_deep_value(item, keys_list) + + def _remove_deep(d: MutableMapping[Any, Any], keys_list: list[Any]) -> None: for key in keys_list: d.pop(key, None) for value in list(d.values()): - if type_util.is_dict(value): - _remove_deep(value, keys_list) - elif type_util.is_list_or_tuple(value): - for item in value: - if type_util.is_dict(item): - _remove_deep(item, keys_list) + _remove_deep_value(value, keys_list) def remove( @@ -30,12 +33,7 @@ def remove( d.pop(key, None) # Then recurse into nested plain dicts (keys are matched literally). for value in list(d.values()): - if type_util.is_dict(value): - _remove_deep(value, keys_list) - elif type_util.is_list_or_tuple(value): - for item in value: - if type_util.is_dict(item): - _remove_deep(item, keys_list) + _remove_deep_value(value, keys_list) else: for key in keys_list: d.pop(key, None) diff --git a/benedict/core/rename.py b/benedict/core/rename.py index 433e8e6e..b4164a7e 100644 --- a/benedict/core/rename.py +++ b/benedict/core/rename.py @@ -7,16 +7,19 @@ _K = TypeVar("_K") +def _rename_deep_value(value: Any, key: _K, key_new: _K) -> None: + if type_util.is_dict(value): + _rename_deep(value, key, key_new) + elif type_util.is_list_or_tuple(value): + for item in value: + _rename_deep_value(item, key, key_new) + + def _rename_deep(d: MutableMapping[_K, Any], key: _K, key_new: _K) -> None: if key in d: move(d, key, key_new, overwrite=False) for value in list(d.values()): - if type_util.is_dict(value): - _rename_deep(value, key, key_new) - elif type_util.is_list_or_tuple(value): - for item in value: - if type_util.is_dict(item): - _rename_deep(item, key, key_new) + _rename_deep_value(value, key, key_new) def rename( @@ -28,11 +31,6 @@ def rename( move(d, key, key_new, overwrite=False) # Then recurse into nested plain dicts (keys are matched literally). for value in list(d.values()): - if type_util.is_dict(value): - _rename_deep(value, key, key_new) - elif type_util.is_list_or_tuple(value): - for item in value: - if type_util.is_dict(item): - _rename_deep(item, key, key_new) + _rename_deep_value(value, key, key_new) else: move(d, key, key_new, overwrite=False) diff --git a/tests/core/test_remove.py b/tests/core/test_remove.py index e549c2c3..04f40ee4 100644 --- a/tests/core/test_remove.py +++ b/tests/core/test_remove.py @@ -168,3 +168,13 @@ def test_remove_deep_inside_tuple_nested_in_dict(self) -> None: }, } self.assertEqual(d, r) + + def test_remove_deep_inside_nested_lists(self) -> None: + d = {"users": [[{"name": "Alice", "password": "abc", "token": "xyz"}]]} + _remove(d, ["password"], "token", deep=True) + self.assertEqual(d, {"users": [[{"name": "Alice"}]]}) + + def test_remove_deep_inside_mixed_nested_sequences(self) -> None: + d = {"users": ([({"name": "Alice", "password": "abc"},)],)} + _remove(d, "password", deep=True) + self.assertEqual(d, {"users": ([({"name": "Alice"},)],)}) diff --git a/tests/core/test_rename.py b/tests/core/test_rename.py index 263e54aa..f4bdddd8 100644 --- a/tests/core/test_rename.py +++ b/tests/core/test_rename.py @@ -176,3 +176,16 @@ def test_rename_deep_inside_tuple_nested_in_dict(self) -> None: }, } self.assertEqual(d, r) + + def test_rename_deep_inside_nested_lists(self) -> None: + d = {"users": [[{"fname": "Alice"}], [42, [{"fname": "Bob"}]]]} + _rename(d, "fname", "first_name", deep=True) + self.assertEqual( + d, + {"users": [[{"first_name": "Alice"}], [42, [{"first_name": "Bob"}]]]}, + ) + + def test_rename_deep_inside_nested_tuples_under_dict(self) -> None: + d = {"section": {"users": ([({"fname": "Alice"},)],)}} + _rename(d, "fname", "first_name", deep=True) + self.assertEqual(d, {"section": {"users": ([({"first_name": "Alice"},)],)}})