@vscode/python-environments 1.0.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,49 @@
1
+ # Changelog
2
+
3
+ All notable changes to the `@vscode/python-environments` API package are documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [1.4.0]
9
+
10
+ ### Changed
11
+
12
+ - Reorganized the package source into separate API facade, public contract, and public error modules without changing the root package exports.
13
+
14
+ ## [1.3.0]
15
+
16
+ ### Added
17
+
18
+ - Added `PackageVersionLookupNotSupportedError`, thrown when a package manager cannot list a package's available versions (an unsupported capability, as distinct from an operational failure). The error exposes a stable `code` (`'PackageVersionLookupNotSupported'`) discriminator.
19
+ - Added the `isPackageVersionLookupNotSupportedError(error): error is PackageVersionLookupNotSupportedError` type guard. It recognizes the error via its stable `code`, so it works even when the error crosses an extension bundle boundary and `instanceof` would fail.
20
+ - Added an optional `errorMode` to `PythonPackageGetterApi.getPackageAvailableVersions`. The default `legacy` mode preserves the existing `undefined` result for unsupported lookups and operational failures. The opt-in `throw` mode rejects with `PackageVersionLookupNotSupportedError` for unsupported capabilities and propagates operational failures unchanged.
21
+
22
+ ### Changed
23
+
24
+ - Documented that `PackageManager.getPackageAvailableVersions` implementations should throw `PackageVersionLookupNotSupportedError` when version lookup is unsupported and let operational failures propagate. Resolving to `undefined` continues to be treated by callers as an unsupported capability.
25
+
26
+ ## [1.2.0]
27
+
28
+ ### Added
29
+
30
+ - Added `PackageManagementInteractionOptions` with an optional `runHeadless?: boolean` property, mixed into `PackageManagementOptions`. When `true`, package management operations run without any user prompts or interaction — steps that would normally require input, such as selecting packages to install when none are specified, are skipped instead of prompting — for automated or headless scenarios such as integration tests.
31
+ - Added `RemoveEnvironmentOptions` with an optional `runHeadless?: boolean` property to remove environments without a confirmation prompt in automated or headless scenarios.
32
+
33
+ ## [1.1.0]
34
+
35
+ ### Added
36
+
37
+ - Re-exported the `Pep440Version` type from `@renovatebot/pep440` for use with the new package version APIs.
38
+ - Added the optional `PackageInfo.isTransitive?: boolean` property to indicate whether a package is a transitive dependency.
39
+ - Added `GetPackagesOptions` with an optional `skipCache?: boolean` property. When `true`, package managers bypass cached data and query the underlying package management tool.
40
+ - Added optional `PackageManager.getPackageWatchTargets?(environment: PythonEnvironment): RelativePattern[]` to return manager-specific filesystem patterns to monitor for package installation and removal changes, in addition to the default site-packages metadata locations.
41
+ - Added optional `PackageManager.getDirectPackageNames?(environment: PythonEnvironment): Promise<Set<string> | undefined>` to return a best-effort set of direct, non-transitive package names when supported by the package manager.
42
+ - Added optional `PackageManager.getVersion?(environment: PythonEnvironment): Promise<Pep440Version | undefined>` to return the version of the underlying package management tool, such as pip, uv, or conda.
43
+ - Added optional `PackageManager.getPackageAvailableVersions?(environment: PythonEnvironment, packageName: string): Promise<Pep440Version[] | undefined>` to return the available versions of a package in newest-first order when supported.
44
+ - Added optional `PackageManager.formatInstallSpec?(packageName: string, version: string): string` to format a versioned install specification using manager-specific syntax, such as `name==version` for pip or `name=version` for conda.
45
+ - Added `PythonPackageGetterApi.getPackageAvailableVersions(environment: PythonEnvironment, packageName: string): Promise<Pep440Version[] | undefined>` so API consumers can query a package's available versions in newest-first order. Resolves to `undefined` when the environment's package manager does not support version listing.
46
+
47
+ ### Changed
48
+
49
+ - Added the optional `options?: GetPackagesOptions` parameter to `PackageManager.getPackages(environment, options?)` and `PythonPackageGetterApi.getPackages(environment, options?)`. Consumers can set `options.skipCache` to request fresh package data.
package/README.md CHANGED
@@ -35,3 +35,20 @@ export async function activate() {
35
35
  }
36
36
  ```
37
37
 
38
+ ## Full API reference
39
+
40
+ 📘 **[Python Environments API reference](https://github.com/microsoft/vscode-python-environments/blob/main/docs/README.md)**
41
+
42
+ The complete manual documents every method and data type, organized by domain -
43
+ environments, packages, projects, execution, environment variables, and
44
+ extensibility - with field tables, parameter tables, return types, and examples.
45
+
46
+ - [Environments](https://github.com/microsoft/vscode-python-environments/blob/main/docs/README.md#environments) - discover, resolve, select, create, and remove interpreters
47
+ - [Packages](https://github.com/microsoft/vscode-python-environments/blob/main/docs/README.md#packages) - list, install, uninstall, and look up versions
48
+ - [Projects](https://github.com/microsoft/vscode-python-environments/blob/main/docs/README.md#projects) - the folders the extension tracks
49
+ - [Execution](https://github.com/microsoft/vscode-python-environments/blob/main/docs/README.md#execution) - run Python in terminals, tasks, and background processes
50
+ - [Environment variables](https://github.com/microsoft/vscode-python-environments/blob/main/docs/README.md#environment-variables) - resolved variables for a scope
51
+ - [Extensibility](https://github.com/microsoft/vscode-python-environments/blob/main/docs/README.md#extensibility) - register your own environment manager, package manager, or project creator
52
+
53
+ See [`CHANGELOG.md`](https://github.com/microsoft/vscode-python-environments/blob/main/api/CHANGELOG.md) for API changes between versions.
54
+
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ // Copyright (c) Microsoft Corporation. All rights reserved.
3
+ // Licensed under the MIT License.
4
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
5
+ if (k2 === undefined) k2 = k;
6
+ var desc = Object.getOwnPropertyDescriptor(m, k);
7
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
8
+ desc = { enumerable: true, get: function() { return m[k]; } };
9
+ }
10
+ Object.defineProperty(o, k2, desc);
11
+ }) : (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ o[k2] = m[k];
14
+ }));
15
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
17
+ };
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.PythonEnvironments = exports.EXTENSION_ID = void 0;
20
+ const vscode_1 = require("vscode");
21
+ /*
22
+ * Do not introduce any breaking changes to this API.
23
+ * This is the public API for other extensions to interact with the Python Environments extension.
24
+ *
25
+ * This module is a small public runtime/package facade: it re-exports all public type contracts
26
+ * from `./types` and the concrete error/guard from `./publicErrors`, and hosts the runtime surface
27
+ * (`EXTENSION_ID` and `PythonEnvironments.api()`).
28
+ */
29
+ __exportStar(require("./types.js"), exports);
30
+ __exportStar(require("./publicErrors.js"), exports);
31
+ exports.EXTENSION_ID = 'ms-python.vscode-python-envs';
32
+ var PythonEnvironments;
33
+ (function (PythonEnvironments) {
34
+ /**
35
+ * Returns the API exposed by the Python Environments extension in VS Code.
36
+ */
37
+ async function api() {
38
+ const extension = vscode_1.extensions.getExtension(exports.EXTENSION_ID);
39
+ if (extension === undefined) {
40
+ throw new Error(`Python Environments extension (${exports.EXTENSION_ID}) is not installed or is disabled`);
41
+ }
42
+ if (!extension.isActive) {
43
+ await extension.activate();
44
+ }
45
+ const api = extension.exports;
46
+ if (!api) {
47
+ throw new Error(`Python Environments extension (${exports.EXTENSION_ID}) did not expose its API. Ensure "python.useEnvironmentsExtension" is enabled and reload the window.`);
48
+ }
49
+ return api;
50
+ }
51
+ PythonEnvironments.api = api;
52
+ })(PythonEnvironments || (exports.PythonEnvironments = PythonEnvironments = {}));
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ // Copyright (c) Microsoft Corporation. All rights reserved.
3
+ // Licensed under the MIT License.
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.PackageVersionLookupNotSupportedError = void 0;
6
+ exports.isPackageVersionLookupNotSupportedError = isPackageVersionLookupNotSupportedError;
7
+ /*
8
+ * Concrete, public runtime error type(s) for the Python Environments API.
9
+ * Kept separate from `./types.ts` (pure contracts) and re-exported from `./api.ts` to keep
10
+ * that facade small.
11
+ */
12
+ /**
13
+ * Error thrown when a package manager cannot list available package versions.
14
+ *
15
+ * This distinguishes an *unsupported capability* from an *operational failure* (such as a
16
+ * failed command, a network error, or malformed/unparseable output). Consumers of
17
+ * {@link PythonPackageGetterApi.getPackageAvailableVersions} should treat this specific error
18
+ * as a signal to fall back to manual version entry, while letting any other error propagate.
19
+ *
20
+ * The {@link code} property carries a stable, string-literal discriminator so the error can be
21
+ * recognized reliably across extension bundle boundaries, where `instanceof` may fail because
22
+ * each bundle can load its own copy of this class. Prefer {@link isPackageVersionLookupNotSupportedError}
23
+ * over a bare `instanceof` check for that reason.
24
+ */
25
+ class PackageVersionLookupNotSupportedError extends Error {
26
+ constructor(message) {
27
+ super(message ?? 'The package manager does not support looking up available package versions.');
28
+ /**
29
+ * Stable discriminator identifying this error type across bundle boundaries.
30
+ */
31
+ this.code = 'PackageVersionLookupNotSupported';
32
+ this.name = 'PackageVersionLookupNotSupportedError';
33
+ // Preserve the prototype chain when this class is transpiled to older targets so that
34
+ // `instanceof` continues to work within a single bundle.
35
+ Object.setPrototypeOf(this, PackageVersionLookupNotSupportedError.prototype);
36
+ }
37
+ }
38
+ exports.PackageVersionLookupNotSupportedError = PackageVersionLookupNotSupportedError;
39
+ /**
40
+ * Type guard reporting whether an error represents unsupported package version lookup.
41
+ *
42
+ * Uses the stable {@link PackageVersionLookupNotSupportedError.code} discriminator, so it returns
43
+ * `true` even when the error crossed an extension bundle boundary and `instanceof` would fail.
44
+ *
45
+ * @param error The value to test.
46
+ * @returns `true` if `error` is a {@link PackageVersionLookupNotSupportedError} (or a structurally
47
+ * equivalent error carrying the same `code`).
48
+ */
49
+ function isPackageVersionLookupNotSupportedError(error) {
50
+ return (error instanceof PackageVersionLookupNotSupportedError ||
51
+ (typeof error === 'object' &&
52
+ error !== null &&
53
+ 'code' in error &&
54
+ error.code === 'PackageVersionLookupNotSupported'));
55
+ }
@@ -2,8 +2,7 @@
2
2
  // Copyright (c) Microsoft Corporation. All rights reserved.
3
3
  // Licensed under the MIT License.
4
4
  Object.defineProperty(exports, "__esModule", { value: true });
5
- exports.PythonEnvironments = exports.EXTENSION_ID = exports.PackageChangeKind = exports.EnvironmentChangeKind = void 0;
6
- const vscode_1 = require("vscode");
5
+ exports.PackageChangeKind = exports.EnvironmentChangeKind = void 0;
7
6
  /**
8
7
  * Enum representing the kinds of environment changes.
9
8
  */
@@ -32,23 +31,3 @@ var PackageChangeKind;
32
31
  */
33
32
  PackageChangeKind["remove"] = "remove";
34
33
  })(PackageChangeKind || (exports.PackageChangeKind = PackageChangeKind = {}));
35
- exports.EXTENSION_ID = 'ms-python.vscode-python-envs';
36
- // eslint-disable-next-line @typescript-eslint/no-namespace
37
- var PythonEnvironments;
38
- (function (PythonEnvironments) {
39
- /**
40
- * Returns the API exposed by the Python Environments extension in VS Code.
41
- */
42
- async function api() {
43
- const extension = vscode_1.extensions.getExtension(exports.EXTENSION_ID);
44
- if (extension === undefined) {
45
- throw new Error(`Python Environments extension is not installed or is disabled`);
46
- }
47
- if (!extension.isActive) {
48
- await extension.activate();
49
- }
50
- const pythonEnvsApi = extension.exports;
51
- return pythonEnvsApi;
52
- }
53
- PythonEnvironments.api = api;
54
- })(PythonEnvironments || (exports.PythonEnvironments = PythonEnvironments = {}));
@@ -0,0 +1,35 @@
1
+ // Copyright (c) Microsoft Corporation. All rights reserved.
2
+ // Licensed under the MIT License.
3
+ import { extensions } from 'vscode';
4
+ /*
5
+ * Do not introduce any breaking changes to this API.
6
+ * This is the public API for other extensions to interact with the Python Environments extension.
7
+ *
8
+ * This module is a small public runtime/package facade: it re-exports all public type contracts
9
+ * from `./types` and the concrete error/guard from `./publicErrors`, and hosts the runtime surface
10
+ * (`EXTENSION_ID` and `PythonEnvironments.api()`).
11
+ */
12
+ export * from './types.js';
13
+ export * from './publicErrors.js';
14
+ export const EXTENSION_ID = 'ms-python.vscode-python-envs';
15
+ export var PythonEnvironments;
16
+ (function (PythonEnvironments) {
17
+ /**
18
+ * Returns the API exposed by the Python Environments extension in VS Code.
19
+ */
20
+ async function api() {
21
+ const extension = extensions.getExtension(EXTENSION_ID);
22
+ if (extension === undefined) {
23
+ throw new Error(`Python Environments extension (${EXTENSION_ID}) is not installed or is disabled`);
24
+ }
25
+ if (!extension.isActive) {
26
+ await extension.activate();
27
+ }
28
+ const api = extension.exports;
29
+ if (!api) {
30
+ throw new Error(`Python Environments extension (${EXTENSION_ID}) did not expose its API. Ensure "python.useEnvironmentsExtension" is enabled and reload the window.`);
31
+ }
32
+ return api;
33
+ }
34
+ PythonEnvironments.api = api;
35
+ })(PythonEnvironments || (PythonEnvironments = {}));
@@ -0,0 +1 @@
1
+ {"type":"module"}
@@ -0,0 +1,50 @@
1
+ // Copyright (c) Microsoft Corporation. All rights reserved.
2
+ // Licensed under the MIT License.
3
+ /*
4
+ * Concrete, public runtime error type(s) for the Python Environments API.
5
+ * Kept separate from `./types.ts` (pure contracts) and re-exported from `./api.ts` to keep
6
+ * that facade small.
7
+ */
8
+ /**
9
+ * Error thrown when a package manager cannot list available package versions.
10
+ *
11
+ * This distinguishes an *unsupported capability* from an *operational failure* (such as a
12
+ * failed command, a network error, or malformed/unparseable output). Consumers of
13
+ * {@link PythonPackageGetterApi.getPackageAvailableVersions} should treat this specific error
14
+ * as a signal to fall back to manual version entry, while letting any other error propagate.
15
+ *
16
+ * The {@link code} property carries a stable, string-literal discriminator so the error can be
17
+ * recognized reliably across extension bundle boundaries, where `instanceof` may fail because
18
+ * each bundle can load its own copy of this class. Prefer {@link isPackageVersionLookupNotSupportedError}
19
+ * over a bare `instanceof` check for that reason.
20
+ */
21
+ export class PackageVersionLookupNotSupportedError extends Error {
22
+ constructor(message) {
23
+ super(message ?? 'The package manager does not support looking up available package versions.');
24
+ /**
25
+ * Stable discriminator identifying this error type across bundle boundaries.
26
+ */
27
+ this.code = 'PackageVersionLookupNotSupported';
28
+ this.name = 'PackageVersionLookupNotSupportedError';
29
+ // Preserve the prototype chain when this class is transpiled to older targets so that
30
+ // `instanceof` continues to work within a single bundle.
31
+ Object.setPrototypeOf(this, PackageVersionLookupNotSupportedError.prototype);
32
+ }
33
+ }
34
+ /**
35
+ * Type guard reporting whether an error represents unsupported package version lookup.
36
+ *
37
+ * Uses the stable {@link PackageVersionLookupNotSupportedError.code} discriminator, so it returns
38
+ * `true` even when the error crossed an extension bundle boundary and `instanceof` would fail.
39
+ *
40
+ * @param error The value to test.
41
+ * @returns `true` if `error` is a {@link PackageVersionLookupNotSupportedError} (or a structurally
42
+ * equivalent error carrying the same `code`).
43
+ */
44
+ export function isPackageVersionLookupNotSupportedError(error) {
45
+ return (error instanceof PackageVersionLookupNotSupportedError ||
46
+ (typeof error === 'object' &&
47
+ error !== null &&
48
+ 'code' in error &&
49
+ error.code === 'PackageVersionLookupNotSupported'));
50
+ }
@@ -0,0 +1,30 @@
1
+ // Copyright (c) Microsoft Corporation. All rights reserved.
2
+ // Licensed under the MIT License.
3
+ /**
4
+ * Enum representing the kinds of environment changes.
5
+ */
6
+ export var EnvironmentChangeKind;
7
+ (function (EnvironmentChangeKind) {
8
+ /**
9
+ * Indicates that an environment was added.
10
+ */
11
+ EnvironmentChangeKind["add"] = "add";
12
+ /**
13
+ * Indicates that an environment was removed.
14
+ */
15
+ EnvironmentChangeKind["remove"] = "remove";
16
+ })(EnvironmentChangeKind || (EnvironmentChangeKind = {}));
17
+ /**
18
+ * Enum representing the kinds of package changes.
19
+ */
20
+ export var PackageChangeKind;
21
+ (function (PackageChangeKind) {
22
+ /**
23
+ * Indicates that a package was added.
24
+ */
25
+ PackageChangeKind["add"] = "add";
26
+ /**
27
+ * Indicates that a package was removed.
28
+ */
29
+ PackageChangeKind["remove"] = "remove";
30
+ })(PackageChangeKind || (PackageChangeKind = {}));
@@ -0,0 +1,10 @@
1
+ import type { PythonEnvironmentApi } from './types.js';
2
+ export * from './types.js';
3
+ export * from './publicErrors.js';
4
+ export declare const EXTENSION_ID = "ms-python.vscode-python-envs";
5
+ export declare namespace PythonEnvironments {
6
+ /**
7
+ * Returns the API exposed by the Python Environments extension in VS Code.
8
+ */
9
+ function api(): Promise<PythonEnvironmentApi>;
10
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Error thrown when a package manager cannot list available package versions.
3
+ *
4
+ * This distinguishes an *unsupported capability* from an *operational failure* (such as a
5
+ * failed command, a network error, or malformed/unparseable output). Consumers of
6
+ * {@link PythonPackageGetterApi.getPackageAvailableVersions} should treat this specific error
7
+ * as a signal to fall back to manual version entry, while letting any other error propagate.
8
+ *
9
+ * The {@link code} property carries a stable, string-literal discriminator so the error can be
10
+ * recognized reliably across extension bundle boundaries, where `instanceof` may fail because
11
+ * each bundle can load its own copy of this class. Prefer {@link isPackageVersionLookupNotSupportedError}
12
+ * over a bare `instanceof` check for that reason.
13
+ */
14
+ export declare class PackageVersionLookupNotSupportedError extends Error {
15
+ /**
16
+ * Stable discriminator identifying this error type across bundle boundaries.
17
+ */
18
+ readonly code = "PackageVersionLookupNotSupported";
19
+ constructor(message?: string);
20
+ }
21
+ /**
22
+ * Type guard reporting whether an error represents unsupported package version lookup.
23
+ *
24
+ * Uses the stable {@link PackageVersionLookupNotSupportedError.code} discriminator, so it returns
25
+ * `true` even when the error crossed an extension bundle boundary and `instanceof` would fail.
26
+ *
27
+ * @param error The value to test.
28
+ * @returns `true` if `error` is a {@link PackageVersionLookupNotSupportedError} (or a structurally
29
+ * equivalent error carrying the same `code`).
30
+ */
31
+ export declare function isPackageVersionLookupNotSupportedError(error: unknown): error is PackageVersionLookupNotSupportedError;
@@ -1,4 +1,6 @@
1
- import { Disposable, Event, FileChangeType, LogOutputChannel, MarkdownString, TaskExecution, Terminal, TerminalOptions, ThemeIcon, Uri } from 'vscode';
1
+ import type { Pep440Version } from '@renovatebot/pep440';
2
+ import type { Disposable, Event, FileChangeType, LogOutputChannel, MarkdownString, RelativePattern, TaskExecution, Terminal, TerminalOptions, ThemeIcon, Uri } from 'vscode';
3
+ export type { Pep440Version } from '@renovatebot/pep440';
2
4
  /**
3
5
  * The path to an icon, or a theme-specific configuration of icons.
4
6
  */
@@ -274,6 +276,16 @@ export interface QuickCreateConfig {
274
276
  */
275
277
  readonly detail?: string;
276
278
  }
279
+ /**
280
+ * Options controlling environment removal.
281
+ */
282
+ export interface RemoveEnvironmentOptions {
283
+ /**
284
+ * When `true`, removes the environment without prompting for confirmation.
285
+ * Intended for automated or headless scenarios. Defaults to `false`.
286
+ */
287
+ runHeadless?: boolean;
288
+ }
277
289
  /**
278
290
  * Interface representing an environment manager.
279
291
  *
@@ -345,7 +357,7 @@ export interface EnvironmentManager {
345
357
  * Invoked to delete the given environment. Typical triggers include an explicit user
346
358
  * action (such as a "Delete Environment" command) and programmatic removal via the API.
347
359
  */
348
- remove?(environment: PythonEnvironment): Promise<void>;
360
+ remove?(environment: PythonEnvironment, options?: RemoveEnvironmentOptions): Promise<void>;
349
361
  /**
350
362
  * Refreshes the list of Python environments within the specified scope.
351
363
  * @param scope - The scope within which to refresh environments.
@@ -402,24 +414,21 @@ export interface EnvironmentManager {
402
414
  */
403
415
  onDidChangeEnvironment?: Event<DidChangeEnvironmentEventArgs>;
404
416
  /**
405
- * Resolves the specified Python environment. The environment can be either a {@link PythonEnvironment} or a {@link Uri} context.
417
+ * Resolves the Python environment associated with the specified URI context.
406
418
  *
407
- * This method is used to obtain a fully detailed {@link PythonEnvironment} object. The input can be:
408
- * - A {@link PythonEnvironment} object, which might be missing key details such as {@link PythonEnvironment.execInfo}.
409
- * - A {@link Uri} object, which typically represents either:
410
- * - A folder that contains the Python environment.
411
- * - The path to a Python executable.
419
+ * This method is used to obtain a fully detailed {@link PythonEnvironment} object. The input
420
+ * URI typically represents either a folder that contains the Python environment or the path to
421
+ * a Python executable.
412
422
  *
413
- * @param context - The context for resolving the environment, which can be a {@link PythonEnvironment} or a {@link Uri}.
423
+ * @param context - The URI context for resolving the environment.
414
424
  * @returns A promise that resolves to the fully detailed {@link PythonEnvironment}, or `undefined` if the environment cannot be resolved.
415
425
  *
416
426
  * @remarks
417
- * Called to turn a lightly-populated {@link PythonEnvironment} or a {@link Uri}
418
- * pointing at an interpreter or environment folder into a fully-populated
419
- * {@link PythonEnvironment} with complete {@link PythonEnvironment.execInfo}. Typical
420
- * triggers include the user manually selecting an interpreter path, resolving
421
- * `python.defaultInterpreterPath` at startup, and populating execution details before
422
- * launching Python.
427
+ * Called to turn a {@link Uri} pointing at an interpreter or environment folder into a
428
+ * fully-populated {@link PythonEnvironment} with complete {@link PythonEnvironment.execInfo}.
429
+ * Typical triggers include the user manually selecting an interpreter path, resolving
430
+ * `python.defaultInterpreterPath` at startup, and populating execution details before launching
431
+ * Python.
423
432
  */
424
433
  resolve(context: ResolveEnvironmentContext): Promise<PythonEnvironment | undefined>;
425
434
  /**
@@ -484,6 +493,10 @@ export interface PackageInfo {
484
493
  * The URIs associated with the package.
485
494
  */
486
495
  readonly uris?: readonly Uri[];
496
+ /**
497
+ * Whether the package is a transitive dependency.
498
+ */
499
+ readonly isTransitive?: boolean;
487
500
  }
488
501
  /**
489
502
  * Interface representing a package.
@@ -571,18 +584,79 @@ export interface PackageManager {
571
584
  /**
572
585
  * Retrieves the list of packages for the specified Python environment.
573
586
  * @param environment - The Python environment for which to retrieve packages.
587
+ * @param options - Optional settings for package retrieval.
574
588
  * @returns An array of packages, or undefined if the packages could not be retrieved.
575
589
  */
576
- getPackages(environment: PythonEnvironment): Promise<Package[] | undefined>;
590
+ getPackages(environment: PythonEnvironment, options?: GetPackagesOptions): Promise<Package[] | undefined>;
591
+ /**
592
+ * Returns additional filesystem patterns to watch for package install/uninstall changes.
593
+ *
594
+ * These patterns are appended to the default site-packages metadata locations.
595
+ * Implement this for manager-specific locations (for example, conda-meta).
596
+ *
597
+ * @param environment - The Python environment whose package paths should be watched.
598
+ * @returns Relative patterns to watch for package changes.
599
+ */
600
+ getPackageWatchTargets?(environment: PythonEnvironment): RelativePattern[];
577
601
  /**
578
602
  * Event that is fired when packages change.
579
603
  */
580
604
  onDidChangePackages?: Event<DidChangePackagesEventArgs>;
605
+ /**
606
+ * Fetches the names of direct (non-transitive) packages for the specified Python environment.
607
+ *
608
+ * **Caveat:** Most package managers cannot track user install intent. For pip, this uses
609
+ * `pip list --not-required` which returns packages with no installed dependents (leaf packages),
610
+ * not necessarily packages the user explicitly installed. For example, if a user runs
611
+ * `pip install flask werkzeug`, werkzeug will still be reported as transitive because flask
612
+ * depends on it. This is a best-effort approximation.
613
+ *
614
+ * @param environment - The Python environment for which to fetch direct package names.
615
+ * @returns A promise that resolves to a set of package name strings, or undefined if not supported.
616
+ */
617
+ getDirectPackageNames?(environment: PythonEnvironment): Promise<Set<string> | undefined>;
581
618
  /**
582
619
  * Clears the package manager's cache.
583
620
  * @returns A promise that resolves when the cache is cleared.
584
621
  */
585
622
  clearCache?(): Promise<void>;
623
+ /**
624
+ * Returns the version of the underlying package management tool (e.g., pip, uv, conda).
625
+ * @param environment - The Python environment context.
626
+ * @returns A promise that resolves to a {@link Pep440Version} object, or `undefined` if not available.
627
+ */
628
+ getVersion?(environment: PythonEnvironment): Promise<Pep440Version | undefined>;
629
+ /**
630
+ * Retrieves the list of available versions for a given package, newest first.
631
+ *
632
+ * Implementations should:
633
+ * - resolve to an array of {@link Pep440Version} objects on success;
634
+ * - throw a {@link PackageVersionLookupNotSupportedError} when this manager cannot look up
635
+ * versions at all (an unsupported capability);
636
+ * - let operational failures (command, network, or malformed/unparseable output) propagate
637
+ * instead of swallowing them into `undefined`.
638
+ *
639
+ * Resolving to `undefined` is treated by callers as an unsupported capability, equivalent to
640
+ * throwing {@link PackageVersionLookupNotSupportedError}.
641
+ *
642
+ * @param environment - The Python environment context for the lookup.
643
+ * @param packageName - The name of the package to look up.
644
+ * @returns A promise that resolves to an array of {@link Pep440Version} objects (newest first).
645
+ * @throws {@link PackageVersionLookupNotSupportedError} when version lookup is unsupported.
646
+ */
647
+ getPackageAvailableVersions?(environment: PythonEnvironment, packageName: string): Promise<Pep440Version[] | undefined>;
648
+ /**
649
+ * Formats a versioned install specification for this package manager.
650
+ *
651
+ * Different package managers use different syntax (e.g. pip uses `name==version`,
652
+ * conda uses `name=version`). Implement this method to return the correct format.
653
+ * When absent, callers should default to `name==version`.
654
+ *
655
+ * @param packageName - The name of the package.
656
+ * @param version - The version string.
657
+ * @returns The install specification string (e.g. `"requests==2.31.0"` or `"requests=2.31.0"`).
658
+ */
659
+ formatInstallSpec?(packageName: string, version: string): string;
586
660
  }
587
661
  /**
588
662
  * Interface representing a Python project.
@@ -670,7 +744,30 @@ export interface DidChangePythonProjectsEventArgs {
670
744
  */
671
745
  removed: PythonProject[];
672
746
  }
673
- export type PackageManagementOptions = {
747
+ /**
748
+ * Options for retrieving packages from a package manager.
749
+ */
750
+ export interface GetPackagesOptions {
751
+ /**
752
+ * When `true`, bypasses the cache and fetches the latest packages from the underlying tool.
753
+ * Defaults to `false`.
754
+ */
755
+ skipCache?: boolean;
756
+ }
757
+ /**
758
+ * Options controlling user interaction during package management operations.
759
+ */
760
+ export interface PackageManagementInteractionOptions {
761
+ /**
762
+ * When `true`, the package management operation runs without any user prompts or
763
+ * interaction and relies solely on the packages provided in the options. Any step
764
+ * that would normally require user input — such as selecting packages to install
765
+ * when none are specified — is skipped instead of prompting the user. Intended for
766
+ * automated or headless scenarios such as integration tests. Defaults to `false`.
767
+ */
768
+ runHeadless?: boolean;
769
+ }
770
+ export type PackageManagementOptions = PackageManagementInteractionOptions & ({
674
771
  /**
675
772
  * Upgrade the packages if they are already installed.
676
773
  */
@@ -704,7 +801,7 @@ export type PackageManagementOptions = {
704
801
  * The list of packages to uninstall.
705
802
  */
706
803
  uninstall: string[];
707
- };
804
+ });
708
805
  /**
709
806
  * Options for creating a Python environment.
710
807
  */
@@ -758,9 +855,8 @@ export interface PythonEnvironmentManagerRegistrationApi {
758
855
  *
759
856
  * @param manager Environment Manager implementation to register.
760
857
  * @param options Optional registration options.
761
- * @param options.extensionId The extension ID of the calling extension. This is used as a fallback when
762
- * automatic extension detection fails, such as during F5 debugging where the extension's file path
763
- * does not contain its marketplace ID. If automatic detection succeeds, this value is ignored.
858
+ * @param options.extensionId The extension ID of the calling extension. When this is not specified,
859
+ * or when the specified extension cannot be found, the extension ID will be automatically detected.
764
860
  * @returns A disposable that can be used to unregister the environment manager.
765
861
  * @see {@link EnvironmentManager}
766
862
  */
@@ -792,9 +888,10 @@ export interface PythonEnvironmentManagementApi {
792
888
  * Remove a Python environment.
793
889
  *
794
890
  * @param environment The Python environment to remove.
891
+ * @param options Optional parameters controlling environment removal.
795
892
  * @returns A promise that resolves when the environment has been removed.
796
893
  */
797
- removeEnvironment(environment: PythonEnvironment): Promise<void>;
894
+ removeEnvironment(environment: PythonEnvironment, options?: RemoveEnvironmentOptions): Promise<void>;
798
895
  }
799
896
  export interface PythonEnvironmentsApi {
800
897
  /**
@@ -815,10 +912,10 @@ export interface PythonEnvironmentsApi {
815
912
  */
816
913
  onDidChangeEnvironments: Event<DidChangeEnvironmentsEventArgs>;
817
914
  /**
818
- * This method is used to get the details missing from a PythonEnvironment. Like
819
- * {@link PythonEnvironment.execInfo} and other details.
915
+ * This method is used to get the details for the Python environment associated with a URI
916
+ * context, such as an interpreter path or environment folder.
820
917
  *
821
- * @param context : The PythonEnvironment or Uri for which details are required.
918
+ * @param context - The URI context for which environment details are required.
822
919
  */
823
920
  resolveEnvironment(context: ResolveEnvironmentContext): Promise<PythonEnvironment | undefined>;
824
921
  }
@@ -849,9 +946,8 @@ export interface PythonPackageManagerRegistrationApi {
849
946
  *
850
947
  * @param manager Package Manager implementation to register.
851
948
  * @param options Optional registration options.
852
- * @param options.extensionId The extension ID of the calling extension. This is used as a fallback when
853
- * automatic extension detection fails, such as during F5 debugging where the extension's file path
854
- * does not contain its marketplace ID. If automatic detection succeeds, this value is ignored.
949
+ * @param options.extensionId The extension ID of the calling extension. When this is not specified,
950
+ * or when the specified extension cannot be found, the extension ID will be automatically detected.
855
951
  * @returns A disposable that can be used to unregister the package manager.
856
952
  * @see {@link PackageManager}
857
953
  */
@@ -859,6 +955,21 @@ export interface PythonPackageManagerRegistrationApi {
859
955
  extensionId?: string;
860
956
  }): Disposable;
861
957
  }
958
+ /**
959
+ * Controls how package version lookup failures are reported.
960
+ */
961
+ export interface GetPackageAvailableVersionsOptions {
962
+ /**
963
+ * Determines whether lookup failures preserve the legacy `undefined` result or reject.
964
+ *
965
+ * - `legacy` resolves to `undefined` for unsupported lookups and operational failures.
966
+ * This remains the default for backward compatibility, but may be removed in a future
967
+ * major API version.
968
+ * - `throw` rejects with {@link PackageVersionLookupNotSupportedError} for unsupported
969
+ * lookups and propagates operational failures unchanged.
970
+ */
971
+ errorMode?: 'legacy' | 'throw';
972
+ }
862
973
  export interface PythonPackageGetterApi {
863
974
  /**
864
975
  * Refresh the list of packages in a Python Environment.
@@ -871,9 +982,28 @@ export interface PythonPackageGetterApi {
871
982
  * Get the list of packages in a Python Environment.
872
983
  *
873
984
  * @param environment The Python Environment for which the list of packages is required.
985
+ * @param options Optional settings for package retrieval.
874
986
  * @returns The list of packages in the Python Environment.
875
987
  */
876
- getPackages(environment: PythonEnvironment): Promise<Package[] | undefined>;
988
+ getPackages(environment: PythonEnvironment, options?: GetPackagesOptions): Promise<Package[] | undefined>;
989
+ /**
990
+ * Get the list of available versions for a package, newest first.
991
+ *
992
+ * By default, this preserves the legacy behavior of resolving to `undefined` for unsupported
993
+ * lookups and operational failures. Pass `{ errorMode: 'throw' }` to distinguish unsupported
994
+ * capabilities from operational failures: unsupported lookups reject with
995
+ * {@link PackageVersionLookupNotSupportedError}, while other failures propagate unchanged.
996
+ *
997
+ * @param environment The Python Environment context for the lookup.
998
+ * @param packageName The name of the package to look up.
999
+ * @param options Controls how lookup failures are reported.
1000
+ * @returns A promise that resolves to an array of {@link Pep440Version} objects (newest first),
1001
+ * or `undefined` in legacy mode when lookup is unsupported or fails.
1002
+ */
1003
+ getPackageAvailableVersions(environment: PythonEnvironment, packageName: string, options: GetPackageAvailableVersionsOptions & {
1004
+ errorMode: 'throw';
1005
+ }): Promise<Pep440Version[]>;
1006
+ getPackageAvailableVersions(environment: PythonEnvironment, packageName: string, options?: GetPackageAvailableVersionsOptions): Promise<Pep440Version[] | undefined>;
877
1007
  /**
878
1008
  * Event raised when the list of packages in a Python Environment changes.
879
1009
  * @see {@link DidChangePackagesEventArgs}
@@ -1079,7 +1209,9 @@ export interface PythonBackgroundRunOptions {
1079
1209
  */
1080
1210
  args: string[];
1081
1211
  /**
1082
- * Current working directory for the script or module. Default is the project directory for the script being run.
1212
+ * Current working directory for the script or module. This is passed directly to the spawned
1213
+ * process; when it is omitted the process inherits the extension host's working directory,
1214
+ * which is not the project directory. Supply this when the script resolves relative paths.
1083
1215
  */
1084
1216
  cwd?: string;
1085
1217
  /**
@@ -1143,10 +1275,3 @@ export interface PythonEnvironmentVariablesApi {
1143
1275
  */
1144
1276
  export interface PythonEnvironmentApi extends PythonEnvironmentManagerApi, PythonPackageManagerApi, PythonProjectApi, PythonExecutionApi, PythonEnvironmentVariablesApi {
1145
1277
  }
1146
- export declare const EXTENSION_ID = "ms-python.vscode-python-envs";
1147
- export declare namespace PythonEnvironments {
1148
- /**
1149
- * Returns the API exposed by the Python Environments extension in VS Code.
1150
- */
1151
- function api(): Promise<PythonEnvironmentApi>;
1152
- }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vscode/python-environments",
3
3
  "description": "An API facade for the Python Environments extension in VS Code",
4
- "version": "1.0.0",
4
+ "version": "1.4.0",
5
5
  "author": {
6
6
  "name": "Microsoft Corporation"
7
7
  },
@@ -11,8 +11,18 @@
11
11
  "API",
12
12
  "Environments"
13
13
  ],
14
- "main": "./out/main.js",
15
- "types": "./out/main.d.ts",
14
+ "main": "./out/cjs/main.cjs",
15
+ "types": "./out/types/main.d.ts",
16
+ "exports": {
17
+ "import": {
18
+ "types": "./out/types/main.d.ts",
19
+ "default": "./out/esm/main.mjs"
20
+ },
21
+ "require": {
22
+ "types": "./out/types/main.d.ts",
23
+ "default": "./out/cjs/main.cjs"
24
+ }
25
+ },
16
26
  "engines": {
17
27
  "node": ">=22.21.1",
18
28
  "vscode": "^1.110.0"
@@ -29,13 +39,23 @@
29
39
  "scripts": {
30
40
  "prepublishOnly": "echo \"⛔ Can only publish from a secure pipeline ⛔\" && node -e \"process.exitCode = 1\"",
31
41
  "prepack": "npm run all:publish",
32
- "all:publish": "git clean -xfd . && npm install && npm run compile",
33
- "compile": "tsc -b ./tsconfig.json",
34
- "clean": "node -e \"const fs = require('fs'); fs.rmSync('./out', { recursive: true, force: true });\""
42
+ "all:publish": "git clean -xfd . && npm install && npm run copy:sources && npm run compile",
43
+ "copy:sources": "node ./scripts/copy-sources.cjs",
44
+ "compile": "npm run clean && npm run compile:types && npm run compile:esm && npm run compile:cjs",
45
+ "compile:types": "tsc -b ./tsconfig.types.json",
46
+ "compile:esm": "tsc -b ./tsconfig.esm.json && mve out/esm/main.js out/esm/main.mjs && node -e \"require('fs').writeFileSync('out/esm/package.json', '{\\\"type\\\":\\\"module\\\"}')\"",
47
+ "compile:cjs": "tsc -b ./tsconfig.cjs.json && mve out/cjs/main.js out/cjs/main.cjs",
48
+ "clean": "node -e \"const fs = require('fs'); fs.rmSync('./out', { recursive: true, force: true });\"",
49
+ "test": "npm run test:package",
50
+ "test:package": "node ./scripts/test-package.cjs"
35
51
  },
36
52
  "devDependencies": {
37
53
  "@types/node": "^22.0.0",
38
54
  "@types/vscode": "^1.99.0",
55
+ "mve": "^0.1.2",
39
56
  "typescript": "^5.1.3"
57
+ },
58
+ "dependencies": {
59
+ "@renovatebot/pep440": "^3.1.0"
40
60
  }
41
61
  }