Skip to content

Commit 6fb1e8a

Browse files
Copilotkarthiknadig
andcommitted
Add POETRY_VIRTUALENVS_IN_PROJECT env var support to poetryUtils.ts
Co-authored-by: karthiknadig <3840081+karthiknadig@users.noreply.github.com>
1 parent c12d4ee commit 6fb1e8a

3 files changed

Lines changed: 115 additions & 14 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/poetry/poetryUtils.ts

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,19 @@ import {
1717
} from '../common/nativePythonFinder';
1818
import { getShellActivationCommands, shortVersion, sortEnvironments } from '../common/utils';
1919

20+
/**
21+
* Checks if the POETRY_VIRTUALENVS_IN_PROJECT environment variable is set to a truthy value.
22+
* When true, Poetry creates virtualenvs in the project's `.venv` directory.
23+
* Mirrors the PET server logic in `pet-poetry/src/env_variables.rs`.
24+
*/
25+
export function isPoetryVirtualenvsInProject(): boolean {
26+
const value = process.env.POETRY_VIRTUALENVS_IN_PROJECT;
27+
if (value === undefined) {
28+
return false;
29+
}
30+
return value === '1' || value.toLowerCase() === 'true';
31+
}
32+
2033
async function findPoetry(): Promise<string | undefined> {
2134
try {
2235
return await which('poetry');
@@ -251,19 +264,28 @@ async function nativeToPythonEnv(
251264

252265
// Determine if the environment is in Poetry's global virtualenvs directory
253266
let isGlobalPoetryEnv = false;
254-
const virtualenvsPath = poetryVirtualenvsPath; // Use the cached value if available
255-
if (virtualenvsPath) {
256-
const normalizedVirtualenvsPath = path.normalize(virtualenvsPath);
257-
isGlobalPoetryEnv = normalizedPrefix.startsWith(normalizedVirtualenvsPath);
267+
268+
// If POETRY_VIRTUALENVS_IN_PROJECT is set, environments are created in-project (.venv)
269+
// and should not be classified as global
270+
if (isPoetryVirtualenvsInProject() && info.project) {
271+
isGlobalPoetryEnv = false;
258272
} else {
259-
// Fall back to checking the default location if we haven't cached the path yet
260-
const homeDir = getUserHomeDir();
261-
if (homeDir) {
262-
const defaultPath = path.normalize(path.join(homeDir, '.cache', 'pypoetry', 'virtualenvs'));
263-
isGlobalPoetryEnv = normalizedPrefix.startsWith(defaultPath);
264-
265-
// Try to get the actual path asynchronously for next time
266-
getPoetryVirtualenvsPath(_poetry).catch((e) => traceError(`Error getting Poetry virtualenvs path: ${e}`));
273+
const virtualenvsPath = poetryVirtualenvsPath; // Use the cached value if available
274+
if (virtualenvsPath) {
275+
const normalizedVirtualenvsPath = path.normalize(virtualenvsPath);
276+
isGlobalPoetryEnv = normalizedPrefix.startsWith(normalizedVirtualenvsPath);
277+
} else {
278+
// Fall back to checking the default location if we haven't cached the path yet
279+
const homeDir = getUserHomeDir();
280+
if (homeDir) {
281+
const defaultPath = path.normalize(path.join(homeDir, '.cache', 'pypoetry', 'virtualenvs'));
282+
isGlobalPoetryEnv = normalizedPrefix.startsWith(defaultPath);
283+
284+
// Try to get the actual path asynchronously for next time
285+
getPoetryVirtualenvsPath(_poetry).catch((e) =>
286+
traceError(`Error getting Poetry virtualenvs path: ${e}`),
287+
);
288+
}
267289
}
268290
}
269291

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import assert from 'node:assert';
2+
import { isPoetryVirtualenvsInProject } from '../../../managers/poetry/poetryUtils';
3+
4+
suite('isPoetryVirtualenvsInProject', () => {
5+
let originalEnv: string | undefined;
6+
7+
setup(() => {
8+
originalEnv = process.env.POETRY_VIRTUALENVS_IN_PROJECT;
9+
});
10+
11+
teardown(() => {
12+
if (originalEnv === undefined) {
13+
delete process.env.POETRY_VIRTUALENVS_IN_PROJECT;
14+
} else {
15+
process.env.POETRY_VIRTUALENVS_IN_PROJECT = originalEnv;
16+
}
17+
});
18+
19+
test('should return false when env var is not set', () => {
20+
delete process.env.POETRY_VIRTUALENVS_IN_PROJECT;
21+
assert.strictEqual(isPoetryVirtualenvsInProject(), false);
22+
});
23+
24+
test('should return true when env var is "true"', () => {
25+
process.env.POETRY_VIRTUALENVS_IN_PROJECT = 'true';
26+
assert.strictEqual(isPoetryVirtualenvsInProject(), true);
27+
});
28+
29+
test('should return true when env var is "True" (case insensitive)', () => {
30+
process.env.POETRY_VIRTUALENVS_IN_PROJECT = 'True';
31+
assert.strictEqual(isPoetryVirtualenvsInProject(), true);
32+
});
33+
34+
test('should return true when env var is "TRUE" (case insensitive)', () => {
35+
process.env.POETRY_VIRTUALENVS_IN_PROJECT = 'TRUE';
36+
assert.strictEqual(isPoetryVirtualenvsInProject(), true);
37+
});
38+
39+
test('should return true when env var is "1"', () => {
40+
process.env.POETRY_VIRTUALENVS_IN_PROJECT = '1';
41+
assert.strictEqual(isPoetryVirtualenvsInProject(), true);
42+
});
43+
44+
test('should return false when env var is "false"', () => {
45+
process.env.POETRY_VIRTUALENVS_IN_PROJECT = 'false';
46+
assert.strictEqual(isPoetryVirtualenvsInProject(), false);
47+
});
48+
49+
test('should return false when env var is "0"', () => {
50+
process.env.POETRY_VIRTUALENVS_IN_PROJECT = '0';
51+
assert.strictEqual(isPoetryVirtualenvsInProject(), false);
52+
});
53+
54+
test('should return false when env var is empty string', () => {
55+
process.env.POETRY_VIRTUALENVS_IN_PROJECT = '';
56+
assert.strictEqual(isPoetryVirtualenvsInProject(), false);
57+
});
58+
59+
test('should return false when env var is arbitrary string', () => {
60+
process.env.POETRY_VIRTUALENVS_IN_PROJECT = 'yes';
61+
assert.strictEqual(isPoetryVirtualenvsInProject(), false);
62+
});
63+
});

0 commit comments

Comments
 (0)