Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

46 changes: 34 additions & 12 deletions src/managers/poetry/poetryUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,19 @@ import {
} from '../common/nativePythonFinder';
import { getShellActivationCommands, shortVersion, sortEnvironments } from '../common/utils';

/**
* Checks if the POETRY_VIRTUALENVS_IN_PROJECT environment variable is set to a truthy value.
* When true, Poetry creates virtualenvs in the project's `.venv` directory.
* Mirrors the PET server logic in `pet-poetry/src/env_variables.rs`.
*/
export function isPoetryVirtualenvsInProject(): boolean {
const value = process.env.POETRY_VIRTUALENVS_IN_PROJECT;
if (value === undefined) {
return false;
}
return value === '1' || value.toLowerCase() === 'true';
}

async function findPoetry(): Promise<string | undefined> {
try {
return await which('poetry');
Expand Down Expand Up @@ -251,19 +264,28 @@ async function nativeToPythonEnv(

// Determine if the environment is in Poetry's global virtualenvs directory
let isGlobalPoetryEnv = false;
const virtualenvsPath = poetryVirtualenvsPath; // Use the cached value if available
if (virtualenvsPath) {
const normalizedVirtualenvsPath = path.normalize(virtualenvsPath);
isGlobalPoetryEnv = normalizedPrefix.startsWith(normalizedVirtualenvsPath);

// If POETRY_VIRTUALENVS_IN_PROJECT is set, environments are created in-project (.venv)
// and should not be classified as global
if (isPoetryVirtualenvsInProject() && info.project) {
isGlobalPoetryEnv = false;
} else {
// Fall back to checking the default location if we haven't cached the path yet
const homeDir = getUserHomeDir();
if (homeDir) {
const defaultPath = path.normalize(path.join(homeDir, '.cache', 'pypoetry', 'virtualenvs'));
isGlobalPoetryEnv = normalizedPrefix.startsWith(defaultPath);

// Try to get the actual path asynchronously for next time
getPoetryVirtualenvsPath(_poetry).catch((e) => traceError(`Error getting Poetry virtualenvs path: ${e}`));
const virtualenvsPath = poetryVirtualenvsPath; // Use the cached value if available
if (virtualenvsPath) {
const normalizedVirtualenvsPath = path.normalize(virtualenvsPath);
isGlobalPoetryEnv = normalizedPrefix.startsWith(normalizedVirtualenvsPath);
} else {
// Fall back to checking the default location if we haven't cached the path yet
const homeDir = getUserHomeDir();
if (homeDir) {
const defaultPath = path.normalize(path.join(homeDir, '.cache', 'pypoetry', 'virtualenvs'));
isGlobalPoetryEnv = normalizedPrefix.startsWith(defaultPath);

// Try to get the actual path asynchronously for next time
getPoetryVirtualenvsPath(_poetry).catch((e) =>
traceError(`Error getting Poetry virtualenvs path: ${e}`),
);
}
}
}

Expand Down
63 changes: 63 additions & 0 deletions src/test/managers/poetry/poetryUtils.unit.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import assert from 'node:assert';
import { isPoetryVirtualenvsInProject } from '../../../managers/poetry/poetryUtils';

suite('isPoetryVirtualenvsInProject', () => {
let originalEnv: string | undefined;

setup(() => {
originalEnv = process.env.POETRY_VIRTUALENVS_IN_PROJECT;
});

teardown(() => {
if (originalEnv === undefined) {
delete process.env.POETRY_VIRTUALENVS_IN_PROJECT;
} else {
process.env.POETRY_VIRTUALENVS_IN_PROJECT = originalEnv;
}
});

test('should return false when env var is not set', () => {
delete process.env.POETRY_VIRTUALENVS_IN_PROJECT;
assert.strictEqual(isPoetryVirtualenvsInProject(), false);
});

test('should return true when env var is "true"', () => {
process.env.POETRY_VIRTUALENVS_IN_PROJECT = 'true';
assert.strictEqual(isPoetryVirtualenvsInProject(), true);
});

test('should return true when env var is "True" (case insensitive)', () => {
process.env.POETRY_VIRTUALENVS_IN_PROJECT = 'True';
assert.strictEqual(isPoetryVirtualenvsInProject(), true);
});

test('should return true when env var is "TRUE" (case insensitive)', () => {
process.env.POETRY_VIRTUALENVS_IN_PROJECT = 'TRUE';
assert.strictEqual(isPoetryVirtualenvsInProject(), true);
});

test('should return true when env var is "1"', () => {
process.env.POETRY_VIRTUALENVS_IN_PROJECT = '1';
assert.strictEqual(isPoetryVirtualenvsInProject(), true);
});

test('should return false when env var is "false"', () => {
process.env.POETRY_VIRTUALENVS_IN_PROJECT = 'false';
assert.strictEqual(isPoetryVirtualenvsInProject(), false);
});

test('should return false when env var is "0"', () => {
process.env.POETRY_VIRTUALENVS_IN_PROJECT = '0';
assert.strictEqual(isPoetryVirtualenvsInProject(), false);
});

test('should return false when env var is empty string', () => {
process.env.POETRY_VIRTUALENVS_IN_PROJECT = '';
assert.strictEqual(isPoetryVirtualenvsInProject(), false);
});

test('should return false when env var is arbitrary string', () => {
process.env.POETRY_VIRTUALENVS_IN_PROJECT = 'yes';
assert.strictEqual(isPoetryVirtualenvsInProject(), false);
});
});