Skip to content

Reject trailing characters in key_value() - #594

Open
dylanpulver wants to merge 1 commit into
python-poetry:masterfrom
dylanpulver:fix-key-value-trailing-chars
Open

Reject trailing characters in key_value()#594
dylanpulver wants to merge 1 commit into
python-poetry:masterfrom
dylanpulver:fix-key-value-trailing-chars

Conversation

@dylanpulver

Copy link
Copy Markdown

Summary

tomlkit.key_value() returned the first pair it could parse and threw away
whatever followed:

>>> tomlkit.key_value("a = 1 b = 2 c = 3")
(<Key a >, 1)

TOML 1.0.0 (Key/Value Pair) requires
a newline or EOF after a pair, and parse() already enforces it — each of the
inputs in the new test raises UnexpectedCharError there.
tests/examples/invalid/key_value_with_trailing_chars.toml exists for this exact
rule and its own text spells it out, but it was only ever asserted against
parse().

The fix mirrors what's already next door: value() (api.py:283-287) guards with
if not parser.end(): raise ..., and the document parser reads a top-level pair
with _parse_key_value(True) so the comment trail is consumed. key_value() now
does both. Trailing whitespace, a trailing comment and a final newline stay
valid; real trailing input raises.

This follows the same call the project already made in #527, "Raise on malformed
array element instead of dropping it".

Behaviour change: input that was silently truncated now raises. I found no
open PR or issue touching key_value (checked the changed files of all 22 open
PRs; only #294 touches api.py, for Decimal codecs).

Verification

python -m pytest tests/ -q, same command and environment either side:

result
before (tests added, api.py at HEAD) 5 failed, 1057 passed
after 1062 passed

I also checked the naive version of this fix — the end() guard alone, without
parse_comment=True. It fails 3 of the new cases ("foo = 12\n",
"foo = 12 ", "foo = 12 # comment\n"), which is why those are in the test.

Agent Drafting Metadata

  • Agent: Claude Code
  • Model: Claude Opus 5 (claude-opus-5)
  • Notes: Found by comparing the public helpers in api.py against each other —
    key_value() was the only one with a single test reference, and the sibling
    value() had the end-of-input guard it was missing. The diff, tests and this
    description were drafted with the agent and reviewed before submission.

tomlkit.key_value() parsed a single key/value pair and returned it without
checking that the input was consumed, so anything after the pair was silently
discarded:

    >>> tomlkit.key_value("a = 1 b = 2 c = 3")
    (<Key a >, 1)

TOML 1.0.0 requires a newline or EOF after a key/value pair, and parse()
already enforces that -- tests/examples/invalid/key_value_with_trailing_chars.toml
exists for exactly this rule and is asserted against parse() alone.

Parse the comment trail (as the document parser does for a top-level pair) and
then require end of input, mirroring the guard value() already has. Trailing
whitespace, a comment and a final newline stay valid; real trailing input now
raises UnexpectedCharError.
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.

1 participant