Skip to content

Commit

Permalink
Ensure env manager context is available to use by extensions (#100)
Browse files Browse the repository at this point in the history
Closes #94
  • Loading branch information
karthiknadig authored Jan 6, 2025
1 parent 6bc409d commit 3dee5e9
Show file tree
Hide file tree
Showing 4 changed files with 261 additions and 48 deletions.
6 changes: 3 additions & 3 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
"preLaunchTask": "${defaultBuildTask}"
},
{
"name": "Unit Tests",
"type": "node",
"request": "launch",
"args": [
"-u=tdd",
"--timeout=180000",
Expand All @@ -24,12 +27,9 @@
"./out/test/**/*.unit.test.js"
],
"internalConsoleOptions": "openOnSessionStart",
"name": "Unit Tests",
"program": "${workspaceFolder}/node_modules/mocha/bin/_mocha",
"request": "launch",
"skipFiles": ["<node_internals>/**"],
"outFiles": ["${workspaceFolder}/out/**/*.js", "!${workspaceFolder}/**/node_modules**/*"],
"type": "node",
"preLaunchTask": "tasks: watch-tests"
},
{
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -278,11 +278,11 @@
{
"command": "python-envs.create",
"group": "inline",
"when": "view == env-managers && viewItem =~ /.*pythonEnvManager.*-create.*/"
"when": "view == env-managers && viewItem =~ /.*pythonEnvManager.*;create;.*/"
},
{
"command": "python-envs.remove",
"when": "view == env-managers && viewItem =~ /.*pythonEnvironment.*-remove.*/"
"when": "view == env-managers && viewItem =~ /.*pythonEnvironment.*;remove;.*/"
},
{
"command": "python-envs.setEnv",
Expand All @@ -297,7 +297,7 @@
{
"command": "python-envs.createTerminal",
"group": "inline",
"when": "view == env-managers && viewItem =~ /.*pythonEnvironment.*activatable.*/"
"when": "view == env-managers && viewItem =~ /.*pythonEnvironment.*;activatable;.*/"
},
{
"command": "python-envs.refreshPackages",
Expand Down
56 changes: 14 additions & 42 deletions src/features/views/treeViewItems.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { TreeItem, TreeItemCollapsibleState, MarkdownString, Command, ThemeIcon, Uri } from 'vscode';
import { TreeItem, TreeItemCollapsibleState, MarkdownString, Command, ThemeIcon } from 'vscode';
import { InternalEnvironmentManager, InternalPackageManager } from '../../internal.api';
import { PythonEnvironment, IconPath, Package, PythonProject } from '../../api';
import { removable } from './utils';
Expand Down Expand Up @@ -31,52 +31,34 @@ export class EnvManagerTreeItem implements EnvTreeItem {
item.contextValue = this.getContextValue();
item.description = manager.description;
item.tooltip = manager.tooltip;
this.setIcon(item);
item.iconPath = manager.iconPath;
this.treeItem = item;
}

private getContextValue() {
const create = this.manager.supportsCreate ? '-create' : '';
return `pythonEnvManager${create}`;
}

private setIcon(item: TreeItem) {
const iconPath = this.manager.iconPath;
if (iconPath instanceof Uri && iconPath.fsPath.endsWith('__icon__.py')) {
item.resourceUri = iconPath;
item.iconPath = ThemeIcon.File;
} else {
item.iconPath = iconPath;
}
const create = this.manager.supportsCreate ? 'create' : '';
const parts = ['pythonEnvManager', create, this.manager.id].filter(Boolean);
return parts.join(';') + ';';
}
}

export class PythonEnvTreeItem implements EnvTreeItem {
public readonly kind = EnvTreeItemKind.environment;
public readonly treeItem: TreeItem;
constructor(public readonly environment: PythonEnvironment, public readonly parent: EnvManagerTreeItem) {
const item = new TreeItem(environment.displayName ?? environment.name, TreeItemCollapsibleState.Collapsed);
const item = new TreeItem(environment.displayName, TreeItemCollapsibleState.Collapsed);
item.contextValue = this.getContextValue();
item.description = environment.description;
item.tooltip = environment.tooltip;
this.setIcon(item);
item.iconPath = environment.iconPath;
this.treeItem = item;
}

private getContextValue() {
const activatable = isActivatableEnvironment(this.environment) ? '-activatable' : '';
const remove = this.parent.manager.supportsRemove ? '-remove' : '';
return `pythonEnvironment${remove}${activatable}`;
}

private setIcon(item: TreeItem) {
const iconPath = this.environment.iconPath;
if (iconPath instanceof Uri && iconPath.fsPath.endsWith('__icon__.py')) {
item.resourceUri = iconPath;
item.iconPath = ThemeIcon.File;
} else {
item.iconPath = iconPath;
}
const activatable = isActivatableEnvironment(this.environment) ? 'activatable' : '';
const remove = this.parent.manager.supportsRemove ? 'remove' : '';
const parts = ['pythonEnvironment', remove, activatable].filter(Boolean);
return parts.join(';') + ';';
}
}

Expand Down Expand Up @@ -244,31 +226,21 @@ export class ProjectEnvironment implements ProjectTreeItem {
public readonly id: string;
public readonly treeItem: TreeItem;
constructor(public readonly parent: ProjectItem, public readonly environment: PythonEnvironment) {
this.id = ProjectEnvironment.getId(parent, environment);
this.id = this.getId(parent, environment);
const item = new TreeItem(
this.environment.displayName ?? this.environment.name,
TreeItemCollapsibleState.Collapsed,
);
item.contextValue = 'python-env';
item.description = this.environment.description;
item.tooltip = this.environment.tooltip;
this.setIcon(item);
item.iconPath = this.environment.iconPath;
this.treeItem = item;
}

static getId(workspace: ProjectItem, environment: PythonEnvironment): string {
getId(workspace: ProjectItem, environment: PythonEnvironment): string {
return `${workspace.id}>>>${environment.envId}`;
}

private setIcon(item: TreeItem) {
const iconPath = this.environment.iconPath;
if (iconPath instanceof Uri && iconPath.fsPath.endsWith('__icon__.py')) {
item.resourceUri = iconPath;
item.iconPath = ThemeIcon.File;
} else {
item.iconPath = iconPath;
}
}
}

export class NoProjectEnvironment implements ProjectTreeItem {
Expand Down
241 changes: 241 additions & 0 deletions src/test/features/views/treeViewItems.unit.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
import * as assert from 'assert';
import { EnvManagerTreeItem, PythonEnvTreeItem } from '../../../features/views/treeViewItems';
import { InternalEnvironmentManager, PythonEnvironmentImpl } from '../../../internal.api';
import { Uri } from 'vscode';

suite('Test TreeView Items', () => {
suite('EnvManagerTreeItem', () => {
test('Context Value: no-create', () => {
const manager = new InternalEnvironmentManager('ms-python.python:test-manager', {
name: 'test',
description: 'test',
preferredPackageManagerId: 'pip',
refresh: () => Promise.resolve(),
getEnvironments: () => Promise.resolve([]),
resolve: () => Promise.resolve(undefined),
set: () => Promise.resolve(),
get: () => Promise.resolve(undefined),
});
const item = new EnvManagerTreeItem(manager);
assert.equal(item.treeItem.contextValue, 'pythonEnvManager;ms-python.python:test-manager;');
});

test('Context Value: with create', () => {
const manager = new InternalEnvironmentManager('ms-python.python:test-manager', {
name: 'test',
description: 'test',
preferredPackageManagerId: 'pip',
refresh: () => Promise.resolve(),
getEnvironments: () => Promise.resolve([]),
resolve: () => Promise.resolve(undefined),
set: () => Promise.resolve(),
get: () => Promise.resolve(undefined),
create: () => Promise.resolve(undefined),
});
const item = new EnvManagerTreeItem(manager);
assert.equal(item.treeItem.contextValue, 'pythonEnvManager;create;ms-python.python:test-manager;');
});

test('Name is used', () => {
const manager = new InternalEnvironmentManager('ms-python.python:test-manager', {
name: 'test',
description: 'test',
preferredPackageManagerId: 'pip',
refresh: () => Promise.resolve(),
getEnvironments: () => Promise.resolve([]),
resolve: () => Promise.resolve(undefined),
set: () => Promise.resolve(),
get: () => Promise.resolve(undefined),
});
const item = new EnvManagerTreeItem(manager);
assert.equal(item.treeItem.label, manager.name);
});

test('DisplayName is used', () => {
const manager = new InternalEnvironmentManager('ms-python.python:test-manager', {
name: 'test',
displayName: 'Test',
description: 'test',
preferredPackageManagerId: 'pip',
refresh: () => Promise.resolve(),
getEnvironments: () => Promise.resolve([]),
resolve: () => Promise.resolve(undefined),
set: () => Promise.resolve(),
get: () => Promise.resolve(undefined),
});
const item = new EnvManagerTreeItem(manager);
assert.equal(item.treeItem.label, manager.displayName);
});
});

suite('PythonEnvTreeItem', () => {
const manager1 = new InternalEnvironmentManager('ms-python.python:test-manager', {
name: 'test',
displayName: 'Test',
description: 'test',
preferredPackageManagerId: 'pip',
refresh: () => Promise.resolve(),
getEnvironments: () => Promise.resolve([]),
resolve: () => Promise.resolve(undefined),
set: () => Promise.resolve(),
get: () => Promise.resolve(undefined),
});
const managerItem1 = new EnvManagerTreeItem(manager1);

const manager2 = new InternalEnvironmentManager('ms-python.python:test-manager', {
name: 'test',
displayName: 'Test',
description: 'test',
preferredPackageManagerId: 'pip',
refresh: () => Promise.resolve(),
getEnvironments: () => Promise.resolve([]),
resolve: () => Promise.resolve(undefined),
set: () => Promise.resolve(),
get: () => Promise.resolve(undefined),
create: () => Promise.resolve(undefined),
remove: () => Promise.resolve(),
});
const managerItem2 = new EnvManagerTreeItem(manager2);

test('Context Value: no-remove, no-activate', () => {
const env = new PythonEnvironmentImpl(
{
id: 'test-env',
managerId: manager1.id,
},
{
name: 'test-env',
displayName: 'Test Env',
description: 'This is test environment',
displayPath: '/home/user/envs/.venv/bin/python',
version: '3.12.1',
environmentPath: Uri.file('/home/user/envs/.venv/bin/python'),
execInfo: {
run: {
executable: '/home/user/envs/.venv/bin/python',
},
},
sysPrefix: '/home/user/envs/.venv',
},
);

const item = new PythonEnvTreeItem(env, managerItem1);
assert.equal(item.treeItem.contextValue, 'pythonEnvironment;');
});

test('Context Value: no-remove, with activate', () => {
const env = new PythonEnvironmentImpl(
{
id: 'test-env',
managerId: manager1.id,
},
{
name: 'test-env',
displayName: 'Test Env',
description: 'This is test environment',
displayPath: '/home/user/envs/.venv/bin/python',
version: '3.12.1',
environmentPath: Uri.file('/home/user/envs/.venv/bin/python'),
execInfo: {
run: {
executable: '/home/user/envs/.venv/bin/python',
},
activation: [
{
executable: '/home/user/envs/.venv/bin/activate',
},
],
},
sysPrefix: '/home/user/envs/.venv',
},
);

const item = new PythonEnvTreeItem(env, managerItem1);
assert.equal(item.treeItem.contextValue, 'pythonEnvironment;activatable;');
});

test('Context Value: with remove, with activate', () => {
const env = new PythonEnvironmentImpl(
{
id: 'test-env',
managerId: manager2.id,
},
{
name: 'test-env',
displayName: 'Test Env',
description: 'This is test environment',
displayPath: '/home/user/envs/.venv/bin/python',
version: '3.12.1',
environmentPath: Uri.file('/home/user/envs/.venv/bin/python'),
execInfo: {
run: {
executable: '/home/user/envs/.venv/bin/python',
},
activation: [
{
executable: '/home/user/envs/.venv/bin/activate',
},
],
},
sysPrefix: '/home/user/envs/.venv',
},
);

const item = new PythonEnvTreeItem(env, managerItem2);
assert.equal(item.treeItem.contextValue, 'pythonEnvironment;remove;activatable;');
});

test('Context Value: with remove, no-activate', () => {
const env = new PythonEnvironmentImpl(
{
id: 'test-env',
managerId: manager2.id,
},
{
name: 'test-env',
displayName: 'Test Env',
description: 'This is test environment',
displayPath: '/home/user/envs/.venv/bin/python',
version: '3.12.1',
environmentPath: Uri.file('/home/user/envs/.venv/bin/python'),
execInfo: {
run: {
executable: '/home/user/envs/.venv/bin/python',
},
},
sysPrefix: '/home/user/envs/.venv',
},
);

const item = new PythonEnvTreeItem(env, managerItem2);
assert.equal(item.treeItem.contextValue, 'pythonEnvironment;remove;');
});

test('Display Name is used', () => {
const env = new PythonEnvironmentImpl(
{
id: 'test-env',
managerId: manager1.id,
},
{
name: 'test-env',
displayName: 'Test Env',
description: 'This is test environment',
displayPath: '/home/user/envs/.venv/bin/python',
version: '3.12.1',
environmentPath: Uri.file('/home/user/envs/.venv/bin/python'),
execInfo: {
run: {
executable: '/home/user/envs/.venv/bin/python',
},
},
sysPrefix: '/home/user/envs/.venv',
},
);

const item = new PythonEnvTreeItem(env, managerItem1);

assert.equal(item.treeItem.label, env.displayName);
});
});
});

0 comments on commit 3dee5e9

Please sign in to comment.