From 034ddddd8e7421fd6614fd2bd7a7fdcbfb375b58 Mon Sep 17 00:00:00 2001 From: MildlyMeticulous <302576729+MildlyMeticulous@users.noreply.github.com> Date: Thu, 30 Jul 2026 09:55:21 +0100 Subject: [PATCH] fix: deleting a key added before a table leaves a blank line behind --- tests/test_toml_document.py | 38 +++++++++++++++++++++++++++++++++++++ tomlkit/container.py | 18 +++++++++++++++++- 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/tests/test_toml_document.py b/tests/test_toml_document.py index 7ba61f5..2497105 100644 --- a/tests/test_toml_document.py +++ b/tests/test_toml_document.py @@ -361,6 +361,44 @@ def test_inserting_after_deletion() -> None: assert expected == doc.as_string() +def test_deleting_key_added_before_a_table_restores_the_document() -> None: + content = """[a] +x = 1 +""" + + doc = parse(content) + doc["foo"] = 10 + + assert ( + doc.as_string() + == """foo = 10 + +[a] +x = 1 +""" + ) + + del doc["foo"] + + assert doc.as_string() == content + + +def test_adding_keys_before_a_table_separates_them_from_it_once() -> None: + doc = parse("[a]\nx = 1\n") + doc["foo"] = 10 + doc["bar"] = 11 + + assert ( + doc.as_string() + == """foo = 10 +bar = 11 + +[a] +x = 1 +""" + ) + + def test_toml_document_with_dotted_keys_inside_table( example: Callable[[str], str], ) -> None: diff --git a/tomlkit/container.py b/tomlkit/container.py index 8ff30d9..413b4ba 100644 --- a/tomlkit/container.py +++ b/tomlkit/container.py @@ -150,6 +150,16 @@ def _handle_dotted_key(self, key: Key, value: Item) -> None: self.append(name, table) return + def _trail_table_separator_on(self, item: Item, before_index: int) -> None: + if before_index > 0: + previous = self._body[before_index - 1][1] + if not isinstance(previous, Whitespace) and previous.trivia.trail.endswith( + "\n\n" + ): + previous.trivia.trail = previous.trivia.trail[:-1] + + item.trivia.trail += "\n" + def _get_last_index_before_table(self) -> int: last_index = -1 for i, (k, v) in enumerate(self._body): @@ -388,7 +398,13 @@ def append( if last_index < len(self._body): after_item = self._body[last_index][1] - if not ( + if ( + not is_table + and isinstance(after_item, Table) + and "\n" not in after_item.trivia.indent + ): + self._trail_table_separator_on(item, before_index=last_index) + elif not ( isinstance(after_item, Whitespace) or "\n" in after_item.trivia.indent ):