diff --git a/lib/modules/manager/pep621/processors/uv.spec.ts b/lib/modules/manager/pep621/processors/uv.spec.ts index 7488abe4fc8e744c6f549d6485258cdd35def95b..21141d6250483e14f570f1a6ac755c614d04ce7d 100644 --- a/lib/modules/manager/pep621/processors/uv.spec.ts +++ b/lib/modules/manager/pep621/processors/uv.spec.ts @@ -26,7 +26,7 @@ describe('modules/manager/pep621/processors/uv', () => { describe('process()', () => { it('returns initial dependencies if there is no tool.uv section', () => { const pyproject = { tool: {} }; - const dependencies = [{ packageName: 'dep1' }]; + const dependencies = [{ depName: 'dep1' }]; const result = processor.process(pyproject, dependencies); @@ -37,12 +37,12 @@ describe('modules/manager/pep621/processors/uv', () => { const pyproject = { tool: { uv: { 'dev-dependencies': ['dep2==1.2.3', 'dep3==2.3.4'] } }, }; - const dependencies = [{ packageName: 'dep1' }]; + const dependencies = [{ depName: 'dep1' }]; const result = processor.process(pyproject, dependencies); expect(result).toEqual([ - { packageName: 'dep1' }, + { depName: 'dep1' }, { currentValue: '==1.2.3', currentVersion: '1.2.3', @@ -61,6 +61,66 @@ describe('modules/manager/pep621/processors/uv', () => { }, ]); }); + + it('skips dependencies with unsupported sources', () => { + const pyproject = { + tool: { + uv: { + sources: { + dep2: { git: 'https://github.com/foo/bar' }, + dep3: { path: '/local-dep.whl' }, + dep4: { url: 'https://example.com' }, + dep5: { workspace: true }, + dep6: { workspace: false }, + dep7: {}, + }, + }, + }, + }; + const dependencies = [ + {}, + { depName: 'dep1' }, + { depName: 'dep2' }, + { depName: 'dep3' }, + { depName: 'dep4' }, + { depName: 'dep5' }, + { depName: 'dep6' }, + { depName: 'dep7' }, + ]; + + const result = processor.process(pyproject, dependencies); + + expect(result).toEqual([ + {}, + { + depName: 'dep1', + }, + { + depName: 'dep2', + skipReason: 'git-dependency', + }, + { + depName: 'dep3', + skipReason: 'path-dependency', + }, + { + depName: 'dep4', + skipReason: 'unsupported-url', + }, + { + depName: 'dep5', + skipReason: 'inherited-dependency', + }, + { + depName: 'dep6', + skipReason: 'invalid-dependency-specification', + }, + { + depName: 'dep7', + skipReason: 'invalid-dependency-specification', + }, + ]); + }); }); describe('updateArtifacts()', () => { diff --git a/lib/modules/manager/pep621/processors/uv.ts b/lib/modules/manager/pep621/processors/uv.ts index f5b6cd5c7f713f0f7e95c98ba0d9bcda3632994c..e59ac557dc1f3cf33d26c2646914026f5d8d51b8 100644 --- a/lib/modules/manager/pep621/processors/uv.ts +++ b/lib/modules/manager/pep621/processors/uv.ts @@ -32,6 +32,31 @@ export class UvProcessor implements PyProjectProcessor { ), ); + // https://docs.astral.sh/uv/concepts/dependencies/#dependency-sources + // Skip sources that are either not yet handled by Renovate (e.g. git), or do not make sense to handle (e.g. path). + if (uv.sources) { + for (const dep of deps) { + if (!dep.depName) { + continue; + } + + const depSource = uv.sources[dep.depName]; + if (depSource) { + if (depSource.git) { + dep.skipReason = 'git-dependency'; + } else if (depSource.url) { + dep.skipReason = 'unsupported-url'; + } else if (depSource.path) { + dep.skipReason = 'path-dependency'; + } else if (depSource.workspace) { + dep.skipReason = 'inherited-dependency'; + } else { + dep.skipReason = 'invalid-dependency-specification'; + } + } + } + } + return deps; } diff --git a/lib/modules/manager/pep621/schema.ts b/lib/modules/manager/pep621/schema.ts index 4fc2b80a7dc697cdbf0db54acc2cef96928da7b5..913c43c87c526f759adb9db373b76195c9073863 100644 --- a/lib/modules/manager/pep621/schema.ts +++ b/lib/modules/manager/pep621/schema.ts @@ -35,8 +35,17 @@ const HatchSchema = z.object({ .optional(), }); +// https://docs.astral.sh/uv/concepts/dependencies/#dependency-sources +const UvSource = z.object({ + git: z.string().optional(), + path: z.string().optional(), + url: z.string().optional(), + workspace: z.boolean().optional(), +}); + const UvSchema = z.object({ 'dev-dependencies': DependencyListSchema, + sources: z.record(z.string(), UvSource).optional(), }); export const PyProjectSchema = z.object({