Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@
]
},
"dependencies": {
"@vscode/python-extension": "1.0.1",
"fs-extra": "^11.1.1",
"vscode-languageclient": "^8.1.0"
},
Expand Down
229 changes: 9 additions & 220 deletions src/common/python.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,214 +2,9 @@
// Licensed under the MIT License.

/* eslint-disable @typescript-eslint/naming-convention */
import { commands, Disposable, Event, EventEmitter, extensions, Uri, WorkspaceFolder } from 'vscode';
import { commands, Disposable, Event, EventEmitter, Uri } 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>;
};
}
import { PythonExtension, ResolvedEnvironment } from '@vscode/python-extension';

export interface IInterpreterDetails {
path?: string[];
Expand All @@ -219,19 +14,13 @@ export interface IInterpreterDetails {
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();
}
let _api: PythonExtension | undefined;
async function getPythonExtensionAPI(): Promise<PythonExtension | undefined> {
if (_api) {
return _api;
}
return extension;
}

async function getPythonExtensionAPI(): Promise<IExtensionApi | undefined> {
const extension = await activateExtension();
return extension?.exports as IExtensionApi;
_api = await PythonExtension.api();
return _api;
}

export async function initializePython(disposables: Disposable[]): Promise<void> {
Expand Down Expand Up @@ -275,7 +64,7 @@ export async function getDebuggerPath(): Promise<string | undefined> {
}

export async function runPythonExtensionCommand(command: string, ...rest: any[]) {
await activateExtension();
await getPythonExtensionAPI();
return await commands.executeCommand(command, ...rest);
}

Expand Down