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
5 changes: 5 additions & 0 deletions src/managers/common/nativePythonFinder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,7 @@ class NativePythonFinderImpl implements NativePythonFinder {
workspaceDirectories: this.api.getPythonProjects().map((item) => item.uri.fsPath),
environmentDirectories: extraSearchPaths,
condaExecutable: getPythonSettingAndUntildify<string>('condaPath'),
pipenvExecutable: getPythonSettingAndUntildify<string>('pipenvPath'),
poetryExecutable: getPythonSettingAndUntildify<string>('poetryPath'),
cacheDirectory: this.cacheDirectory?.fsPath,
};
Expand Down Expand Up @@ -602,6 +603,9 @@ class NativePythonFinderImpl implements NativePythonFinder {
if (a.condaExecutable !== b.condaExecutable) {
return false;
}
if (a.pipenvExecutable !== b.pipenvExecutable) {
return false;
}
if (a.poetryExecutable !== b.poetryExecutable) {
return false;
}
Expand Down Expand Up @@ -634,6 +638,7 @@ type ConfigurationOptions = {
workspaceDirectories: string[];
environmentDirectories: string[];
condaExecutable: string | undefined;
pipenvExecutable: string | undefined;
poetryExecutable: string | undefined;
cacheDirectory?: string;
};
Expand Down
22 changes: 18 additions & 4 deletions src/managers/pipenv/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { getPythonApi } from '../../features/pythonApi';
import { PythonProjectManager } from '../../internal.api';
import { NativePythonFinder } from '../common/nativePythonFinder';
import { PipenvManager } from './pipenvManager';
import { getPipenv } from './pipenvUtils';
import { getPipenv, hasPipenvEnvironments } from './pipenvUtils';

import { notifyMissingManagerIfDefault } from '../common/utils';

Expand All @@ -19,15 +19,29 @@ export async function registerPipenvFeatures(
try {
const pipenv = await getPipenv(nativeFinder);

if (pipenv) {
// Register the manager if the CLI is found, or if there are existing pipenv environments.
// This allows users with existing pipenv environments to still see and use them.
const hasPipenvEnvs = !pipenv && (await hasPipenvEnvironments(nativeFinder));

if (pipenv || hasPipenvEnvs) {
const mgr = new PipenvManager(nativeFinder, api);
disposables.push(mgr, api.registerEnvironmentManager(mgr));
if (!pipenv) {
traceInfo(
'Pipenv CLI not found, but pipenv environments were discovered. Registering manager for read-only environment management. To enable full pipenv features, set the "python.pipenvPath" setting to the path of your pipenv executable.',
);
}
} else {
traceInfo('Pipenv not found, turning off pipenv features.');
traceInfo(
'Pipenv not found, turning off pipenv features. If you have pipenv installed in a non-standard location, set the "python.pipenvPath" setting.',
);
await notifyMissingManagerIfDefault('ms-python.python:pipenv', projectManager, api);
}
} catch (ex) {
traceInfo('Pipenv not found, turning off pipenv features.', ex);
traceInfo(
'Pipenv not found, turning off pipenv features. If you have pipenv installed in a non-standard location, set the "python.pipenvPath" setting.',
ex,
);
await notifyMissingManagerIfDefault('ms-python.python:pipenv', projectManager, api);
}
}
29 changes: 20 additions & 9 deletions src/managers/pipenv/pipenvUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,17 @@ export async function clearPipenvCache(): Promise<void> {
pipenvPath = undefined;
}

/**
* Check if any pipenv environments exist without requiring the pipenv CLI.
* This allows the manager to be registered even if the CLI is not found.
*/
export async function hasPipenvEnvironments(nativeFinder: NativePythonFinder): Promise<boolean> {
const data = await nativeFinder.refresh(false);
return data
.filter((e) => isNativeEnvInfo(e))
.some((e) => (e as NativeEnvInfo).kind === NativePythonEnvironmentKind.pipenv);
}

function getPipenvPathFromSettings(): string | undefined {
const pipenvPath = getSettingWorkspaceScope<string>('python', 'pipenvPath');
return pipenvPath ? pipenvPath : undefined;
Expand Down Expand Up @@ -191,12 +202,13 @@ export async function refreshPipenv(

const collection: PythonEnvironment[] = [];

// Add environments even if pipenv CLI is not found.
// This allows users with existing pipenv environments to still see them
// for read-only management (e.g., selecting the environment, viewing info).
for (const e of envs) {
if (pipenv) {
const environment = await nativeToPythonEnv(e, api, manager);
if (environment) {
collection.push(environment);
}
const environment = await nativeToPythonEnv(e, api, manager);
if (environment) {
collection.push(environment);
}
}

Expand All @@ -212,11 +224,10 @@ export async function resolvePipenvPath(
): Promise<PythonEnvironment | undefined> {
const resolved = await nativeFinder.resolve(fsPath);

// Resolve pipenv environments even if the pipenv CLI is not found.
// This allows proper environment identification for read-only scenarios.
if (resolved.kind === NativePythonEnvironmentKind.pipenv) {
const pipenv = await getPipenv(nativeFinder);
if (pipenv) {
return await nativeToPythonEnv(resolved, api, manager);
}
return await nativeToPythonEnv(resolved, api, manager);
}

return undefined;
Expand Down
Loading