From b92e9b7449e2b12007306a3cb693084602dd1e88 Mon Sep 17 00:00:00 2001 From: Vincent Gao Date: Fri, 19 Jun 2026 14:21:42 +0200 Subject: [PATCH] fix: reject tables inside inline tables --- CHANGELOG.md | 1 + tests/test_items.py | 11 +++++++++++ tomlkit/items.py | 9 +++++++++ 3 files changed, 21 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 26584a1c..2aa94a01 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ - Fix `comment()` producing invalid TOML for a multiline string by prefixing every line with `#`, not just the first. ([#449](https://github.com/python-poetry/tomlkit/issues/449)) - Fix the separator comma being swallowed by a trailing comment when appending a key to a multiline inline table, leaving the new key without a separator so the result no longer round-trips. ([#512](https://github.com/python-poetry/tomlkit/issues/512)) - Fix a `KeyAlreadyPresent` error when parsing or accessing an out-of-order table whose array-of-tables elements are split across the table's parts. ([#505](https://github.com/python-poetry/tomlkit/issues/505)) +- Reject tables inserted into inline tables instead of serializing invalid TOML. ([#531](https://github.com/python-poetry/tomlkit/issues/531)) ## [0.15.0] - 2026-05-10 diff --git a/tests/test_items.py b/tests/test_items.py index b4653e72..589cb5c9 100644 --- a/tests/test_items.py +++ b/tests/test_items.py @@ -887,6 +887,17 @@ def test_trim_comments_when_building_inline_table() -> None: assert table.as_string() == '{foo = "bar", baz = "foobaz"}' +def test_append_table_to_inline_table_raises() -> None: + table = api.table() + table.append("a", 1) + inline_table = api.inline_table() + + with pytest.raises(ValueError, match="cannot contain a table"): + inline_table.append("table", table) + with pytest.raises(ValueError, match="cannot contain a table"): + inline_table["table"] = table + + def test_deleting_inline_table_element_does_not_leave_trailing_separator() -> None: table = api.inline_table() table["foo"] = "bar" diff --git a/tomlkit/items.py b/tomlkit/items.py index 6cbb29a9..05a1a3c7 100644 --- a/tomlkit/items.py +++ b/tomlkit/items.py @@ -2035,6 +2035,8 @@ def append(self, key: Key | str | None, _item: Any) -> InlineTable: if not isinstance(_item, Item): _item = item(_item, _parent=self) + self._validate_child(_item) + if not isinstance(_item, (Whitespace, Comment)): if not _item.trivia.indent and len(self._value) > 0 and not self._new: _item.trivia.indent = " " @@ -2051,6 +2053,10 @@ def append(self, key: Key | str | None, _item: Any) -> InlineTable: return self + def _validate_child(self, _item: Item) -> None: + if isinstance(_item, Table): + raise ValueError("Inline tables cannot contain a table") + def as_string(self) -> str: buf = "{" emitted_key = False @@ -2174,6 +2180,9 @@ def _render_dotted(self, key: Key, table: Table) -> list[str]: def __setitem__(self, key: Key | str, value: Any) -> None: # type: ignore[override] if hasattr(value, "trivia") and value.trivia.comment: value.trivia.comment = "" + if not isinstance(value, Item): + value = item(value, _parent=self) + self._validate_child(value) super().__setitem__(key, value) def __copy__(self) -> InlineTable: