@@ -15,6 +15,7 @@ import * as childProcess from "node:child_process";
1515import { WorkspaceFolderManager } from "../vscode-objs/WorkspaceFolderManager" ;
1616import { execFile } from "../cli/CliWrapper" ;
1717import fs from "node:fs" ;
18+ import path from "node:path" ;
1819
1920export class MsPythonExtensionWrapper implements Disposable {
2021 public readonly api : MsPythonExtensionApi ;
@@ -95,6 +96,10 @@ export class MsPythonExtensionWrapper implements Disposable {
9596 return this . api . environments ?. resolveEnvironment ( env ) ;
9697 }
9798
99+ get projectRoot ( ) {
100+ return this . workspaceFolderManager . activeProjectUri . fsPath ;
101+ }
102+
98103 async runWithOutput (
99104 command : string ,
100105 args : string [ ] ,
@@ -115,69 +120,62 @@ export class MsPythonExtensionWrapper implements Disposable {
115120 } ) ;
116121 }
117122
118- async getLatestPackageVersion ( name : string ) {
119- const executable = await this . getPythonExecutable ( ) ;
120- if ( ! executable ) {
121- return ;
123+ async isUsingUv ( ) {
124+ try {
125+ await execFile ( "uv" , [ "--version" ] ) ;
126+ return fs . existsSync ( path . join ( this . projectRoot , "uv.lock" ) ) ;
127+ } catch ( error ) {
128+ return false ;
122129 }
123- const { stdout} = await execFile (
124- executable ,
125- [
130+ }
131+
132+ private async getPipCommandAndArgs (
133+ executable : string ,
134+ baseArgs : string [ ] ,
135+ nativePipArgs : string [ ] = [ ]
136+ ) : Promise < { command : string ; args : string [ ] } > {
137+ const isUv = await this . isUsingUv ( ) ;
138+ if ( isUv ) {
139+ return {
140+ command : "uv" ,
141+ args : [ "pip" , ...baseArgs , "--python" , executable ] ,
142+ } ;
143+ }
144+ return {
145+ command : executable ,
146+ args : [
126147 "-m" ,
127148 "pip" ,
128- "index" ,
129- "versions" ,
130- name ,
149+ ...baseArgs ,
150+ ...nativePipArgs ,
131151 "--disable-pip-version-check" ,
132152 "--no-python-version-warning" ,
133153 ] ,
134- { shell : false }
135- ) ;
136- const match = stdout . match ( / .+ \( ( .+ ) \) / ) ;
137- if ( match ) {
138- return match [ 1 ] ;
139- }
154+ } ;
140155 }
141156
142- async getPackageDetailsFromEnvironment (
143- name : string ,
144- version ?: string | RegExp
145- ) {
157+ async getPackageDetailsFromEnvironment ( name : string ) {
146158 const executable = await this . getPythonExecutable ( ) ;
147159 if ( ! executable ) {
148160 return undefined ;
149161 }
150- if ( version === "latest" ) {
151- version = await this . getLatestPackageVersion ( name ) ;
152- }
153162
154- const { stdout} = await execFile (
155- executable ,
156- [
157- "-m" ,
158- "pip" ,
159- "list" ,
160- "--format" ,
161- "json" ,
162- "--disable-pip-version-check" ,
163- "--no-python-version-warning" ,
164- ] ,
165- { shell : false }
166- ) ;
163+ const { command, args} = await this . getPipCommandAndArgs ( executable , [
164+ "list" ,
165+ "--format" ,
166+ "json" ,
167+ ] ) ;
167168
169+ const { stdout} = await execFile ( command , args , {
170+ shell : false ,
171+ } ) ;
168172 const data : Array < { name : string ; version : string } > = JSON . parse ( stdout ) ;
169- return data . find (
170- ( item ) =>
171- item . name === name &&
172- ( version === undefined ||
173- item . version . match ( version ) !== undefined )
174- ) ;
173+ return data . find ( ( item ) => item . name === name ) ;
175174 }
176175
177- async findPackageInEnvironment ( name : string , version ?: string | RegExp ) {
176+ async findPackageInEnvironment ( name : string ) {
178177 return (
179- ( await this . getPackageDetailsFromEnvironment ( name , version ) ) !==
180- undefined
178+ ( await this . getPackageDetailsFromEnvironment ( name ) ) !== undefined
181179 ) ;
182180 }
183181
@@ -190,19 +188,14 @@ export class MsPythonExtensionWrapper implements Disposable {
190188 if ( ! executable ) {
191189 throw Error ( "No python executable found" ) ;
192190 }
193- if ( version === "latest" ) {
194- version = await this . getLatestPackageVersion ( name ) ;
195- }
196- const args = [
197- "-m" ,
198- "pip" ,
191+
192+ const { command, args} = await this . getPipCommandAndArgs ( executable , [
199193 "install" ,
200194 `${ name } ${ version ? `==${ version } ` : "" } ` ,
201- "--disable-pip-version-check" ,
202- "--no-python-version-warning" ,
203- ] ;
204- outputChannel ?. appendLine ( `Running: ${ executable } ${ args . join ( " " ) } ` ) ;
205- await this . runWithOutput ( executable , args , outputChannel ) ;
195+ ] ) ;
196+
197+ outputChannel ?. appendLine ( `Running: ${ command } ${ args . join ( " " ) } ` ) ;
198+ await this . runWithOutput ( command , args , outputChannel ) ;
206199 }
207200
208201 async uninstallPackageFromEnvironment (
@@ -214,17 +207,15 @@ export class MsPythonExtensionWrapper implements Disposable {
214207 if ( ! exists || ! executable ) {
215208 return ;
216209 }
217- const args = [
218- "-m" ,
219- "pip" ,
220- "uninstall" ,
221- name ,
222- "--disable-pip-version-check" ,
223- "--no-python-version-warning" ,
224- "-y" ,
225- ] ;
226- outputChannel ?. appendLine ( `Running: ${ executable } ${ args . join ( " " ) } ` ) ;
227- await this . runWithOutput ( executable , args , outputChannel ) ;
210+
211+ const { command, args} = await this . getPipCommandAndArgs (
212+ executable ,
213+ [ "uninstall" , name ] ,
214+ [ "-y" ]
215+ ) ;
216+
217+ outputChannel ?. appendLine ( `Running: ${ command } ${ args . join ( " " ) } ` ) ;
218+ await this . runWithOutput ( command , args , outputChannel ) ;
228219 }
229220
230221 async selectPythonInterpreter ( ) {
0 commit comments