clan_lib: persist, compute static data for simpler patch validation
This commit is contained in:
28
pkgs/clan-cli/clan_lib/persist/static_data.py
Normal file
28
pkgs/clan-cli/clan_lib/persist/static_data.py
Normal file
@@ -0,0 +1,28 @@
|
||||
from typing import Any
|
||||
|
||||
from clan_lib.persist.util import flatten_data, list_difference
|
||||
|
||||
|
||||
def calculate_static_data(
|
||||
all_values: dict[str, Any], persisted: dict[str, Any]
|
||||
) -> dict[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)
|
||||
static_flat = {}
|
||||
|
||||
for key, value in all_flat.items():
|
||||
if key not in persisted_flat:
|
||||
# This key exists only in static data
|
||||
static_flat[key] = value
|
||||
elif isinstance(value, list) and isinstance(persisted_flat[key], list):
|
||||
# For lists, find items that are only in all_values (static items)
|
||||
static_items = list_difference(value, persisted_flat[key])
|
||||
if static_items:
|
||||
static_flat[key] = static_items
|
||||
|
||||
return static_flat
|
||||
144
pkgs/clan-cli/clan_lib/persist/static_data_test.py
Normal file
144
pkgs/clan-cli/clan_lib/persist/static_data_test.py
Normal file
@@ -0,0 +1,144 @@
|
||||
from clan_lib.persist.static_data import calculate_static_data
|
||||
|
||||
|
||||
def test_calculate_static_data_basic() -> None:
|
||||
all_values = {
|
||||
"name": "example",
|
||||
"version": 1,
|
||||
"settings": {
|
||||
"optionA": True,
|
||||
"optionB": False,
|
||||
"listSetting": [1, 2, 3, 4],
|
||||
},
|
||||
"staticOnly": "staticValue",
|
||||
}
|
||||
persisted = {
|
||||
"name": "example",
|
||||
"version": 1,
|
||||
"settings": {
|
||||
"optionA": True,
|
||||
"listSetting": [2, 3],
|
||||
},
|
||||
}
|
||||
|
||||
expected_static = {
|
||||
"settings.optionB": False,
|
||||
"settings.listSetting": [1, 4],
|
||||
"staticOnly": "staticValue",
|
||||
}
|
||||
|
||||
static_data = calculate_static_data(all_values, persisted)
|
||||
assert static_data == expected_static
|
||||
|
||||
|
||||
def test_calculate_static_data_no_static() -> None:
|
||||
all_values = {
|
||||
"name": "example",
|
||||
"version": 1,
|
||||
"settings": {
|
||||
"optionA": True,
|
||||
"listSetting": [1, 2, 3],
|
||||
},
|
||||
}
|
||||
persisted = {
|
||||
"name": "example",
|
||||
"version": 1,
|
||||
"settings": {
|
||||
"optionA": True,
|
||||
"listSetting": [1, 2, 3],
|
||||
},
|
||||
}
|
||||
|
||||
expected_static: dict = {}
|
||||
|
||||
static_data = calculate_static_data(all_values, persisted)
|
||||
assert static_data == expected_static
|
||||
|
||||
|
||||
def test_calculate_static_data_all_static() -> None:
|
||||
all_values = {
|
||||
"name": "example",
|
||||
"version": 1,
|
||||
"settings": {
|
||||
"optionA": True,
|
||||
"listSetting": [1, 2, 3],
|
||||
},
|
||||
"staticOnly": "staticValue",
|
||||
}
|
||||
persisted: dict = {}
|
||||
|
||||
expected_static = {
|
||||
"name": "example",
|
||||
"version": 1,
|
||||
"settings.optionA": True,
|
||||
"settings.listSetting": [1, 2, 3],
|
||||
"staticOnly": "staticValue",
|
||||
}
|
||||
|
||||
static_data = calculate_static_data(all_values, persisted)
|
||||
assert static_data == expected_static
|
||||
|
||||
|
||||
def test_calculate_static_data_empty_all_values() -> None:
|
||||
# This should never happen in practice, but we test it for completeness.
|
||||
# Maybe this should emit a warning in the future?
|
||||
all_values: dict = {}
|
||||
persisted = {
|
||||
"name": "example",
|
||||
"version": 1,
|
||||
}
|
||||
|
||||
expected_static: dict = {}
|
||||
|
||||
static_data = calculate_static_data(all_values, persisted)
|
||||
assert static_data == expected_static
|
||||
|
||||
|
||||
def test_calculate_nested_dicts() -> None:
|
||||
all_values = {
|
||||
"level1": {
|
||||
"level2": {
|
||||
"staticKey": "staticValue",
|
||||
"persistedKey": "persistedValue",
|
||||
},
|
||||
"anotherStatic": 42,
|
||||
},
|
||||
"topLevelStatic": True,
|
||||
}
|
||||
persisted = {
|
||||
"level1": {
|
||||
"level2": {
|
||||
"persistedKey": "persistedValue",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
expected_static = {
|
||||
"level1.level2.staticKey": "staticValue",
|
||||
"level1.anotherStatic": 42,
|
||||
"topLevelStatic": True,
|
||||
}
|
||||
|
||||
static_data = calculate_static_data(all_values, persisted)
|
||||
assert static_data == expected_static
|
||||
|
||||
|
||||
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": {
|
||||
"foo": "anotherStaticValue",
|
||||
},
|
||||
}
|
||||
persisted: dict = {}
|
||||
|
||||
expected_static = {
|
||||
"key.foo": "anotherStaticValue",
|
||||
}
|
||||
|
||||
static_data = calculate_static_data(all_values, persisted)
|
||||
|
||||
assert static_data == expected_static
|
||||
Reference in New Issue
Block a user