Skip to content

Commit e30a070

Browse files
Copilotkarthiknadig
andcommitted
Fix Windows path calculation in pyenvUtils for environment grouping
On Windows, pyenv-win is at ~/.pyenv/pyenv-win/bin/pyenv.bat, so we need to go up 3 directory levels (not 2) to reach the pyenv root directory (~/.pyenv). This fixes environment grouping (PYENV_VERSIONS vs PYENV_ENVIRONMENTS) which was broken because versionsPath and envsPaths were calculated from the wrong parent directory. Co-authored-by: karthiknadig <3840081+karthiknadig@users.noreply.github.com>
1 parent 7b21874 commit e30a070

3 files changed

Lines changed: 66 additions & 4 deletions

File tree

package-lock.json

Lines changed: 18 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/managers/pyenv/pyenvUtils.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,18 @@ import {
2323
} from '../common/nativePythonFinder';
2424
import { shortVersion, sortEnvironments } from '../common/utils';
2525

26+
/**
27+
* Returns the pyenv root directory from the pyenv executable path.
28+
* On Windows, pyenv-win is at `~/.pyenv/pyenv-win/bin/pyenv.bat` (3 levels up).
29+
* On POSIX, pyenv is at `~/.pyenv/bin/pyenv` (2 levels up).
30+
*/
31+
export function getPyenvDir(pyenv: string): string {
32+
if (isWindows()) {
33+
return path.dirname(path.dirname(path.dirname(pyenv)));
34+
}
35+
return path.dirname(path.dirname(pyenv));
36+
}
37+
2638
async function findPyenv(): Promise<string | undefined> {
2739
try {
2840
return await which('pyenv');
@@ -174,8 +186,9 @@ function nativeToPythonEnv(
174186
return undefined;
175187
}
176188

177-
const versionsPath = normalizePath(path.join(path.dirname(path.dirname(pyenv)), 'versions'));
178-
const envsPaths = normalizePath(path.join(path.dirname(versionsPath), 'envs'));
189+
const pyenvDir = getPyenvDir(pyenv);
190+
const versionsPath = normalizePath(path.join(pyenvDir, 'versions'));
191+
const envsPaths = normalizePath(path.join(pyenvDir, 'envs'));
179192
let group = undefined;
180193
const normPrefix = normalizePath(info.prefix);
181194
if (normPrefix.startsWith(versionsPath)) {
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import assert from 'node:assert';
2+
import * as path from 'path';
3+
import * as sinon from 'sinon';
4+
import * as platformUtils from '../../../common/utils/platformUtils';
5+
import { getPyenvDir } from '../../../managers/pyenv/pyenvUtils';
6+
7+
suite('pyenvUtils - getPyenvDir', () => {
8+
let isWindowsStub: sinon.SinonStub;
9+
10+
setup(() => {
11+
isWindowsStub = sinon.stub(platformUtils, 'isWindows');
12+
});
13+
14+
teardown(() => {
15+
sinon.restore();
16+
});
17+
18+
test('should go up 2 levels on POSIX (bin/pyenv -> pyenv root)', () => {
19+
isWindowsStub.returns(false);
20+
// e.g. /home/user/.pyenv/bin/pyenv
21+
const pyenvBin = path.join('home', 'user', '.pyenv', 'bin', 'pyenv');
22+
const result = getPyenvDir(pyenvBin);
23+
assert.strictEqual(result, path.join('home', 'user', '.pyenv'));
24+
});
25+
26+
test('should go up 3 levels on Windows (pyenv-win/bin/pyenv.bat -> pyenv root)', () => {
27+
isWindowsStub.returns(true);
28+
// e.g. C:\Users\user\.pyenv\pyenv-win\bin\pyenv.bat
29+
const pyenvBin = path.join('C:', 'Users', 'user', '.pyenv', 'pyenv-win', 'bin', 'pyenv.bat');
30+
const result = getPyenvDir(pyenvBin);
31+
assert.strictEqual(result, path.join('C:', 'Users', 'user', '.pyenv'));
32+
});
33+
});

0 commit comments

Comments
 (0)