forked from DonJayamanne/pythonVSCode
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Expand file tree
/
Copy pathapi.ts
More file actions
167 lines (161 loc) · 7.58 KB
/
api.ts
File metadata and controls
167 lines (161 loc) · 7.58 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
/* eslint-disable @typescript-eslint/no-explicit-any */
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
'use strict';
import { Uri, Event } from 'vscode';
import { BaseLanguageClient, LanguageClientOptions } from 'vscode-languageclient';
import { LanguageClient } from 'vscode-languageclient/node';
import { PYLANCE_NAME } from './activation/node/languageClientFactory';
import { ILanguageServerOutputChannel } from './activation/types';
import { PythonExtension } from './api/types';
import { isTestExecution, PYTHON_LANGUAGE } from './common/constants';
import { IConfigurationService, Resource } from './common/types';
import { getDebugpyLauncherArgs } from './debugger/extension/adapter/remoteLaunchers';
import { IInterpreterService } from './interpreter/contracts';
import { IServiceContainer, IServiceManager } from './ioc/types';
import {
JupyterExtensionIntegration,
JupyterExtensionPythonEnvironments,
JupyterPythonEnvironmentApi,
} from './jupyter/jupyterIntegration';
import { traceError } from './logging';
import { IDiscoveryAPI } from './pythonEnvironments/base/locator';
import { buildEnvironmentApi } from './environmentApi';
import { ApiForPylance } from './pylanceApi';
import { getTelemetryReporter } from './telemetry';
import { TensorboardExtensionIntegration } from './tensorBoard/tensorboardIntegration';
import { getDebugpyPath } from './debugger/pythonDebugger';
export function buildApi(
ready: Promise<void>,
serviceManager: IServiceManager,
serviceContainer: IServiceContainer,
discoveryApi: IDiscoveryAPI,
): PythonExtension {
const configurationService = serviceContainer.get<IConfigurationService>(IConfigurationService);
const interpreterService = serviceContainer.get<IInterpreterService>(IInterpreterService);
serviceManager.addSingleton<JupyterExtensionIntegration>(JupyterExtensionIntegration, JupyterExtensionIntegration);
serviceManager.addSingleton<JupyterExtensionPythonEnvironments>(
JupyterExtensionPythonEnvironments,
JupyterExtensionPythonEnvironments,
);
serviceManager.addSingleton<TensorboardExtensionIntegration>(
TensorboardExtensionIntegration,
TensorboardExtensionIntegration,
);
const jupyterIntegration = serviceContainer.get<JupyterExtensionIntegration>(JupyterExtensionIntegration);
const jupyterPythonEnvApi = serviceContainer.get<JupyterPythonEnvironmentApi>(JupyterExtensionPythonEnvironments);
const tensorboardIntegration = serviceContainer.get<TensorboardExtensionIntegration>(
TensorboardExtensionIntegration,
);
const outputChannel = serviceContainer.get<ILanguageServerOutputChannel>(ILanguageServerOutputChannel);
const api: PythonExtension & {
/**
* Internal API just for Jupyter, hence don't include in the official types.
*/
jupyter: {
registerHooks(): void;
};
/**
* Internal API just for Tensorboard, hence don't include in the official types.
*/
tensorboard: {
registerHooks(): void;
};
} & {
/**
* @deprecated Temporarily exposed for Pylance until we expose this API generally. Will be removed in an
* iteration or two.
*/
pylance: ApiForPylance;
} & {
/**
* @deprecated Use PythonExtension.environments API instead.
*
* Return internal settings within the extension which are stored in VSCode storage
*/
settings: {
/**
* An event that is emitted when execution details (for a resource) change. For instance, when interpreter configuration changes.
*/
readonly onDidChangeExecutionDetails: Event<Uri | undefined>;
/**
* Returns all the details the consumer needs to execute code within the selected environment,
* corresponding to the specified resource taking into account any workspace-specific settings
* for the workspace to which this resource belongs.
* @param {Resource} [resource] A resource for which the setting is asked for.
* * When no resource is provided, the setting scoped to the first workspace folder is returned.
* * If no folder is present, it returns the global setting.
*/
getExecutionDetails(
resource?: Resource,
): {
/**
* E.g of execution commands returned could be,
* * `['<path to the interpreter set in settings>']`
* * `['<path to the interpreter selected by the extension when setting is not set>']`
* * `['conda', 'run', 'python']` which is used to run from within Conda environments.
* or something similar for some other Python environments.
*
* @type {(string[] | undefined)} When return value is `undefined`, it means no interpreter is set.
* Otherwise, join the items returned using space to construct the full execution command.
*/
execCommand: string[] | undefined;
};
};
} = {
// 'ready' will propagate the exception, but we must log it here first.
ready: ready.catch((ex) => {
traceError('Failure during activation.', ex);
return Promise.reject(ex);
}),
jupyter: {
registerHooks: () => jupyterIntegration.integrateWithJupyterExtension(),
},
tensorboard: {
registerHooks: () => tensorboardIntegration.integrateWithTensorboardExtension(),
},
debug: {
async getRemoteLauncherCommand(
host: string,
port: number,
waitUntilDebuggerAttaches = true,
): Promise<string[]> {
return getDebugpyLauncherArgs({
host,
port,
waitUntilDebuggerAttaches,
});
},
async getDebuggerPackagePath(): Promise<string | undefined> {
return getDebugpyPath();
},
},
settings: {
onDidChangeExecutionDetails: interpreterService.onDidChangeInterpreterConfiguration,
getExecutionDetails(resource?: Resource) {
const { pythonPath } = configurationService.getSettings(resource);
// If pythonPath equals an empty string, no interpreter is set.
return { execCommand: pythonPath === '' ? undefined : [pythonPath] };
},
},
pylance: {
createClient: (...args: any[]): BaseLanguageClient => {
// Make sure we share output channel so that we can share one with
// Jedi as well.
const clientOptions = args[1] as LanguageClientOptions;
clientOptions.outputChannel = clientOptions.outputChannel ?? outputChannel.channel;
return new LanguageClient(PYTHON_LANGUAGE, PYLANCE_NAME, args[0], clientOptions);
},
start: (client: BaseLanguageClient): Promise<void> => client.start(),
stop: (client: BaseLanguageClient): Promise<void> => client.stop(),
getTelemetryReporter: () => getTelemetryReporter(),
},
environments: buildEnvironmentApi(discoveryApi, serviceContainer, jupyterPythonEnvApi),
};
// In test environment return the DI Container.
if (isTestExecution()) {
(api as any).serviceContainer = serviceContainer;
(api as any).serviceManager = serviceManager;
}
return api;
}