Skip to content

Fix duplicated comma when removing a middle inline table element#486

Merged
frostming merged 1 commit into
python-poetry:masterfrom
sarathfrancis90:fix-inline-table-duplicate-comma-on-remove
Jun 3, 2026
Merged

Fix duplicated comma when removing a middle inline table element#486
frostming merged 1 commit into
python-poetry:masterfrom
sarathfrancis90:fix-inline-table-duplicate-comma-on-remove

Conversation

@sarathfrancis90
Copy link
Copy Markdown
Contributor

Summary

Removing a key that is neither the first nor the last element of a parsed inline table leaves the dangling comma separator from the deleted key in the body, producing invalid TOML that fails to re-parse.

import tomlkit

doc = tomlkit.parse("t = {a = 1, b = 2, c = 3}\n")
del doc["t"]["b"]
print(doc.as_string())
# -> 't = {a = 1, , c = 3}\n'   <-- invalid: a stray ", ,"

tomlkit.parse(doc.as_string())
# tomlkit.exceptions.UnexpectedCharError: Unexpected character: ',' at line 1 col 12

The serialized output is not valid TOML and breaks the parse → mutate → dump round-trip.

Root cause

When a key is removed from a parsed inline table, its value becomes a Null and the two Whitespace separators that surrounded it remain in Container.body. InlineTable.as_string() already strips one comma in a couple of special cases (the leading separator before the first emitted key, and a trailing separator when only Null values follow), but it had no handling for the middle case: a removed interior key leaves two consecutive comma-bearing whitespace entries, so both commas are emitted and you get , ,.

Fix

InlineTable.as_string() now tracks a pending_separator flag. Once a comma separator has been emitted for the current gap, the next comma-bearing whitespace entry encountered before the next real key is recognized as the redundant separator left behind by the removed key and its comma is dropped. The flag is reset whenever an actual key is emitted, so legitimate separators between surviving keys are preserved.

This mirrors the existing comma-stripping pattern already used in the same method (v.as_string().replace(",", "", 1)).

Tests

Added test_deleting_inline_table_middle_element_does_not_leave_double_separator, which deletes a middle key from a parsed inline table and asserts the result contains no , ,/,, sequence, re-parses to the expected value, and is idempotent (parse(s).as_string() == s). The test fails on master and passes with this change.

The full suite is green:

$ pytest -q tests
969 passed

ruff check, ruff format --check, mypy, and all pre-commit hooks pass on the changed files.

Notes

This is the deletion counterpart to the append fix in #477 (issue #476) and is distinct from the last-element trailing-comma case (#259) — both of those are already handled; only interior deletion was missing.

Removing a key that is neither the first nor the last element of a parsed
inline table left both of its surrounding comma separators in the body,
producing invalid TOML such as `{a = 1, , c = 3}` that fails to re-parse.

InlineTable.as_string() now tracks whether a separator has already been
emitted for the current gap and drops the redundant comma left behind by
the removed key, so the serialized output stays valid and round-trips.
@frostming frostming merged commit 5687396 into python-poetry:master Jun 3, 2026
25 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants