@@ -109,6 +109,7 @@ pub fn find_and_report_envs(
109
109
locators,
110
110
false ,
111
111
& global_env_search_paths,
112
+ None ,
112
113
) ;
113
114
summary. lock ( ) . unwrap ( ) . find_path_time = start. elapsed ( ) ;
114
115
} ) ;
@@ -138,6 +139,7 @@ pub fn find_and_report_envs(
138
139
locators,
139
140
false ,
140
141
& global_env_search_paths,
142
+ None ,
141
143
) ;
142
144
summary. lock ( ) . unwrap ( ) . find_global_virtual_envs_time = start. elapsed ( ) ;
143
145
} ) ;
@@ -161,8 +163,6 @@ pub fn find_and_report_envs(
161
163
search_paths,
162
164
reporter,
163
165
locators,
164
- 0 ,
165
- 1 ,
166
166
) ;
167
167
summary. lock ( ) . unwrap ( ) . find_search_paths_time = start. elapsed ( ) ;
168
168
} ) ;
@@ -173,61 +173,50 @@ pub fn find_and_report_envs(
173
173
}
174
174
175
175
fn find_python_environments_in_workspace_folders_recursive (
176
- paths : Vec < PathBuf > ,
176
+ workspace_folders : Vec < PathBuf > ,
177
177
reporter : & dyn Reporter ,
178
178
locators : & Arc < Vec < Arc < dyn Locator > > > ,
179
- depth : u32 ,
180
- max_depth : u32 ,
181
179
) {
182
180
thread:: scope ( |s| {
183
- // Find in cwd
184
- let paths1 = paths. clone ( ) ;
185
181
s. spawn ( || {
186
- find_python_environments ( paths1, reporter, locators, true , & [ ] ) ;
187
-
188
- if depth >= max_depth {
189
- return ;
190
- }
191
-
192
182
let bin = if cfg ! ( windows) { "Scripts" } else { "bin" } ;
193
- // If the folder has a bin or scripts, then ignore it, its most likely an env.
194
- // I.e. no point looking for python environments in a Python environment.
195
- let paths = paths
196
- . into_iter ( )
197
- . filter ( |p| !p. join ( bin) . exists ( ) )
198
- . collect :: < Vec < PathBuf > > ( ) ;
183
+ for workspace_folder in workspace_folders {
184
+ find_python_environments_in_paths_with_locators (
185
+ vec ! [
186
+ // Possible this is a virtual env
187
+ workspace_folder. clone( ) ,
188
+ // Optimize for finding these first.
189
+ workspace_folder. join( ".venv" ) ,
190
+ // Optimize for finding these first.
191
+ workspace_folder. join( ".conda" ) ,
192
+ ] ,
193
+ locators,
194
+ reporter,
195
+ true ,
196
+ & [ ] ,
197
+ Some ( workspace_folder. clone ( ) ) ,
198
+ ) ;
199
+
200
+ if workspace_folder. join ( bin) . exists ( ) {
201
+ // If the folder has a bin or scripts, then ignore it, its most likely an env.
202
+ // I.e. no point looking for python environments in a Python environment.
203
+ continue ;
204
+ }
199
205
200
- for path in paths {
201
- if let Ok ( reader) = fs:: read_dir ( & path) {
202
- let reader = reader
206
+ if let Ok ( reader) = fs:: read_dir ( & workspace_folder) {
207
+ for folder in reader
203
208
. filter_map ( Result :: ok)
204
209
. filter ( |d| d. file_type ( ) . is_ok_and ( |f| f. is_dir ( ) ) )
205
210
. map ( |p| p. path ( ) )
206
- . filter ( should_search_for_environments_in_path) ;
207
-
208
- // Take a batch of 20 items at a time.
209
- let reader = reader. fold ( vec ! [ ] , |f, a| {
210
- let mut f = f;
211
- if f. is_empty ( ) {
212
- f. push ( vec ! [ a] ) ;
213
- return f;
214
- }
215
- let last_item = f. last_mut ( ) . unwrap ( ) ;
216
- if last_item. is_empty ( ) || last_item. len ( ) < 20 {
217
- last_item. push ( a) ;
218
- return f;
219
- }
220
- f. push ( vec ! [ a] ) ;
221
- f
222
- } ) ;
223
-
224
- for entry in reader {
225
- find_python_environments_in_workspace_folders_recursive (
226
- entry,
211
+ . filter ( should_search_for_environments_in_path)
212
+ {
213
+ find_python_environments (
214
+ vec ! [ folder] ,
227
215
reporter,
228
216
locators,
229
- depth + 1 ,
230
- max_depth,
217
+ true ,
218
+ & [ ] ,
219
+ Some ( workspace_folder. clone ( ) ) ,
231
220
) ;
232
221
}
233
222
}
@@ -242,22 +231,23 @@ fn find_python_environments(
242
231
locators : & Arc < Vec < Arc < dyn Locator > > > ,
243
232
is_workspace_folder : bool ,
244
233
global_env_search_paths : & [ PathBuf ] ,
234
+ search_path : Option < PathBuf > ,
245
235
) {
246
236
if paths. is_empty ( ) {
247
237
return ;
248
238
}
249
239
thread:: scope ( |s| {
250
- let chunks = if is_workspace_folder { paths. len ( ) } else { 1 } ;
251
- for item in paths. chunks ( chunks) {
252
- let lst = item. to_vec ( ) . clone ( ) ;
240
+ for item in paths {
253
241
let locators = locators. clone ( ) ;
242
+ let search_path = search_path. clone ( ) ;
254
243
s. spawn ( move || {
255
244
find_python_environments_in_paths_with_locators (
256
- lst ,
245
+ vec ! [ item ] ,
257
246
& locators,
258
247
reporter,
259
248
is_workspace_folder,
260
249
global_env_search_paths,
250
+ search_path,
261
251
) ;
262
252
} ) ;
263
253
}
@@ -270,55 +260,63 @@ fn find_python_environments_in_paths_with_locators(
270
260
reporter : & dyn Reporter ,
271
261
is_workspace_folder : bool ,
272
262
global_env_search_paths : & [ PathBuf ] ,
263
+ search_path : Option < PathBuf > ,
273
264
) {
274
- let executables = if is_workspace_folder {
275
- // If we're in a workspace folder, then we only need to look for bin/python or bin/python.exe
276
- // As workspace folders generally have either virtual env or conda env or the like.
277
- // They will not have environments that will ONLY have a file like `bin/python3` .
278
- // I.e. bin/python will almost always exist .
279
- paths
280
- . iter ( )
265
+ for path in paths {
266
+ let executables = if is_workspace_folder {
267
+ // If we're in a workspace folder, then we only need to look for bin/python or bin/python.exe
268
+ // As workspace folders generally have either virtual env or conda env or the like .
269
+ // They will not have environments that will ONLY have a file like `bin/python3` .
270
+ // I.e. bin/python will almost always exist.
271
+
281
272
// Paths like /Library/Frameworks/Python.framework/Versions/3.10/bin can end up in the current PATH variable.
282
273
// Hence do not just look for files in a bin directory of the path.
283
- . flat_map ( |p| find_executable ( p ) )
284
- . filter_map ( Option :: Some )
285
- . collect :: < Vec < PathBuf > > ( )
286
- } else {
287
- paths
288
- . iter ( )
274
+ if let Some ( executable ) = find_executable ( & path ) {
275
+ vec ! [ executable ]
276
+ } else {
277
+ vec ! [ ]
278
+ }
279
+ } else {
289
280
// Paths like /Library/Frameworks/Python.framework/Versions/3.10/bin can end up in the current PATH variable.
290
281
// Hence do not just look for files in a bin directory of the path.
291
- . flat_map ( find_executables)
292
- . filter ( |p| {
293
- // Exclude python2 on macOS
294
- if std:: env:: consts:: OS == "macos" {
295
- return p. to_str ( ) . unwrap_or_default ( ) != "/usr/bin/python2" ;
296
- }
297
- true
298
- } )
299
- . collect :: < Vec < PathBuf > > ( )
300
- } ;
282
+ find_executables ( path)
283
+ . into_iter ( )
284
+ . filter ( |p| {
285
+ // Exclude python2 on macOS
286
+ if std:: env:: consts:: OS == "macos" {
287
+ return p. to_str ( ) . unwrap_or_default ( ) != "/usr/bin/python2" ;
288
+ }
289
+ true
290
+ } )
291
+ . collect :: < Vec < PathBuf > > ( )
292
+ } ;
301
293
302
- identify_python_executables_using_locators (
303
- executables,
304
- locators,
305
- reporter,
306
- global_env_search_paths,
307
- ) ;
294
+ identify_python_executables_using_locators (
295
+ executables,
296
+ locators,
297
+ reporter,
298
+ global_env_search_paths,
299
+ search_path. clone ( ) ,
300
+ ) ;
301
+ }
308
302
}
309
303
310
304
fn identify_python_executables_using_locators (
311
305
executables : Vec < PathBuf > ,
312
306
locators : & Arc < Vec < Arc < dyn Locator > > > ,
313
307
reporter : & dyn Reporter ,
314
308
global_env_search_paths : & [ PathBuf ] ,
309
+ search_path : Option < PathBuf > ,
315
310
) {
316
311
for exe in executables. into_iter ( ) {
317
312
let executable = exe. clone ( ) ;
318
313
let env = PythonEnv :: new ( exe. to_owned ( ) , None , None ) ;
319
- if let Some ( env) =
320
- identify_python_environment_using_locators ( & env, locators, global_env_search_paths)
321
- {
314
+ if let Some ( env) = identify_python_environment_using_locators (
315
+ & env,
316
+ locators,
317
+ global_env_search_paths,
318
+ search_path. clone ( ) ,
319
+ ) {
322
320
reporter. report_environment ( & env) ;
323
321
if let Some ( manager) = env. manager {
324
322
reporter. report_manager ( & manager) ;
0 commit comments