Skip to content

Commit c18e8c9

Browse files
authored
Detect ActiveState Python runtimes (#20534)
Closes #20532
1 parent 2152cd9 commit c18e8c9

File tree

28 files changed

+369
-5
lines changed

28 files changed

+369
-5
lines changed

package.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,12 @@
376376
],
377377
"configuration": {
378378
"properties": {
379+
"python.activeStateToolPath": {
380+
"default": "state",
381+
"description": "%python.activeStateToolPath.description%",
382+
"scope": "machine-overridable",
383+
"type": "string"
384+
},
379385
"python.autoComplete.extraPaths": {
380386
"default": [],
381387
"description": "%python.autoComplete.extraPaths.description%",

package.nls.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"python.command.python.launchTensorBoard.title": "Launch TensorBoard",
2626
"python.command.python.refreshTensorBoard.title": "Refresh TensorBoard",
2727
"python.menu.createNewFile.title": "Python File",
28+
"python.activeStateToolPath.description": "Path to the State Tool executable for ActiveState runtimes (version 0.36+).",
2829
"python.autoComplete.extraPaths.description": "List of paths to libraries and the like that need to be imported by auto complete engine. E.g. when using Google App SDK, the paths are not in system path, hence need to be added into this list.",
2930
"python.condaPath.description": "Path to the conda executable to use for activation (version 4.4+).",
3031
"python.defaultInterpreterPath.description": "Path to default Python to use when extension loads up for the first time, no longer used once an interpreter is selected for the workspace. See [here](https://aka.ms/AAfekmf) to understand when this is used",

resources/report_issue_user_settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"envFile": "placeholder",
88
"venvPath": "placeholder",
99
"venvFolders": "placeholder",
10+
"activeStateToolPath": "placeholder",
1011
"condaPath": "placeholder",
1112
"pipenvPath": "placeholder",
1213
"poetryPath": "placeholder",

src/client/common/configSettings.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ export class PythonSettings implements IPythonSettings {
9898

9999
public venvFolders: string[] = [];
100100

101+
public activeStateToolPath = '';
102+
101103
public condaPath = '';
102104

103105
public pipenvPath = '';
@@ -254,6 +256,11 @@ export class PythonSettings implements IPythonSettings {
254256

255257
this.venvPath = systemVariables.resolveAny(pythonSettings.get<string>('venvPath'))!;
256258
this.venvFolders = systemVariables.resolveAny(pythonSettings.get<string[]>('venvFolders'))!;
259+
const activeStateToolPath = systemVariables.resolveAny(pythonSettings.get<string>('activeStateToolPath'))!;
260+
this.activeStateToolPath =
261+
activeStateToolPath && activeStateToolPath.length > 0
262+
? getAbsolutePath(activeStateToolPath, workspaceRoot)
263+
: activeStateToolPath;
257264
const condaPath = systemVariables.resolveAny(pythonSettings.get<string>('condaPath'))!;
258265
this.condaPath = condaPath && condaPath.length > 0 ? getAbsolutePath(condaPath, workspaceRoot) : condaPath;
259266
const pipenvPath = systemVariables.resolveAny(pythonSettings.get<string>('pipenvPath'))!;

src/client/common/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ export interface IPythonSettings {
184184
readonly pythonPath: string;
185185
readonly venvPath: string;
186186
readonly venvFolders: string[];
187+
readonly activeStateToolPath: string;
187188
readonly condaPath: string;
188189
readonly pipenvPath: string;
189190
readonly poetryPath: string;

src/client/interpreter/configuration/environmentTypeComparer.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import { injectable, inject } from 'inversify';
55
import { Resource } from '../../common/types';
66
import { Architecture } from '../../common/utils/platform';
7+
import { isActiveStateEnvironmentForWorkspace } from '../../pythonEnvironments/common/environmentManagers/activestate';
78
import { isParentPath } from '../../pythonEnvironments/common/externalDependencies';
89
import { EnvironmentType, PythonEnvironment, virtualEnvTypes } from '../../pythonEnvironments/info';
910
import { PythonVersion } from '../../pythonEnvironments/info/pythonVersion';
@@ -93,6 +94,14 @@ export class EnvironmentTypeComparer implements IInterpreterComparer {
9394
if (isProblematicCondaEnvironment(i)) {
9495
return false;
9596
}
97+
if (
98+
i.envType === EnvironmentType.ActiveState &&
99+
(!i.path ||
100+
!workspaceUri ||
101+
!isActiveStateEnvironmentForWorkspace(i.path, workspaceUri.folderUri.fsPath))
102+
) {
103+
return false;
104+
}
96105
if (getEnvLocationHeuristic(i, workspaceUri?.folderUri.fsPath || '') === EnvLocationHeuristic.Local) {
97106
return true;
98107
}
@@ -237,6 +246,7 @@ function getPrioritizedEnvironmentType(): EnvironmentType[] {
237246
EnvironmentType.VirtualEnvWrapper,
238247
EnvironmentType.Venv,
239248
EnvironmentType.VirtualEnv,
249+
EnvironmentType.ActiveState,
240250
EnvironmentType.Conda,
241251
EnvironmentType.Pyenv,
242252
EnvironmentType.MicrosoftStore,

src/client/interpreter/configuration/interpreterSelector/commands/setInterpreter.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ export namespace EnvGroups {
7575
export const Venv = 'Venv';
7676
export const Poetry = 'Poetry';
7777
export const VirtualEnvWrapper = 'VirtualEnvWrapper';
78+
export const ActiveState = 'ActiveState';
7879
export const Recommended = Common.recommended;
7980
}
8081

src/client/pythonEnvironments/base/info/envKind.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export function getKindDisplayName(kind: PythonEnvKind): string {
2222
[PythonEnvKind.VirtualEnvWrapper, 'virtualenv'],
2323
[PythonEnvKind.Pipenv, 'pipenv'],
2424
[PythonEnvKind.Conda, 'conda'],
25+
[PythonEnvKind.ActiveState, 'ActiveState'],
2526
// For now we treat OtherVirtual like Unknown.
2627
] as [PythonEnvKind, string][]) {
2728
if (kind === candidate) {
@@ -63,6 +64,7 @@ export function getPrioritizedEnvKinds(): PythonEnvKind[] {
6364
PythonEnvKind.Venv,
6465
PythonEnvKind.VirtualEnvWrapper,
6566
PythonEnvKind.VirtualEnv,
67+
PythonEnvKind.ActiveState,
6668
PythonEnvKind.OtherVirtual,
6769
PythonEnvKind.OtherGlobal,
6870
PythonEnvKind.System,

src/client/pythonEnvironments/base/info/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export enum PythonEnvKind {
1515
MicrosoftStore = 'global-microsoft-store',
1616
Pyenv = 'global-pyenv',
1717
Poetry = 'poetry',
18+
ActiveState = 'activestate',
1819
Custom = 'global-custom',
1920
OtherGlobal = 'global-other',
2021
// "virtual"

src/client/pythonEnvironments/base/locators/composite/resolverUtils.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import { parseVersionFromExecutable } from '../../info/executable';
3030
import { traceError, traceWarn } from '../../../../logging';
3131
import { isVirtualEnvironment } from '../../../common/environmentManagers/simplevirtualenvs';
3232
import { getWorkspaceFolderPaths } from '../../../../common/vscodeApis/workspaceApis';
33+
import { ActiveState } from '../../../common/environmentManagers/activestate';
3334

3435
function getResolvers(): Map<PythonEnvKind, (env: BasicEnvInfo) => Promise<PythonEnvInfo>> {
3536
const resolvers = new Map<PythonEnvKind, (_: BasicEnvInfo) => Promise<PythonEnvInfo>>();
@@ -42,6 +43,7 @@ function getResolvers(): Map<PythonEnvKind, (env: BasicEnvInfo) => Promise<Pytho
4243
resolvers.set(PythonEnvKind.Conda, resolveCondaEnv);
4344
resolvers.set(PythonEnvKind.MicrosoftStore, resolveMicrosoftStoreEnv);
4445
resolvers.set(PythonEnvKind.Pyenv, resolvePyenvEnv);
46+
resolvers.set(PythonEnvKind.ActiveState, resolveActiveStateEnv);
4547
return resolvers;
4648
}
4749

@@ -247,6 +249,25 @@ async function resolvePyenvEnv(env: BasicEnvInfo): Promise<PythonEnvInfo> {
247249
return envInfo;
248250
}
249251

252+
async function resolveActiveStateEnv(env: BasicEnvInfo): Promise<PythonEnvInfo> {
253+
const info = buildEnvInfo({
254+
kind: env.kind,
255+
executable: env.executablePath,
256+
});
257+
const projects = await ActiveState.getState().then((v) => v?.getProjects());
258+
if (projects) {
259+
for (const project of projects) {
260+
for (const dir of project.executables) {
261+
if (arePathsSame(dir, path.dirname(env.executablePath))) {
262+
info.name = `${project.organization}/${project.name}`;
263+
return info;
264+
}
265+
}
266+
}
267+
}
268+
return info;
269+
}
270+
250271
async function isBaseCondaPyenvEnvironment(executablePath: string) {
251272
if (!(await isCondaEnvironment(executablePath))) {
252273
return false;

0 commit comments

Comments
 (0)