Skip to content

Keep out-of-order table indices valid after a table is removed - #635

Open
youdie006 wants to merge 1 commit into
python-poetry:masterfrom
youdie006:fix-out-of-order-proxy-indices
Open

youdie006 wants to merge 1 commit into
python-poetry:masterfrom
youdie006:fix-out-of-order-proxy-indices

Conversation

@youdie006

@youdie006 youdie006 commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Deleting two keys through the same out-of-order table proxy raises or silently does nothing:

src = '[tool.black]\nline-length = 88\n\n[project]\nname = "x"\n\n[tool.ruff]\nselect = ["E"]\n'
doc = tomlkit.parse(src); tool = doc["tool"]
del tool["black"]; del tool["ruff"]      # IndexError: list index out of range
tomlkit.parse(src)["tool"].clear()        # IndexError

With [tool.a], [tool.b] and [tool.c] split by other tables, clear() returns but leaves [tool.b] and [tool.c] in the output. _tables_map holds positions in self._tables, and _remove_table removed the table with list.remove without shifting the later positions (list.remove also compares by equality, so it could take an equal empty table). It now removes the table by identity and shifts the later positions down by one.

test_delete_keys_through_the_same_out_of_order_table fails on master; dropping the shift or shifting the wrong side fails it too. pytest tests (1,069 passed) and pre-commit run on the changed files pass.

Agent Drafting Metadata

  • Agent: Claude Code
  • Model: Claude
  • Notes: Found by comparing edits against a tomllib model. I reviewed the change and ran the tests above.

OutOfOrderTableProxy maps each key to positions in self._tables, but
_remove_table took a table out of that list without shifting the later
positions, so a second delete through the same proxy indexed the wrong
table or ran past the end:

    tool = doc["tool"]; del tool["black"]; del tool["ruff"]  # IndexError

Remove the table by identity and shift the later positions down.

@Wkhanex Wkhanex left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I exercised all six deletion orders with three out-of-order tool subtables that had identical contents, retaining the same proxy throughout. Deleting two keys, replacing the remaining key and clearing the proxy all worked: 18 standalone cases passed, with the unrelated project/other tables preserved.

Checking equal-valued fragments is useful here because list.remove could previously select the wrong table by equality. I validated the serialized remaining document with stdlib tomllib and checked the in-memory result separately; clearing retained an empty parent mapping in memory while removing its subtables from the text.

I used Python 3.12.14 against commit ae55098. These were focused checks, not a full-suite run.

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