Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions benedict/core/flatten.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
from __future__ import annotations

from collections.abc import Mapping
from typing import Any

from benedict.core.clone import clone


def _flatten_key(base_key: str, key: str, separator: str) -> str:
if base_key and separator:
def _flatten_key(base_key: str | None, key: str, separator: str) -> str:
if base_key is not None and separator:
return f"{base_key}{separator}{key}"
return key

Expand Down Expand Up @@ -49,7 +51,7 @@ def _flatten_list(
def _flatten_item(
d: Any,
base_dict: Any,
base_key: str,
base_key: str | None,
separator: str,
indexes: bool = False,
) -> Any:
Expand Down Expand Up @@ -87,7 +89,7 @@ def flatten(d: Any, separator: str = "_", indexes: bool = False) -> Any:
# collect items in a plain dict, flattened keys (eg. "a[0]")
# must not be parsed as keypaths by benedict instances
items = _flatten_item(
d, base_dict={}, base_key="", separator=separator, indexes=indexes
d, base_dict={}, base_key=None, separator=separator, indexes=indexes
)
new_dict = clone(d, empty=True)
new_dict.update(items)
Expand Down
4 changes: 2 additions & 2 deletions tests/core/test_flatten.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def test_flatten(self) -> None:
self.assertEqual(o, r)

def test_flatten_with_falsy_parent_keys(self) -> None:
for key in (0, False, None):
for key in (0, False, None, ""):
for separator in ("_", "/"):
for indexes in (False, True):
with self.subTest(key=key, separator=separator, indexes=indexes):
Expand All @@ -45,7 +45,7 @@ def test_flatten_with_falsy_parent_keys(self) -> None:
self.assertEqual(data, {key: {"child": 1}, "child": 2})

def test_flatten_with_falsy_parent_keys_and_indexed_lists(self) -> None:
for key in (0, False, None):
for key in (0, False, None, ""):
with self.subTest(key=key):
self.assertEqual(
_flatten({key: {"items": [{"value": 1}]}}, indexes=True),
Expand Down
22 changes: 21 additions & 1 deletion tests/dicts/test_benedict.py
Original file line number Diff line number Diff line change
Expand Up @@ -524,14 +524,34 @@ def test_flatten(self) -> None:
self.assertTrue(isinstance(f, benedict))

def test_flatten_with_falsy_parent_keys(self) -> None:
for key in (0, False, None):
for key in (0, False, None, ""):
with self.subTest(key=key):
source = benedict({key: {"child": 1}, "child": 2})
result = source.flatten()
self.assertEqual(result, {f"{key}_child": 1, "child": 2})
self.assertIsInstance(result, benedict)
self.assertEqual(source, {key: {"child": 1}, "child": 2})

def test_flatten_empty_parent_keys_round_trip(self) -> None:
for separator in ("_", "/"):
with self.subTest(separator=separator):
data = {"": {"": 1, "items": [{"value": 2}]}, "value": 3}
source = benedict(data)
result = source.flatten(separator=separator, indexes=True)
self.assertEqual(
result,
{
separator: 1,
f"{separator}items[0]{separator}value": 2,
"value": 3,
},
)
self.assertIsInstance(result, benedict)
self.assertEqual(result.unflatten(separator=separator), data)
self.assertEqual(
data, {"": {"": 1, "items": [{"value": 2}]}, "value": 3}
)

def test_flatten_with_custom_keypath_separator(self) -> None:
d = {
"a": 1,
Expand Down