<< All versions
Skill v1.0.0
currentTrusted Publisher100/100microsoft/vscode-python-environments/python-manager-discovery
──Details
PublishedJune 30, 2026 at 05:52 AM
Content Hashsha256:0803619806b86f4f...
Git SHA
──Files
Files (1 file, 10.5 KB)
SKILL.md10.5 KBactive
SKILL.md · 331 lines · 10.5 KB
version: "1.0.0" name: python-manager-discovery description: Environment manager-specific discovery patterns and known issues. Use when working on or reviewing environment discovery code for conda, poetry, pipenv, pyenv, or venv. argument-hint: 'manager name (e.g., poetry, conda, pyenv)' user-invocable: false
Environment Manager Discovery Patterns
This skill documents manager-specific discovery patterns, environment variable precedence, and known issues.
Manager Quick Reference
| Manager | Config Files | Cache Location | Key Env Vars | |
|---|---|---|---|---|
| Poetry | poetry.toml, pyproject.toml, config.toml | Platform-specific | POETRY_VIRTUALENVS_IN_PROJECT, POETRY_CACHE_DIR | |
| Pipenv | Pipfile, Pipfile.lock | XDG or WORKON_HOME | WORKON_HOME, XDG_DATA_HOME | |
| Pyenv | .python-version, versions/ | ~/.pyenv/ or pyenv-win | PYENV_ROOT, PYENV_VERSION | |
| Conda | environment.yml, conda-meta/ | Registries + paths | CONDA_PREFIX, CONDA_DEFAULT_ENV | |
| venv | pyvenv.cfg | In-project | None |
Poetry
Discovery Locations
Virtualenvs cache (default):
- Windows:
%LOCALAPPDATA%\pypoetry\Cache\virtualenvs - macOS:
~/Library/Caches/pypoetry/virtualenvs - Linux:
~/.cache/pypoetry/virtualenvs
In-project (when enabled):
.venv/in project root
Config Precedence (highest to lowest)
- Local config:
poetry.tomlin project root - Environment variables:
POETRY_VIRTUALENVS_* - Global config:
~/.config/pypoetry/config.toml
Known Issues
| Issue | Description | Fix | |
|---|---|---|---|
{cache-dir} placeholder | Not resolved in paths from config | Resolve placeholder before use | |
| Wrong default path | Windows/macOS differ from Linux | Use platform-specific defaults | |
| In-project detection | POETRY_VIRTUALENVS_IN_PROJECT must be checked | Check env var first, then config |
Code Pattern
typescript
async function getPoetryVirtualenvsPath(): Promise<string> {// 1. Check environment variable firstconst envVar = process.env.POETRY_VIRTUALENVS_PATH;if (envVar) return envVar;// 2. Check local poetry.tomlconst localConfig = await readPoetryToml(projectRoot);if (localConfig?.virtualenvs?.path) {return resolvePoetryPath(localConfig.virtualenvs.path);}// 3. Use platform-specific defaultreturn getDefaultPoetryCache();}function resolvePoetryPath(configPath: string): string {// Handle {cache-dir} placeholderif (configPath.includes('{cache-dir}')) {const cacheDir = getDefaultPoetryCache();return configPath.replace('{cache-dir}', cacheDir);}return configPath;}
Pipenv
Discovery Locations
Default:
- Linux:
~/.local/share/virtualenvs/(XDG_DATA_HOME) - macOS:
~/.local/share/virtualenvs/ - Windows:
~\.virtualenvs\
When WORKON_HOME is set:
- Use
$WORKON_HOME/directly
Environment Variables
| Var | Purpose | |
|---|---|---|
WORKON_HOME | Override virtualenv location | |
XDG_DATA_HOME | Base for Linux default | |
PIPENV_VENV_IN_PROJECT | Create .venv/ in project |
Known Issues
| Issue | Description | Fix | |
|---|---|---|---|
| Missing WORKON_HOME support | Env var not checked | Read env var before defaults | |
| Missing XDG_DATA_HOME support | Not used on Linux | Check XDG spec |
Code Pattern
typescript
function getPipenvVirtualenvsPath(): string {// Check WORKON_HOME firstif (process.env.WORKON_HOME) {return process.env.WORKON_HOME;}// Check XDG_DATA_HOME on Linuxif (process.platform === 'linux') {const xdgData = process.env.XDG_DATA_HOME || path.join(os.homedir(), '.local', 'share');return path.join(xdgData, 'virtualenvs');}// Windows/macOS defaultsreturn path.join(os.homedir(), '.virtualenvs');}
PyEnv
Discovery Locations
Unix:
~/.pyenv/versions/(default)$PYENV_ROOT/versions/(if PYENV_ROOT set)
Windows (pyenv-win):
%USERPROFILE%\.pyenv\pyenv-win\versions\- Different directory structure than Unix!
Key Differences: Unix vs Windows
| Aspect | Unix | Windows (pyenv-win) | |
|---|---|---|---|
| Command | pyenv | pyenv.bat | |
| Root | ~/.pyenv/ | %USERPROFILE%\.pyenv\pyenv-win\ | |
| Shims | ~/.pyenv/shims/ | %USERPROFILE%\.pyenv\pyenv-win\shims\ |
Known Issues
| Issue | Description | Fix | |
|---|---|---|---|
| path.normalize() vs path.resolve() | Windows drive letter missing | Use path.resolve() on both sides | |
| Wrong command on Windows | Looking for pyenv instead of pyenv.bat | Check for .bat extension |
Code Pattern
typescript
function getPyenvRoot(): string {if (process.env.PYENV_ROOT) {return process.env.PYENV_ROOT;}if (process.platform === 'win32') {// pyenv-win uses different structurereturn path.join(os.homedir(), '.pyenv', 'pyenv-win');}return path.join(os.homedir(), '.pyenv');}function getPyenvVersionsPath(): string {const root = getPyenvRoot();return path.join(root, 'versions');}// Use path.resolve() for comparisons!function comparePyenvPaths(pathA: string, pathB: string): boolean {return path.resolve(pathA) === path.resolve(pathB);}
Conda
Discovery Locations
Environment locations:
- Base install
envs/directory ~/.conda/envs/- Paths in
~/.condarcenvs_dirs
Windows Registry:
HKCU\Software\Python\ContinuumAnalytics\HKLM\SOFTWARE\Python\ContinuumAnalytics\
Shell Activation
| Shell | Activation Command | |
|---|---|---|
| bash, zsh | source activate envname | |
| fish | conda activate envname (NOT source!) | |
| PowerShell | conda activate envname | |
| cmd | activate.bat envname |
Known Issues
| Issue | Description | Fix | |
|---|---|---|---|
| Fish shell activation | Uses bash-style command | Use fish-compatible syntax | |
| Registry paths | May be stale/invalid | Verify paths exist | |
| Base vs named envs | Different activation | Check if activating base |
Code Pattern
typescript
function getCondaActivationCommand(shell: ShellType, envName: string): string {switch (shell) {case 'fish':// Fish uses different syntax!return `conda activate ${envName}`;case 'cmd':return `activate.bat ${envName}`;case 'powershell':return `conda activate ${envName}`;default:// bash, zshreturn `source activate ${envName}`;}}
venv
Discovery
Identification:
- Look for
pyvenv.cfgfile in directory - Contains
homeand optionallyversionkeys
Version Extraction Priority
versionfield inpyvenv.cfg- Parse from
homepath (e.g.,Python311) - Spawn Python executable (last resort)
Code Pattern
typescript
async function getVenvVersion(venvPath: string): Promise<string | undefined> {const cfgPath = path.join(venvPath, 'pyvenv.cfg');try {const content = await fs.readFile(cfgPath, 'utf-8');const lines = content.split('\n');for (const line of lines) {const [key, value] = line.split('=').map((s) => s.trim());if (key === 'version') {return value;}}// Fall back to parsing home pathconst homeLine = lines.find((l) => l.startsWith('home'));if (homeLine) {const home = homeLine.split('=')[1].trim();const match = home.match(/(\d+)\.(\d+)/);if (match) {return `${match[1]}.${match[2]}`;}}} catch {// Config file not found or unreadable}return undefined;}
PET Server (Native Finder)
JSON-RPC Communication
The PET server is a Rust-based locator that communicates via JSON-RPC over stdio.
Known Issues
| Issue | Description | Fix | |
|---|---|---|---|
| No timeout | JSON-RPC can hang forever | Add Promise.race with timeout | |
| Silent spawn errors | Extension continues without envs | Surface spawn errors to user | |
| Resource leaks | Worker pool not cleaned up | Dispose on deactivation | |
| Type guard missing | Response types not validated | Add runtime type checks | |
| Cache key collision | Paths normalize to same key | Use consistent normalization |
Code Pattern
typescript
async function fetchFromPET<T>(method: string, params: unknown): Promise<T> {const timeout = 30000; // 30 secondsconst result = await Promise.race([this.client.request(method, params),new Promise<never>((_, reject) => setTimeout(() => reject(new Error('PET server timeout')), timeout)),]);// Validate response typeif (!isValidResponse<T>(result)) {throw new Error(`Invalid response from PET: ${JSON.stringify(result)}`);}return result;}