Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
- 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))
- Out-of-order value-vs-table and dotted-key-vs-table redefinitions are now rejected at parse time instead of being silently accepted or raising only on access. The parser also detects when a non-dotted key is a prefix of an existing dotted key, matching the stdlib `tomllib` behaviour. ([#523](https://github.com/python-poetry/tomlkit/issues/523))
- Reject tables inserted into inline tables instead of serializing invalid TOML. ([#531](https://github.com/python-poetry/tomlkit/issues/531))
- Fix assigning an array of tables over a dotted key (e.g. `doc["a"] = aot(...)` where `a` came from `a.b = ...`): the new `[[a]]` header kept the dotted key's inline position and swallowed the following dotted sibling on round-trip. The array of tables now renders past the inline entries it would otherwise capture, mirroring the table fix for [#513](https://github.com/python-poetry/tomlkit/issues/513). ([#542](https://github.com/python-poetry/tomlkit/issues/542))

## [0.15.0] - 2026-05-10

Expand Down
22 changes: 22 additions & 0 deletions tests/test_toml_document.py
Original file line number Diff line number Diff line change
Expand Up @@ -1113,6 +1113,28 @@ def test_replace_dotted_key_with_table_keeps_following_sibling() -> None:
assert parse(doc.as_string()) == {"c": {"d": 2}, "a": {"x": 9}}


def test_replace_dotted_key_with_aot_keeps_following_sibling() -> None:
# https://github.com/python-poetry/tomlkit/issues/542
content = """a.b = 1
c.d = 2
"""
doc = parse(content)
arr = tomlkit.aot()
tbl = tomlkit.table()
tbl["x"] = 9
arr.append(tbl)
doc["a"] = arr
assert (
doc.as_string()
== """c.d = 2

[[a]]
x = 9
"""
)
assert parse(doc.as_string()) == {"c": {"d": 2}, "a": [{"x": 9}]}


def test_replace_value_with_table_keeps_following_dotted_sibling() -> None:
# A plain value turning into a table must likewise clear the inline region
# (including dotted keys) before emitting its header.
Expand Down
12 changes: 7 additions & 5 deletions tomlkit/container.py
Original file line number Diff line number Diff line change
Expand Up @@ -860,11 +860,13 @@ def _replace_at(
assert k is not None
# A dotted key renders its value inline (e.g. ``a.b = 1``), which is only
# consistent with a super table. When the replacement value renders with
# its own ``[header]`` instead (a non-super table), keeping the dotted key
# duplicates the prefix onto the header (#524). Drop the dotted key so the
# replacement renders as a plain table.
dotted_to_header = (
k.is_dotted() and isinstance(value, Table) and not value.is_super_table()
# its own ``[header]`` instead (a non-super table, or an array of tables),
# keeping the dotted key duplicates the prefix onto the header (#524) and
# lets the header swallow following dotted siblings (#542). Drop the dotted
# key so the replacement renders as a plain table/array of tables.
dotted_to_header = k.is_dotted() and (
isinstance(value, AoT)
or (isinstance(value, Table) and not value.is_super_table())
)
# That new header also captures every sibling that renders inline -- plain
# values and dotted keys -- if any still follow it (#513), so it must be
Expand Down
Loading