Skip to content

Implement Pipenv as a New Environment Manager#3

Closed
Copilot wants to merge 6 commits intocopilot/vscode1755728512180from
copilot/fix-8da9d21e-962d-48df-8df2-12146a3a967e
Closed

Implement Pipenv as a New Environment Manager#3
Copilot wants to merge 6 commits intocopilot/vscode1755728512180from
copilot/fix-8da9d21e-962d-48df-8df2-12146a3a967e

Conversation

Copy link
Copy Markdown

Copilot AI commented Aug 20, 2025

This PR implements Pipenv as a new environment manager in the Python Environments extension, following the structured integration plan outlined in docs/pipenv-integration.md.

Overview

Pipenv is now fully integrated as an environment manager, allowing users to discover, select, and manage Pipenv virtual environments through the VS Code Python Environments extension UI.

Implementation Details

Environment Manager (PipenvManager)

  • Discovery: Detects pipenv environments using the native Python finder with NativePythonEnvironmentKind.pipenv
  • Shell Integration: Uses pipenv shell for terminal activation and exit for deactivation
  • Persistence: Maintains workspace and global environment selections using VS Code's persistent state
  • Events: Emits environment change events for UI updates and integration with other components

Utilities (pipenvUtils.ts)

  • Binary Detection: Locates pipenv executable via PATH, persistent state, or native finder fallback
  • Environment Resolution: Converts native environment info to PythonEnvironment objects
  • Workspace Mapping: Maps pipenv environments to VS Code workspaces with persistence

Package Manager (PipenvPackageManager)

  • Integration: Registered with ID ms-python.python:pipenv as specified in the integration plan
  • Scaffolding: Provides foundation for pipenv install/pipenv uninstall operations
  • UI Ready: Integrates with extension's package management interface

Registration & Activation

  • Extension Integration: Added to main extension activation sequence in extension.ts
  • Conditional Loading: Only activates when pipenv binary is detected on the system
  • Resource Management: Proper disposal and cleanup following extension patterns

Technical Highlights

  • Full EnvironmentManager Interface: Implements all required methods (getEnvironments, refresh, get, set, resolve, clearCache)
  • TypeScript Compliance: All code compiles without errors and follows project linting standards
  • Event-Driven Architecture: Proper event emitters for environment and package changes
  • Progress Indicators: User-friendly discovery operations with localized progress messages
  • Memory Management: Implements disposable pattern for proper resource cleanup

User Experience

Users can now:

  1. Discover pipenv environments automatically when the extension loads
  2. Select pipenv environments for their workspaces through the Python Environments UI
  3. Activate environments in terminals using the built-in activation commands
  4. Manage packages through the pipenv package manager (foundation implemented)

Code Quality

  • Follows established patterns from existing managers (pyenv, poetry, conda)
  • Comprehensive error handling and logging
  • Uses existing localization infrastructure (PipenvStrings)
  • Maintains backward compatibility with existing functionality
  • Zero breaking changes to existing APIs

The implementation provides a solid foundation for pipenv environment management and can be extended with additional features like quick create functionality and enhanced package management operations.


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 2 commits August 20, 2025 22:30
Co-authored-by: eleanorjboyd <26030610+eleanorjboyd@users.noreply.github.com>
Co-authored-by: eleanorjboyd <26030610+eleanorjboyd@users.noreply.github.com>
@eleanorjboyd
Copy link
Copy Markdown
Owner

This may help:

async function findPipenv(): Promise<string | undefined> {
    try {
        return await which('pipenv');
    } catch {
        return undefined;
    }
}

export async function getPipenv(_native?: NativePythonFinder): Promise<string | undefined> {
    if (pipenvPath) {
        return pipenvPath;
    }

    // Fast PATH lookup
    pipenvPath = await findPipenv();
    if (pipenvPath) {
        return pipenvPath;
    }

    // If native finder provided, try to get manager info
    if (_native) {
        try {
            const data = await _native.refresh(false);
            const managers = data
                .filter((e) => !isNativeEnvInfo(e))
                .map((e) => e as NativeEnvManagerInfo)
                .filter((e) => e.tool.toLowerCase() === 'pipenv');
            if (managers.length > 0) {
                pipenvPath = managers[0].executable;
                traceInfo(`Using pipenv from native finder: ${pipenvPath}`);
                return pipenvPath;
            }
        } catch (e) {
            traceError(`Error checking native managers for pipenv: ${e}`);
        }
    }

    return undefined;
}

/**
 * Convert a native (found by the native finder) Pipenv environment descriptor into
 * the extension's PythonEnvironment item.
 *
 * Steps:
 * 1. Validate native info: ensure prefix, executable and version are present.
 * 2. Derive user-facing metadata: short version, name and displayName.
 * 3. Determine grouping: if this environment is associated with a project (info.project)
 *    use the project name as the group label; otherwise leave undefined.
 * 4. Compute bin directory from the executable and use the generic
 *    getShellActivationCommands helper to build shell activation/deactivation commands.
 * 5. Assemble a PythonEnvironmentInfo object with execInfo.run set to the environment's
 *    python executable and the activation/deactivation maps.
 * 6. Call api.createPythonEnvironmentItem(...) and return the result.
 */
export async function nativeToPythonEnv(
    info: NativeEnvInfo,
    api: PythonEnvironmentApi,
    manager: EnvironmentManager,
    _pipenv?: string,
): Promise<PythonEnvironment | undefined> {
    // 1) Validate input
    if (!(info.prefix && info.executable && info.version)) {
        traceError(`Incomplete pipenv environment info: ${JSON.stringify(info)}`);
        return undefined;
    }

    // 2) Derive display metadata
    const sv = shortVersion(info.version);
    const name = info.name || info.displayName || path.basename(info.prefix);
    const displayName = info.displayName || `pipenv (${sv})`;

    // 3) Determine group (project-based if available)
    // If info.project is provided by the native finder, use the project folder name as the group label.
    // This mirrors how project-scoped environments are typically represented in the UI.
    const group = info.project ? path.basename(info.project) : undefined;

    // 4) Compute activation/deactivation commands using bin dir from executable
    const binDir = path.dirname(info.executable);
    const { shellActivation, shellDeactivation } = await getShellActivationCommands(binDir);

    // 5) Assemble the PythonEnvironmentInfo
    const environment: PythonEnvironmentInfo = {
        name: name,
        displayName: displayName,
        shortDisplayName: displayName,
        displayPath: info.prefix,
        version: info.version,
        environmentPath: Uri.file(info.prefix),
        description: undefined,
        tooltip: info.prefix,
        execInfo: {
            run: { executable: info.executable },
            shellActivation,
            shellDeactivation,
        },
        sysPrefix: info.prefix,
        group: group,
    };

    // 6) Create and return the platform-agnostic PythonEnvironment wrapper
    return api.createPythonEnvironmentItem(environment, manager);
}

Co-authored-by: eleanorjboyd <26030610+eleanorjboyd@users.noreply.github.com>
Copilot AI changed the title [WIP] Integration of Pipenv as a New Environment Manager Implement Pipenv as a New Environment Manager Aug 20, 2025
Copilot AI requested a review from eleanorjboyd August 20, 2025 22:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants