feat(pip): add pyproject.toml support via pip --dry-run --report#465
Conversation
Review Summary by QodoAdd pip provider for PEP 621 pyproject.toml and workspace support
WalkthroughsDescription• Add Python_pip_pyproject provider for PEP 621 pyproject.toml without lock files • Resolve dependencies using pip install --dry-run --ignore-installed --report • Implement workspace/monorepo support with lock file discovery and boundary detection • Add comprehensive test coverage for pip provider and workspace scenarios Diagramflowchart LR
A["pyproject.toml<br/>PEP 621 format"] -->|"pip --dry-run<br/>--report"| B["pip report<br/>JSON"]
B -->|"Parse & build<br/>dependency graph"| C["Python_pip_pyproject<br/>Provider"]
C -->|"Fallback when<br/>no lock file"| D["SBOM<br/>with transitive deps"]
E["Workspace detection<br/>uv/poetry markers"] -->|"Walk up directory<br/>tree"| F["Find lock file<br/>or boundary"]
F -->|"Resolve to<br/>correct lock dir"| G["Accurate analysis<br/>per package"]
File Changes1. src/provider.js
|
Code Review by Qodo
|
Verification Report — TC-4065
Root-Cause AnalysisTC-4098 —
TC-4099 —
Overall: ❌ FAILBlocking issues:
This comment was AI-generated by sdlc-workflow/verify-pr v0.5.11. |
Verification Report for TC-4065 (commit 7a2cffa)
Overall:
|
|
/review |
|
/retest |
Add Python_pip_pyproject provider that resolves PEP 621 pyproject.toml dependencies using `pip install --dry-run --ignore-installed --report`. This is the fallback provider when no lock file (uv.lock/poetry.lock) is found, enabling analysis of standard pyproject.toml projects without requiring uv or poetry. The pip report JSON provides resolved versions, requires_dist for building the dependency tree, and requested flags for direct vs transitive classification. Extras-only deps are filtered out. Supports TRUSTIFY_DA_PIP_REPORT env var for testing without pip. Implements TC-4065 Assisted-by: Claude Code
…se class Python_pip_pyproject._getDependencyData() had only 3 parameters (manifestDir, parsed, opts) instead of the 4 defined by the base class (manifestDir, workspaceDir, parsed, opts). When called from _createSbom() with 4 arguments, workspaceDir was silently received as parsed, and parsed was received as opts, causing argument misalignment. Add the missing _workspaceDir parameter to match the base class contract and sibling providers (python_uv, python_poetry). Implements TC-4098 Assisted-by: Claude Code
…ir_info entries _parsePipReport() filtered nonRootPackages by checking p.download_info?.dir_info === undefined, which excluded ALL packages with dir_info (including local/path dependencies). Changed to filter by identity (p !== rootEntry) so only the specific root project entry is excluded, matching the Java implementation's behavior. Implements TC-4099 Assisted-by: Claude Code
Extract shared SBOM_CASES constant and use forEach loops to eliminate repetitive stack/component test pairs across uv, poetry, and pip suites. Parameterize validateLockFile and workspace tests similarly. Add JSDoc comments to all 39 test functions. Implements TC-4065 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…tering Add requests[socks] to the test pyproject.toml and include PySocks in the pip_report.json install list. This makes the extras-filtering test exercise the actual code path: PySocks is now present in the report but correctly excluded from the SBOM via _hasExtraMarker. Previously the test trivially passed because PySocks was never in the install list. Implements TC-4065 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove TRUSTIFY_DA_PIP_REPORT setup/teardown from pip tests and let them invoke pip directly. Pin fixture pyproject.toml versions to get deterministic output, add --quiet flag to suppress non-JSON stdout, and update expected SBOMs with real resolved versions. Add testing convention to CONVENTIONS.md and ignore *.egg-info build artifacts. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
CI uses Python 3.9 (setup-python in test.yml), so pip rejects pyproject.toml fixtures that require >=3.12. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
pip creates .egg-info as a side effect of --dry-run --report. Snapshot existing .egg-info dirs before invoking pip and remove only newly created ones afterward to avoid polluting the user's project. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The pip_pep621_ignore fixture was missing expected_stack_sbom.json and expected_component_sbom.json, relying on partial manual assertions instead of the standard SBOM_CASES golden-file pattern. Add the golden files and switch to deep.equal comparison. Document the golden SBOM convention in CONVENTIONS.md to prevent this gap in future implementations. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The pyproject base class built an intermediate tree with a visited set that prevented a dependency from appearing under multiple parents. This caused PySocks to be missing from requests' dependsOn when both requests and urllib3 declared it (via extras). All other providers (npm, cargo, go, maven) already produce true CycloneDX graphs. Replace _buildDependencyTree/_collectTransitive/_addAllDependencies with graph-based BFS reachability + flat edge iteration. No recursion prevention needed — Python resolvers reject circular dependencies. Regenerate all pyproject golden SBOM files (pip, uv, poetry, workspace). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Summary
Python_pip_pyprojectprovider that resolves PEP 621pyproject.tomldependencies usingpip install --dry-run --ignore-installed --reportuv.lock/poetry.lock) is found — registered after uv/poetry in the provider matching orderTRUSTIFY_DA_PIP_REPORTenv var override for testing without pip installed_getDependencyDatasignature inPython_pip_pyprojectto match base class 4-param contract (TC-4098)_parsePipReportto only exclude the root entry from the graph, not alldir_infoentries — preserves local/path dependencies (TC-4099)Details
The pip report JSON provides:
requires_distper package for building the dependency treerequested: true/falsefor root project identificationExtras-only dependencies (e.g.
PySocks; extra == "socks") are filtered out.Only PEP 621 format (
[project.dependencies]) is in scope — poetry-formatpyproject.tomlshould use the lock-file-based provider.Implements TC-4065
Test plan
exhortignoremarker excludes deps from both analysis typescharset_normalizer→charset-normalizer)validateLockFilealways returns true (fallback)🤖 Generated with Claude Code