Skip to content

Commit 55d0768

Browse files
authored
fix: preserve siblings when updating out-of-order tables (#677)
Replace only the repeated key in later fragments, retaining unrelated sibling entries. Add regression coverage for table, AoT and scalar replacements in both update orders, with and without a prior pop. Fixes #675.
1 parent 3cc03fe commit 55d0768

2 files changed

Lines changed: 26 additions & 2 deletions

File tree

‎tests/test_toml_document.py‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1764,6 +1764,28 @@ def test_delete_key_from_out_of_order_table() -> None:
17641764
)
17651765

17661766

1767+
@pytest.mark.parametrize("replacement", [{"z": 1}, [{"z": 1}], 1])
1768+
@pytest.mark.parametrize("remove_subtable", [False, True])
1769+
@pytest.mark.parametrize("sibling_first", [False, True])
1770+
def test_update_out_of_order_table_preserves_siblings(
1771+
replacement: Any, remove_subtable: bool, sibling_first: bool
1772+
) -> None:
1773+
doc = parse("[y.y.b]\nc = 1\n[y]\nd = 1\n[y.b]\ne = 2\n[y.y]\n")
1774+
if remove_subtable:
1775+
doc["y"]["y"].pop("b")
1776+
1777+
table = doc["y"]
1778+
updates = {"y": replacement, "b": {"e": -0.5}}
1779+
if sibling_first:
1780+
updates = dict(reversed(updates.items()))
1781+
table.update(updates)
1782+
1783+
expected = {"y": {"y": replacement, "d": 1, "b": {"e": -0.5}}}
1784+
assert table.unwrap() == expected["y"]
1785+
assert doc.unwrap() == expected
1786+
assert parse(doc.as_string()).unwrap() == expected
1787+
1788+
17671789
def test_parse_aot_without_ending_newline() -> None:
17681790
content = '''\
17691791
[[products]]

‎tomlkit/container.py‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1223,11 +1223,13 @@ def _is_table_or_aot(it: Any) -> bool:
12231223
_key: Key = key if isinstance(key, Key) else SingleKey(key)
12241224

12251225
if _key in self._tables_map:
1226-
# Overwrite the first table and remove others
1226+
# Overwrite the first occurrence and remove this key from later parts.
12271227
map_indices = self._tables_map[_key]
12281228
while len(map_indices) > 1:
12291229
table = self._tables[map_indices.pop()]
1230-
self._remove_table(table)
1230+
del table[key]
1231+
if not table:
1232+
self._remove_table(table)
12311233
old_value = self._tables[map_indices[0]][key]
12321234
if _is_table_or_aot(old_value) and not _is_table_or_aot(value):
12331235
# Remove the entry from the map and set value again.

0 commit comments

Comments
 (0)