Skip to content

Commit a9174b5

Browse files
a-orenclaude
andcommitted
refactor(python): switch UV provider from pip list/show to uv export
Replace the two-command approach (uv pip list + uv pip show) with a single uv export --format requirements.txt --frozen --no-hashes --no-dev --no-emit-project, aligning with the JS client implementation. Also extract duplicated canonicalize() method from PythonUvProvider and PythonPyprojectProvider into PyprojectTomlUtils, and convert UvPackage and UvDependencyData from static final classes to records. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent e8e4756 commit a9174b5

12 files changed

Lines changed: 224 additions & 420 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -608,7 +608,7 @@ Python support works with both `requirements.txt` and `pyproject.toml` manifest
608608

609609
##### uv Support
610610

611-
When a `uv.lock` file is present alongside `pyproject.toml`, the client automatically uses the [uv](https://docs.astral.sh/uv/) package manager for dependency resolution instead of pip. Dependency data is collected via `uv pip list --format=json` and `uv pip show`. No additional configuration is required — the provider is selected automatically based on lock file detection.
611+
When a `uv.lock` file is present alongside `pyproject.toml`, the client automatically uses the [uv](https://docs.astral.sh/uv/) package manager for dependency resolution instead of pip. Dependency data is collected via `uv export --format requirements.txt --frozen --no-hashes --no-dev`. No additional configuration is required — the provider is selected automatically based on lock file detection.
612612

613613
To use a custom uv binary, set `TRUSTIFY_DA_UV_PATH` to the path of your uv executable.
614614

src/main/java/io/github/guacsec/trustifyda/providers/PythonPyprojectProvider.java

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ private void addDependencyTree(
132132
PackageURL packageURL = toPurl(pkg.name, pkg.version);
133133
sbom.addDependency(source, packageURL, null);
134134

135-
String key = canonicalize(pkg.name);
135+
String key = PyprojectTomlUtils.canonicalize(pkg.name);
136136
if (!visited.add(key)) {
137137
return;
138138
}
@@ -263,7 +263,7 @@ PipReportData parsePipReport(String reportJson) throws IOException {
263263
}
264264
String name = extractDepName(reqStr);
265265
if (name != null) {
266-
directDepNames.add(canonicalize(name));
266+
directDepNames.add(PyprojectTomlUtils.canonicalize(name));
267267
}
268268
}
269269
}
@@ -282,7 +282,7 @@ PipReportData parsePipReport(String reportJson) throws IOException {
282282
if (name == null) {
283283
continue;
284284
}
285-
String key = canonicalize(name);
285+
String key = PyprojectTomlUtils.canonicalize(name);
286286
graph.put(key, new PipPackage(name, version, new ArrayList<>()));
287287
}
288288

@@ -296,7 +296,7 @@ PipReportData parsePipReport(String reportJson) throws IOException {
296296
if (name == null) {
297297
continue;
298298
}
299-
String key = canonicalize(name);
299+
String key = PyprojectTomlUtils.canonicalize(name);
300300
PipPackage pipPkg = graph.get(key);
301301
if (pipPkg == null) {
302302
continue;
@@ -314,7 +314,7 @@ PipReportData parsePipReport(String reportJson) throws IOException {
314314
if (depName == null) {
315315
continue;
316316
}
317-
String depKey = canonicalize(depName);
317+
String depKey = PyprojectTomlUtils.canonicalize(depName);
318318
if (graph.containsKey(depKey)) {
319319
pipPkg.children.add(depKey);
320320
}
@@ -335,10 +335,6 @@ static String extractDepName(String req) {
335335
return m.find() ? m.group(1) : null;
336336
}
337337

338-
static String canonicalize(String name) {
339-
return name.toLowerCase().replaceAll("[-_.]+", "-");
340-
}
341-
342338
private TomlParseResult getToml() throws IOException {
343339
if (cachedToml == null) {
344340
cachedToml = PyprojectTomlUtils.parseToml(manifestPath);

0 commit comments

Comments
 (0)