3
3
4
4
import { injectable , inject } from 'inversify' ;
5
5
import { getArchitectureDisplayName } from '../../common/platform/registry' ;
6
+ import { Resource } from '../../common/types' ;
6
7
import { isParentPath } from '../../pythonEnvironments/common/externalDependencies' ;
7
- import { EnvironmentType , PythonEnvironment } from '../../pythonEnvironments/info' ;
8
+ import { EnvironmentType , PythonEnvironment , virtualEnvTypes } from '../../pythonEnvironments/info' ;
8
9
import { PythonVersion } from '../../pythonEnvironments/info/pythonVersion' ;
9
10
import { IInterpreterHelper } from '../contracts' ;
10
11
import { IInterpreterComparer } from './types' ;
11
12
12
- /*
13
- * Enum description:
14
- * - Local environments (.venv);
15
- * - Global environments (pipenv, conda);
16
- * - Globally-installed interpreters (/usr/bin/python3, Windows Store).
17
- */
18
- export enum EnvTypeHeuristic {
13
+ export enum EnvLocationHeuristic {
14
+ /**
15
+ * Environments inside the workspace.
16
+ */
19
17
Local = 1 ,
18
+ /**
19
+ * Environments outside the workspace.
20
+ */
20
21
Global = 2 ,
21
- GlobalInterpreters = 3 ,
22
22
}
23
23
24
24
@injectable ( )
@@ -41,8 +41,14 @@ export class EnvironmentTypeComparer implements IInterpreterComparer {
41
41
* Always sort with newest version of Python first within each subgroup.
42
42
*/
43
43
public compare ( a : PythonEnvironment , b : PythonEnvironment ) : number {
44
+ // Check environment location.
45
+ const envLocationComparison = compareEnvironmentLocation ( a , b , this . workspaceFolderPath ) ;
46
+ if ( envLocationComparison !== 0 ) {
47
+ return envLocationComparison ;
48
+ }
49
+
44
50
// Check environment type.
45
- const envTypeComparison = compareEnvironmentType ( a , b , this . workspaceFolderPath ) ;
51
+ const envTypeComparison = compareEnvironmentType ( a , b ) ;
46
52
if ( envTypeComparison !== 0 ) {
47
53
return envTypeComparison ;
48
54
}
@@ -53,20 +59,15 @@ export class EnvironmentTypeComparer implements IInterpreterComparer {
53
59
return versionComparison ;
54
60
}
55
61
56
- // Prioritize non- Conda environments .
57
- if ( isCondaEnvironment ( a ) && ! isCondaEnvironment ( b ) ) {
62
+ // If we have the "base" Conda env, put it last in its Python version subgroup .
63
+ if ( isBaseCondaEnvironment ( a ) ) {
58
64
return 1 ;
59
65
}
60
66
61
- if ( ! isCondaEnvironment ( a ) && isCondaEnvironment ( b ) ) {
67
+ if ( isBaseCondaEnvironment ( b ) ) {
62
68
return - 1 ;
63
69
}
64
70
65
- // If we have the "base" Conda env, put it last in its Python version subgroup.
66
- if ( isBaseCondaEnvironment ( a ) ) {
67
- return 1 ;
68
- }
69
-
70
71
// Check alphabetical order.
71
72
const nameA = getSortName ( a , this . interpreterHelper ) ;
72
73
const nameB = getSortName ( b , this . interpreterHelper ) ;
@@ -76,6 +77,25 @@ export class EnvironmentTypeComparer implements IInterpreterComparer {
76
77
77
78
return nameA > nameB ? 1 : - 1 ;
78
79
}
80
+
81
+ public getRecommended ( interpreters : PythonEnvironment [ ] , resource : Resource ) : PythonEnvironment | undefined {
82
+ // When recommending an intepreter for a workspace, we either want to return a local one
83
+ // or fallback on a globally-installed interpreter, and we don't want want to suggest a global environment
84
+ // because we would have to add a way to match environments to a workspace.
85
+ const workspaceUri = this . interpreterHelper . getActiveWorkspaceUri ( resource ) ;
86
+ const filteredInterpreters = interpreters . filter ( ( i ) => {
87
+ if ( getEnvLocationHeuristic ( i , workspaceUri ?. folderUri . fsPath || '' ) === EnvLocationHeuristic . Local ) {
88
+ return true ;
89
+ }
90
+ if ( virtualEnvTypes . includes ( i . envType ) ) {
91
+ // We're not sure if these envs were created for the workspace, so do not recommend them.
92
+ return false ;
93
+ }
94
+ return true ;
95
+ } ) ;
96
+ filteredInterpreters . sort ( this . compare . bind ( this ) ) ;
97
+ return filteredInterpreters . length ? filteredInterpreters [ 0 ] : undefined ;
98
+ }
79
99
}
80
100
81
101
function getSortName ( info : PythonEnvironment , interpreterHelper : IInterpreterHelper ) : string {
@@ -113,12 +133,11 @@ function getSortName(info: PythonEnvironment, interpreterHelper: IInterpreterHel
113
133
return `${ sortNameParts . join ( ' ' ) } ${ envSuffix } ` . trim ( ) ;
114
134
}
115
135
116
- function isCondaEnvironment ( environment : PythonEnvironment ) : boolean {
117
- return environment . envType === EnvironmentType . Conda ;
118
- }
119
-
120
136
function isBaseCondaEnvironment ( environment : PythonEnvironment ) : boolean {
121
- return isCondaEnvironment ( environment ) && ( environment . envName === 'base' || environment . envName === 'miniconda' ) ;
137
+ return (
138
+ environment . envType === EnvironmentType . Conda &&
139
+ ( environment . envName === 'base' || environment . envName === 'miniconda' )
140
+ ) ;
122
141
}
123
142
124
143
/**
@@ -151,40 +170,50 @@ function comparePythonVersionDescending(a: PythonVersion | undefined, b: PythonV
151
170
}
152
171
153
172
/**
154
- * Compare 2 environment types : return 0 if they are the same, -1 if a comes before b, 1 otherwise.
173
+ * Compare 2 environment locations : return 0 if they are the same, -1 if a comes before b, 1 otherwise.
155
174
*/
156
- function compareEnvironmentType ( a : PythonEnvironment , b : PythonEnvironment , workspacePath : string ) : number {
157
- const aHeuristic = getEnvTypeHeuristic ( a , workspacePath ) ;
158
- const bHeuristic = getEnvTypeHeuristic ( b , workspacePath ) ;
175
+ function compareEnvironmentLocation ( a : PythonEnvironment , b : PythonEnvironment , workspacePath : string ) : number {
176
+ const aHeuristic = getEnvLocationHeuristic ( a , workspacePath ) ;
177
+ const bHeuristic = getEnvLocationHeuristic ( b , workspacePath ) ;
159
178
160
179
return Math . sign ( aHeuristic - bHeuristic ) ;
161
180
}
162
181
163
182
/**
164
183
* Return a heuristic value depending on the environment type.
165
184
*/
166
- export function getEnvTypeHeuristic ( environment : PythonEnvironment , workspacePath : string ) : EnvTypeHeuristic {
167
- const { envType } = environment ;
168
-
185
+ export function getEnvLocationHeuristic ( environment : PythonEnvironment , workspacePath : string ) : EnvLocationHeuristic {
169
186
if (
170
187
workspacePath . length > 0 &&
171
188
( ( environment . envPath && isParentPath ( environment . envPath , workspacePath ) ) ||
172
189
( environment . path && isParentPath ( environment . path , workspacePath ) ) )
173
190
) {
174
- return EnvTypeHeuristic . Local ;
191
+ return EnvLocationHeuristic . Local ;
175
192
}
193
+ return EnvLocationHeuristic . Global ;
194
+ }
176
195
177
- switch ( envType ) {
178
- case EnvironmentType . Venv :
179
- case EnvironmentType . Conda :
180
- case EnvironmentType . VirtualEnv :
181
- case EnvironmentType . VirtualEnvWrapper :
182
- case EnvironmentType . Pipenv :
183
- case EnvironmentType . Poetry :
184
- return EnvTypeHeuristic . Global ;
185
- // The default case covers global environments.
186
- // For now this includes: pyenv, Windows Store, Global, System and Unknown environment types.
187
- default :
188
- return EnvTypeHeuristic . GlobalInterpreters ;
189
- }
196
+ /**
197
+ * Compare 2 environment types: return 0 if they are the same, -1 if a comes before b, 1 otherwise.
198
+ */
199
+ function compareEnvironmentType ( a : PythonEnvironment , b : PythonEnvironment ) : number {
200
+ const envTypeByPriority = getPrioritizedEnvironmentType ( ) ;
201
+ return Math . sign ( envTypeByPriority . indexOf ( a . envType ) - envTypeByPriority . indexOf ( b . envType ) ) ;
202
+ }
203
+
204
+ function getPrioritizedEnvironmentType ( ) : EnvironmentType [ ] {
205
+ return [
206
+ // Prioritize non-Conda environments.
207
+ EnvironmentType . Poetry ,
208
+ EnvironmentType . Pipenv ,
209
+ EnvironmentType . VirtualEnvWrapper ,
210
+ EnvironmentType . Venv ,
211
+ EnvironmentType . VirtualEnv ,
212
+ EnvironmentType . Conda ,
213
+ EnvironmentType . Pyenv ,
214
+ EnvironmentType . WindowsStore ,
215
+ EnvironmentType . Global ,
216
+ EnvironmentType . System ,
217
+ EnvironmentType . Unknown ,
218
+ ] ;
190
219
}
0 commit comments