diff --git a/CHANGELOG.md b/CHANGELOG.md index 124efaa..355a06d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## [0.13.2] - 2024-08-14 + +### Fixed + +- Fix deleting keys from an out-of-order table does not remove all table parts. ([#379](https://github.com/python-poetry/tomlkit/issues/379)) + ## [0.13.1] - 2024-08-14 ### Fixed @@ -414,7 +420,8 @@ - Fixed handling of super tables with different sections. - Fixed raw strings escaping. -[unreleased]: https://github.com/sdispater/tomlkit/compare/0.13.1...master +[unreleased]: https://github.com/sdispater/tomlkit/compare/0.13.2...master +[0.13.2]: https://github.com/sdispater/tomlkit/releases/tag/0.13.2 [0.13.1]: https://github.com/sdispater/tomlkit/releases/tag/0.13.1 [0.13.0]: https://github.com/sdispater/tomlkit/releases/tag/0.13.0 [0.12.5]: https://github.com/sdispater/tomlkit/releases/tag/0.12.5 diff --git a/pyproject.toml b/pyproject.toml index e9d249c..f578226 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "tomlkit" -version = "0.13.1" +version = "0.13.2" description = "Style preserving TOML library" authors = [ "Sébastien Eustace ", diff --git a/tests/test_toml_document.py b/tests/test_toml_document.py index 9331478..ae18ff1 100644 --- a/tests/test_toml_document.py +++ b/tests/test_toml_document.py @@ -1109,3 +1109,81 @@ def test_item_preserves_the_order(): age = 42 """ assert tomlkit.dumps(doc) == expected + + +def test_delete_out_of_order_table_key(): + content = """\ +[foo] +name = "foo" + +[bar.a.b] +name = "bar-a-b" + +[foo.a] +name = "foo-a" + +[bar.a] +name = "bar-a" + +[baz] +name = "baz" + +[bar.a.c] +name = "bar-a-c" +""" + doc = parse(content) + del doc["bar"]["a"] + assert ( + doc.as_string() + == """\ +[foo] +name = "foo" + +[foo.a] +name = "foo-a" + +[baz] +name = "baz" + +""" + ) + + +def test_overwrite_out_of_order_table_key(): + content = """\ +[foo] +name = "foo" + +[bar.a.b] +name = "bar-a-b" + +[foo.a] +name = "foo-a" + +[bar.a] +name = "bar-a" + +[baz] +name = "baz" + +[bar.a.c] +name = "bar-a-c" +""" + doc = parse(content) + doc["bar"]["a"] = {"name": "bar-a-updated"} + assert ( + doc.as_string() + == """\ +[foo] +name = "foo" + +[bar.a] +name = "bar-a-updated" +[foo.a] +name = "foo-a" + +[baz] +name = "baz" + +""" + ) diff --git a/tomlkit/__init__.py b/tomlkit/__init__.py index b5b6773..fbbab82 100644 --- a/tomlkit/__init__.py +++ b/tomlkit/__init__.py @@ -27,7 +27,7 @@ from tomlkit.api import ws -__version__ = "0.13.1" +__version__ = "0.13.2" __all__ = [ "aot", "array", diff --git a/tomlkit/container.py b/tomlkit/container.py index da4f2db..7890880 100644 --- a/tomlkit/container.py +++ b/tomlkit/container.py @@ -814,7 +814,7 @@ def __init__(self, container: Container, indices: tuple[int, ...]) -> None: table_idx = len(self._tables) - 1 for k, v in item.value.body: self._internal_container._raw_append(k, v) - self._tables_map[k] = table_idx + self._tables_map.setdefault(k, []).append(table_idx) if k is not None: dict.__setitem__(self, k.key, v) @@ -835,8 +835,12 @@ def __getitem__(self, key: Key | str) -> Any: def __setitem__(self, key: Key | str, item: Any) -> None: if key in self._tables_map: - table = self._tables[self._tables_map[key]] - table[key] = item + # Overwrite the first table and remove others + indices = self._tables_map[key] + while len(indices) > 1: + table = self._tables[indices.pop()] + self._remove_table(table) + self._tables[indices[0]][key] = item elif self._tables: table = self._tables[0] table[key] = item @@ -856,15 +860,16 @@ def _remove_table(self, table: Table) -> None: break def __delitem__(self, key: Key | str) -> None: - if key in self._tables_map: - table = self._tables[self._tables_map[key]] + if key not in self._tables_map: + raise NonExistentKey(key) + + for i in reversed(self._tables_map[key]): + table = self._tables[i] del table[key] if not table and len(self._tables) > 1: self._remove_table(table) - del self._tables_map[key] - else: - raise NonExistentKey(key) + del self._tables_map[key] del self._internal_container[key] if key is not None: dict.__delitem__(self, key)