From 78634d0165affbde742b1389faaadfe200755e21 Mon Sep 17 00:00:00 2001 From: Johannes Kirschbauer Date: Fri, 19 Sep 2025 17:23:53 +0200 Subject: [PATCH] clan_lib: persist, compute static data for simpler patch validation --- pkgs/clan-cli/clan_lib/persist/static_data.py | 28 ++++ .../clan_lib/persist/static_data_test.py | 144 ++++++++++++++++++ 2 files changed, 172 insertions(+) create mode 100644 pkgs/clan-cli/clan_lib/persist/static_data.py create mode 100644 pkgs/clan-cli/clan_lib/persist/static_data_test.py diff --git a/pkgs/clan-cli/clan_lib/persist/static_data.py b/pkgs/clan-cli/clan_lib/persist/static_data.py new file mode 100644 index 000000000..b9681367f --- /dev/null +++ b/pkgs/clan-cli/clan_lib/persist/static_data.py @@ -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 diff --git a/pkgs/clan-cli/clan_lib/persist/static_data_test.py b/pkgs/clan-cli/clan_lib/persist/static_data_test.py new file mode 100644 index 000000000..f4f9fca97 --- /dev/null +++ b/pkgs/clan-cli/clan_lib/persist/static_data_test.py @@ -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