Buckets:
ktongue/docker_container / .vscode-server /extensions /ms-python.vscode-python-envs-1.20.1-linux-arm64 /.github /skills /python-manager-discovery /SKILL.md
metadata
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
async function getPoetryVirtualenvsPath(): Promise<string> {
// 1. Check environment variable first
const envVar = process.env.POETRY_VIRTUALENVS_PATH;
if (envVar) return envVar;
// 2. Check local poetry.toml
const localConfig = await readPoetryToml(projectRoot);
if (localConfig?.virtualenvs?.path) {
return resolvePoetryPath(localConfig.virtualenvs.path);
}
// 3. Use platform-specific default
return getDefaultPoetryCache();
}
function resolvePoetryPath(configPath: string): string {
// Handle {cache-dir} placeholder
if (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
function getPipenvVirtualenvsPath(): string {
// Check WORKON_HOME first
if (process.env.WORKON_HOME) {
return process.env.WORKON_HOME;
}
// Check XDG_DATA_HOME on Linux
if (process.platform === 'linux') {
const xdgData = process.env.XDG_DATA_HOME || path.join(os.homedir(), '.local', 'share');
return path.join(xdgData, 'virtualenvs');
}
// Windows/macOS defaults
return 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
function getPyenvRoot(): string {
if (process.env.PYENV_ROOT) {
return process.env.PYENV_ROOT;
}
if (process.platform === 'win32') {
// pyenv-win uses different structure
return 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
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, zsh
return `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
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 path
const 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
async function fetchFromPET<T>(method: string, params: unknown): Promise<T> {
const timeout = 30000; // 30 seconds
const result = await Promise.race([
this.client.request(method, params),
new Promise<never>((_, reject) => setTimeout(() => reject(new Error('PET server timeout')), timeout)),
]);
// Validate response type
if (!isValidResponse<T>(result)) {
throw new Error(`Invalid response from PET: ${JSON.stringify(result)}`);
}
return result;
}
Xet Storage Details
- Size:
- 10.7 kB
- Xet hash:
- f9d33030a0bcde74d8e55e377fa7f3a7c4ffc4b60a772de57c4f64e2336cfd4c
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.