-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathpython.ts
More file actions
275 lines (248 loc) · 8.6 KB
/
Copy pathpython.ts
File metadata and controls
275 lines (248 loc) · 8.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
/* eslint-disable @typescript-eslint/naming-convention */
import { commands, Disposable, Event, EventEmitter, extensions, Uri, WorkspaceFolder } from 'vscode';
import { traceError, traceLog } from './log/logging';
type Environment = EnvironmentPath & {
/**
* Carries details about python executable.
*/
readonly executable: {
/**
* Uri of the python interpreter/executable. Carries `undefined` in case an executable does not belong to
* the environment.
*/
readonly uri: Uri | undefined;
/**
* Bitness if known at this moment.
*/
readonly bitness: Bitness | undefined;
/**
* Value of `sys.prefix` in sys module if known at this moment.
*/
readonly sysPrefix: string | undefined;
};
/**
* Carries details if it is an environment, otherwise `undefined` in case of global interpreters and others.
*/
readonly environment:
| {
/**
* Type of the environment.
*/
readonly type: EnvironmentType;
/**
* Name to the environment if any.
*/
readonly name: string | undefined;
/**
* Uri of the environment folder.
*/
readonly folderUri: Uri;
/**
* Any specific workspace folder this environment is created for.
*/
readonly workspaceFolder: Uri | undefined;
}
| undefined;
/**
* Carries Python version information known at this moment.
*/
readonly version: VersionInfo & {
/**
* Value of `sys.version` in sys module if known at this moment.
*/
readonly sysVersion: string | undefined;
};
/**
* Tools/plugins which created the environment or where it came from. First value in array corresponds
* to the primary tool which manages the environment, which never changes over time.
*
* Array is empty if no tool is responsible for creating/managing the environment. Usually the case for
* global interpreters.
*/
readonly tools: readonly EnvironmentTools[];
};
/**
* Derived form of {@link Environment} where certain properties can no longer be `undefined`. Meant to represent an
* {@link Environment} with complete information.
*/
type ResolvedEnvironment = Environment & {
/**
* Carries complete details about python executable.
*/
readonly executable: {
/**
* Uri of the python interpreter/executable. Carries `undefined` in case an executable does not belong to
* the environment.
*/
readonly uri: Uri | undefined;
/**
* Bitness of the environment.
*/
readonly bitness: Bitness;
/**
* Value of `sys.prefix` in sys module.
*/
readonly sysPrefix: string;
};
/**
* Carries complete Python version information.
*/
readonly version: ResolvedVersionInfo & {
/**
* Value of `sys.version` in sys module if known at this moment.
*/
readonly sysVersion: string;
};
};
type EnvironmentsChangeEvent = {
readonly env: Environment;
/**
* * "add": New environment is added.
* * "remove": Existing environment in the list is removed.
* * "update": New information found about existing environment.
*/
readonly type: 'add' | 'remove' | 'update';
};
type ActiveEnvironmentPathChangeEvent = EnvironmentPath & {
/**
* Workspace folder the environment changed for.
*/
readonly resource: WorkspaceFolder | undefined;
};
/**
* Uri of a file inside a workspace or workspace folder itself.
*/
type Resource = Uri | WorkspaceFolder;
type EnvironmentPath = {
/**
* The ID of the environment.
*/
readonly id: string;
/**
* Path to environment folder or path to python executable that uniquely identifies an environment. Environments
* lacking a python executable are identified by environment folder paths, whereas other envs can be identified
* using python executable path.
*/
readonly path: string;
};
/**
* Tool/plugin where the environment came from. It can be {@link KnownEnvironmentTools} or custom string which
* was contributed.
*/
type EnvironmentTools = KnownEnvironmentTools | string;
/**
* Tools or plugins the Python extension currently has built-in support for. Note this list is expected to shrink
* once tools have their own separate extensions.
*/
type KnownEnvironmentTools =
| 'Conda'
| 'Pipenv'
| 'Poetry'
| 'VirtualEnv'
| 'Venv'
| 'VirtualEnvWrapper'
| 'Pyenv'
| 'Unknown';
/**
* Type of the environment. It can be {@link KnownEnvironmentTypes} or custom string which was contributed.
*/
type EnvironmentType = KnownEnvironmentTypes | string;
/**
* Environment types the Python extension is aware of. Note this list is expected to shrink once tools have their
* own separate extensions, in which case they're expected to provide the type themselves.
*/
type KnownEnvironmentTypes = 'VirtualEnvironment' | 'Conda' | 'Unknown';
/**
* Carries bitness for an environment.
*/
type Bitness = '64-bit' | '32-bit' | 'Unknown';
/**
* The possible Python release levels.
*/
type PythonReleaseLevel = 'alpha' | 'beta' | 'candidate' | 'final';
/**
* Release information for a Python version.
*/
type PythonVersionRelease = {
readonly level: PythonReleaseLevel;
readonly serial: number;
};
type VersionInfo = {
readonly major: number | undefined;
readonly minor: number | undefined;
readonly micro: number | undefined;
readonly release: PythonVersionRelease | undefined;
};
type ResolvedVersionInfo = {
readonly major: number;
readonly minor: number;
readonly micro: number;
readonly release: PythonVersionRelease;
};
interface IExtensionApi {
ready: Promise<void>;
debug: {
getRemoteLauncherCommand(host: string, port: number, waitUntilDebuggerAttaches: boolean): Promise<string[]>;
getDebuggerPackagePath(): Promise<string | undefined>;
};
environments: {
getActiveEnvironmentPath(resource?: Resource): EnvironmentPath;
resolveEnvironment(
environment: Environment | EnvironmentPath | string,
): Promise<ResolvedEnvironment | undefined>;
readonly onDidChangeActiveEnvironmentPath: Event<ActiveEnvironmentPathChangeEvent>;
};
}
export interface IInterpreterDetails {
path?: string[];
resource?: Uri;
}
const onDidChangePythonInterpreterEvent = new EventEmitter<IInterpreterDetails>();
export const onDidChangePythonInterpreter: Event<IInterpreterDetails> = onDidChangePythonInterpreterEvent.event;
async function activateExtension() {
const extension = extensions.getExtension('ms-python.python');
if (extension) {
if (!extension.isActive) {
await extension.activate();
}
}
return extension;
}
async function getPythonExtensionAPI(): Promise<IExtensionApi | undefined> {
const extension = await activateExtension();
return extension?.exports as IExtensionApi;
}
export async function initializePython(disposables: Disposable[]): Promise<void> {
try {
const api = await getPythonExtensionAPI();
if (api) {
disposables.push(
api.environments.onDidChangeActiveEnvironmentPath((e) => {
onDidChangePythonInterpreterEvent.fire({ path: [e.path], resource: e.resource?.uri });
}),
);
traceLog('Waiting for interpreter from python extension.');
onDidChangePythonInterpreterEvent.fire(await getInterpreterDetails());
}
} catch (error) {
traceError('Error initializing python: ', error);
}
}
export async function getInterpreterDetails(resource?: Uri): Promise<IInterpreterDetails> {
const api = await getPythonExtensionAPI();
const environment = await api?.environments.resolveEnvironment(api?.environments.getActiveEnvironmentPath(resource));
if (environment?.executable.uri) {
return { path: [environment?.executable.uri.fsPath], resource };
}
return { path: undefined, resource };
}
export async function getDebuggerPath(): Promise<string | undefined> {
const api = await getPythonExtensionAPI();
return api?.debug.getDebuggerPackagePath();
}
export async function runPythonExtensionCommand(command: string, ...rest: any[]) {
await activateExtension();
return await commands.executeCommand(command, ...rest);
}