clan_lib: use flatten_data_structured
This commit is contained in:
@@ -3,10 +3,21 @@ from typing import Any
|
||||
from clan_lib.persist.util import flatten_data, list_difference
|
||||
|
||||
|
||||
def flatten_data_structured(data: dict, parent_path: tuple = ()) -> dict:
|
||||
"""Flatten using tuple keys instead of string concatenation
|
||||
def flatten_data_structured(data: dict, parent_path: tuple = ()) -> dict[tuple[str, ...], Any]:
|
||||
"""Flatten data using tuple keys instead of string concatenation.
|
||||
This eliminates ambiguity between literal dots in keys vs nested structure.
|
||||
|
||||
Avoids ambiguity issues with keys that contain dots or other separators.
|
||||
Args:
|
||||
data: The nested dictionary to flatten
|
||||
parent_path: Current path as tuple (used for recursion)
|
||||
|
||||
Returns:
|
||||
Dict with tuple keys representing the full path to each value
|
||||
|
||||
Example:
|
||||
{"key.foo": "val1", "key": {"foo": "val2"}}
|
||||
becomes:
|
||||
{("key.foo",): "val1", ("key", "foo"): "val2"}
|
||||
|
||||
"""
|
||||
flattened = {}
|
||||
@@ -25,14 +36,14 @@ def flatten_data_structured(data: dict, parent_path: tuple = ()) -> dict:
|
||||
|
||||
def calculate_static_data(
|
||||
all_values: dict[str, Any], persisted: dict[str, Any]
|
||||
) -> dict[str, Any]:
|
||||
) -> dict[tuple[str, ...], Any]:
|
||||
"""Calculate the static (read-only) data by finding what exists in all_values
|
||||
but not in persisted data.
|
||||
|
||||
This gives us a clear view of what cannot be modified/deleted.
|
||||
"""
|
||||
all_flat = flatten_data(all_values)
|
||||
persisted_flat = flatten_data(persisted)
|
||||
all_flat = flatten_data_structured(all_values)
|
||||
persisted_flat = flatten_data_structured(persisted)
|
||||
static_flat = {}
|
||||
|
||||
for key, value in all_flat.items():
|
||||
|
||||
@@ -86,9 +86,9 @@ def test_calculate_static_data_basic() -> None:
|
||||
}
|
||||
|
||||
expected_static = {
|
||||
"settings.optionB": False,
|
||||
"settings.listSetting": [1, 4],
|
||||
"staticOnly": "staticValue",
|
||||
("settings", "optionB"): False,
|
||||
("settings","listSetting"): [1, 4],
|
||||
("staticOnly",): "staticValue"
|
||||
}
|
||||
|
||||
static_data = calculate_static_data(all_values, persisted)
|
||||
@@ -132,11 +132,11 @@ def test_calculate_static_data_all_static() -> None:
|
||||
persisted: dict = {}
|
||||
|
||||
expected_static = {
|
||||
"name": "example",
|
||||
"version": 1,
|
||||
"settings.optionA": True,
|
||||
"settings.listSetting": [1, 2, 3],
|
||||
"staticOnly": "staticValue",
|
||||
("name",): "example",
|
||||
("version",): 1,
|
||||
("settings", "optionA"): True,
|
||||
("settings", "listSetting"): [1, 2, 3],
|
||||
("staticOnly",): "staticValue",
|
||||
}
|
||||
|
||||
static_data = calculate_static_data(all_values, persisted)
|
||||
@@ -178,9 +178,9 @@ def test_calculate_nested_dicts() -> None:
|
||||
}
|
||||
|
||||
expected_static = {
|
||||
"level1.level2.staticKey": "staticValue",
|
||||
"level1.anotherStatic": 42,
|
||||
"topLevelStatic": True,
|
||||
("level1", "level2", "staticKey"): "staticValue",
|
||||
("level1", "anotherStatic"): 42,
|
||||
("topLevelStatic",): True,
|
||||
}
|
||||
|
||||
static_data = calculate_static_data(all_values, persisted)
|
||||
@@ -188,9 +188,6 @@ def test_calculate_nested_dicts() -> None:
|
||||
|
||||
|
||||
def test_dot_in_keys() -> None:
|
||||
# TODO: This is a bug in the current implementation.
|
||||
# We need to change the key representation to handle this case correctly.
|
||||
# For now, we just document the behavior with this test.
|
||||
all_values = {
|
||||
"key.foo": "staticValue",
|
||||
"key": {
|
||||
@@ -200,7 +197,8 @@ def test_dot_in_keys() -> None:
|
||||
persisted: dict = {}
|
||||
|
||||
expected_static = {
|
||||
"key.foo": "anotherStaticValue",
|
||||
("key.foo",): "staticValue",
|
||||
("key", "foo"): "anotherStaticValue",
|
||||
}
|
||||
|
||||
static_data = calculate_static_data(all_values, persisted)
|
||||
|
||||
Reference in New Issue
Block a user