Skip to content

Fix pyproject product detection tables (#1527, #642) - #1529

Merged
Mikola Lysenko (mikolalysenko) merged 5 commits into
mainfrom
agent/fix-pyproject-product-tables
Oct 14, 2026
Merged

Mikola Lysenko (mikolalysenko) merged 5 commits into
mainfrom
agent/fix-pyproject-product-tables

Conversation

@mikolalysenko

@mikolalysenko Mikola Lysenko (mikolalysenko) commented Oct 14, 2026 •

Copy link
Copy Markdown
Collaborator

LLM Description written by Claude Code:claude-opus-5-5

Fixes #1527
Fixes #642

Summary

vex and scan --vex now detect the product for two documented pyproject layouts that failed with product_undetected (exit 2 for vex, exit 1 for scan --vex after it had already rewritten the lock):

Root cause

vex/product.rs::parse_pyproject took name and version from one table only ([project], else [tool.poetry]), each read by a line scanner that needed both keys in that table. It never combined [project].name with Poetry 2's dynamic version, and it never read [tool.pdm].

Fix

  • pyproject.toml is now read with toml_edit, the crate's existing TOML parser, instead of the line scanner. Multi-line dynamic arrays, dotted keys and inline tables now parse the way tomllib parses them. A BOM'd file still yields no product, as before, because tomllib refuses it. The check goes through formats::text::BOM.
  • Order: [project] name+version. Then, when Poetry builds the project, poetry-core's own merge (Factory.create_poetry): the name is [project].name or else [tool.poetry].name, and the version is [project].version or else [tool.poetry].version. Last comes legacy [tool.pdm].
  • If [project].name and [tool.poetry].name differ, no product is named, because Poetry 2 builds the first and Poetry 1.x the second.
  • "Poetry builds it" means no build-backend is declared, or it is under poetry. or is poetry_dynamic_versioning.backend, and the poetry-dynamic-versioning plugin is not enabled. Under the enabled plugin the version is a placeholder like 0.0.0. Under hatch-vcs or setuptools-scm the table is a leftover. In both cases detection names no product rather than a version that is never built.
  • The old scanner's unit tests now run against the new reader through test-only shims.

Not in this PR: scan --vex resolving the product only after it writes is tracked in #1064.

Per-issue checklist

Test evidence

  • Red on main: cargo test -p socket-patch-core --all-features --lib vex::product → detect_pyproject_poetry2_dynamic_version, pyproject_poetry2_multiline_dynamic_version and detect_pyproject_pdm_legacy_table FAILED (132 passed, 3 failed).
  • Green on the branch: cargo test -p socket-patch-core --all-features --lib -- vex:: formats::text → 700 passed, 0 failed.
  • cargo fmt --all -- --check and cargo clippy --workspace --all-features -- -D warnings are clean.
  • cargo test --workspace --all-features --no-fail-fast: everything passes except tests that make a file or directory read-only or unremovable and expect a write to fail (covgap_commands_vendor, in_process_redirect, repair, plus 4 core tests such as wire_failure_rolls_back_already_written_files), and one in e2e_bun_lockb. The sandbox runs as root, where chmod doesn't block writes. The 4 core tests fail the same way without the last two commits, and none of these tests touch vex/product.rs. CI runs them as a non-root user.
  • No wrapper (npm/pypi/gem) changes: product detection is in the Rust core only.

/code-review high findings not fixed

  • toml_edit parses TOML 1.1 while tomllib parses 1.0. A pyproject that uses only 1.1 syntax, such as a multi-line inline table or a \e escape, would yield a product that pip can't build. That needs a hand-written 1.1-to-1.0 validator, which is far more code than the risk justifies.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Ekek5ktEG5b5ujMggdbzyu


Generated by Claude Code

Assisted-by: Claude Code:claude-opus-5-5
vex and scan --vex failed with product_undetected on two documented
pyproject layouts, because the name and version had to come from one
table:

- Poetry 2 keeps the name in [project] and, when version is listed in
  [project].dynamic, the version in [tool.poetry] (#1527).
- PDM 0.x keeps both in the legacy [tool.pdm] table (#642).

Read pyproject.toml with toml_edit instead of the line scanner, so
multi-line dynamic arrays and dotted keys parse as tomllib parses
them, and fall back through both layouts. A BOM'd file still yields
no product, as tomllib refuses it.

Assisted-by: Claude Code:claude-opus-5-5
Keeps the inline-BOM guard test green: production code names the BOM
through the shared formats::text helpers.

Assisted-by: Claude Code:claude-opus-5-5
A [tool.poetry].version is a placeholder when poetry-dynamic-versioning
is enabled, and a leftover when another backend (hatch-vcs,
setuptools-scm) builds the project. VEX now reports no product for
those instead of naming a version that is never built. Also reads
[project] once and drops comments about the removed line scanner.

Assisted-by: Claude Code:claude-opus-5-5
@mikolalysenko
Mikola Lysenko (mikolalysenko) marked this pull request as ready for review October 14, 2026 11:29
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

BugBot review


Generated by Claude Code

@cursor cursor Bot 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.

Stale Bugbot comment from a previous run.

Comment thread crates/socket-patch-core/src/vex/product.rs Outdated
poetry-core takes the name from [project] or else [tool.poetry], and
the version the same way, with no need for version to be dynamic. A
[project].name with a static [tool.poetry].version now yields a
product, and a [tool.poetry].name that differs from [project].name
(Poetry 1.x and 2 would build different names) yields none instead of
the legacy name. The poetry-dynamic-versioning backend counts as
Poetry when the plugin is not enabled, as it then builds the static
version.

Assisted-by: Claude Code:claude-opus-5-5
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

BugBot review


Generated by Claude Code

@cursor cursor Bot 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.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 66c36d2. Configure here.

Merged via the queue into main with commit 9a5929a Oct 14, 2026
54 checks passed
@mikolalysenko
Mikola Lysenko (mikolalysenko) deleted the agent/fix-pyproject-product-tables branch October 14, 2026 13:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

3 participants