Repository navigation
Write emptied AoT fallback under its declaring header - #693
ryanchou1994 wants to merge 1 commit into
Conversation
An emptied array of tables is rendered as `key = []` at the top of the nearest header scope. When a table on its path is declared by a header in a later fragment (`[[a.b.c]]` ... `[a]`), the hoisted dotted key `a.b.c = []` declared `a` before `[a]`, which is invalid TOML. Pass such fallbacks down to the deepest table whose header declares them, and write them there with a relative key. Fallbacks without a declaring header are rendered as before. Fixes python-poetry#690
There was a problem hiding this comment.
Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.
An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.
Ekko82
left a comment
There was a problem hiding this comment.
Checked 0c0b3867 on Windows with Python 3.13.9. All 98 tests in tests/test_toml_document.py pass. The six added regression cases fail against base d7def7d and pass on this head; the five existing emptied-AoT cases pass on both.
Twelve additional parse/pop/dump cases also pass, covering equivalent quoted keys, deeper declaring headers, multiple emptied siblings, nested array elements, and controls without a declaring header or with a nonempty AoT. Both tomllib and tomlkit recover the mutated document's data, and rendering is unchanged after a second call or a deepcopy. Nine of these cases produce invalid TOML on the base.
|
One header-order case still produces invalid TOML on import tomlkit
import tomllib
source = "[a.b]\nz=1\n[a]\ny=1\n[[a.b.c]]\nx=1\n"
tomllib.loads(source) # valid input
doc = tomlkit.parse(source)
doc["a"]["b"]["c"].pop()
rendered = doc.as_string()
print(rendered)
tomllib.loads(rendered)The output is: [a.b]
z=1
[a]
b.c = []
y=1
This is an uncovered case, not a regression introduced by the PR: it also fails on base |
|
Thanks for the repro. I can reproduce it on 0c0b386 and on the base too, so it's the same fallback with the declaring [a.b] header sitting in an earlier fragment of a. I'll extend the lookup to cover that, add this case and the deeper variant to the tests, and push here. |
Summary
Since #567, an emptied array of tables is rendered as
key = []at the top of the nearest header scope. If a table on its path is declared by a header in a later fragment ([[a.b.c]]...[a], or[a.b]), the hoisted dotted keya.b.c = []declares that table before its header does, which is invalid TOML (both tomlkit andtomllibreject the output).This change only affects rendering in
tomlkit/container.py: before writing a fallback,_declaring_tablelooks for the deepest table on its path that emits a header in the current scope. If there is one, the fallback is handed to that table and written at the top of its own scope with a relative key, e.g.Fallbacks with no declaring header are written exactly as before, and parsing is untouched.
Tests: the new parametrized cases (5 shapes, also checked with
tomllibon 3.11+) and the exact-output test fail on master and pass with the change. Full suite including the toml-test submodule on Linux (Python 3.14): 1223 passed. The 7tmp_patherrors intest_toml_file.pycome from the container user having no name and happen on master too.ruff checkandruff format --checkare clean.Fixes #690
Duplicate Check
Agent Drafting Metadata