Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gather additional data to determine failures in identifying conda envs #23779

Merged
merged 4 commits into from
Jul 10, 2024
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import { Event, EventEmitter, workspace } from 'vscode';
import '../../../../common/extensions';
import * as fsPath from 'path';
import { createDeferred, Deferred } from '../../../../common/utils/async';
import { StopWatch } from '../../../../common/utils/stopWatch';
import { traceError, traceInfo, traceVerbose } from '../../../../logging';
Expand All @@ -28,6 +29,7 @@ import { createNativeGlobalPythonFinder, NativeEnvInfo } from '../common/nativeP
import { pathExists } from '../../../../common/platform/fs-paths';
import { noop } from '../../../../common/utils/misc';
import { parseVersion } from '../../info/pythonVersion';
import { Conda } from '../../../common/environmentManagers/conda';

/**
* A service which maintains the collection of known environments.
Expand Down Expand Up @@ -304,6 +306,12 @@ export class EnvsCollectionService extends PythonEnvsWatcher<PythonEnvCollection
const nativeDuration = nativeStopWatch.elapsedTime;
void this.sendNativeLocatorTelemetry(nativeEnvs);
const missingEnvironments = {
envsWithDuplicatePrefixes: 0,
envsNotFound: 0,
condaEnvsInEnvDir: 0,
invalidCondaEnvs: 0,
condaEnvsWithoutPrefix: 0,
nativeCondaEnvsInEnvDir: 0,
missingNativeCondaEnvs: 0,
missingNativeCustomEnvs: 0,
missingNativeMicrosoftStoreEnvs: 0,
Expand All @@ -320,6 +328,31 @@ export class EnvsCollectionService extends PythonEnvsWatcher<PythonEnvCollection
missingNativeOtherGlobalEnvs: 0,
};

let canSpawnConda: boolean | undefined;
let condaInfoEnvs: undefined | number;
let condaInfoEnvsDirs: undefined | number;
let envsDirs: string[] = [];
try {
const conda = await Conda.getConda();
const info = await conda?.getInfo();
canSpawnConda = true;
condaInfoEnvs = info?.envs?.length;
// eslint-disable-next-line camelcase
condaInfoEnvsDirs = info?.envs_dirs?.length;
// eslint-disable-next-line camelcase
envsDirs = info?.envs_dirs || [];

nativeEnvs
.filter((e) => this.nativeFinder.categoryToKind(e.kind) === PythonEnvKind.Conda)
.forEach((e) => {
if (e.prefix && envsDirs.some((d) => e.prefix && e.prefix.startsWith(d))) {
missingEnvironments.nativeCondaEnvsInEnvDir += 1;
}
});
} catch (ex) {
canSpawnConda = false;
}
const prefixesSeenAlready = new Set<string>();
await Promise.all(
envs.map(async (env) => {
try {
Expand All @@ -332,9 +365,16 @@ export class EnvsCollectionService extends PythonEnvsWatcher<PythonEnvCollection
if (!exe || !(await pathExists(exe))) {
exe = (await pathExists(env.executable.sysPrefix)) ? env.executable.sysPrefix : '';
}
if (env.executable.sysPrefix && prefixesSeenAlready.has(env.executable.sysPrefix)) {
prefixesSeenAlready.add(env.executable.sysPrefix);
missingEnvironments.envsWithDuplicatePrefixes += 1;
}
// Lowercase for purposes of comparison (safe).
exe = exe.trim().toLowerCase();
if (!exe) {
if (env.executable.filename || env.executable.sysPrefix) {
missingEnvironments.envsNotFound += 1;
}
return;
}
// If this exe is not found by the native locator, then it is missing.
Expand All @@ -357,6 +397,12 @@ export class EnvsCollectionService extends PythonEnvsWatcher<PythonEnvCollection
traceError(`Environment ${exe} is missing from native locator`);
switch (env.kind) {
case PythonEnvKind.Conda:
if (
env.executable.sysPrefix &&
envsDirs.some((d) => env.executable.sysPrefix.startsWith(d))
) {
missingEnvironments.condaEnvsInEnvDir += 1;
}
missingEnvironments.missingNativeCondaEnvs += 1;
break;
case PythonEnvKind.Custom:
Expand Down Expand Up @@ -419,7 +465,7 @@ export class EnvsCollectionService extends PythonEnvsWatcher<PythonEnvCollection
(e) => getEnvPath(e.executable.filename, e.location).pathType === 'envFolderPath',
).length;
const activeStateEnvs = envs.filter((e) => e.kind === PythonEnvKind.ActiveState).length;
const condaEnvs = envs.filter((e) => e.kind === PythonEnvKind.Conda).length;
const condaEnvs = envs.filter((e) => e.kind === PythonEnvKind.Conda);
const customEnvs = envs.filter((e) => e.kind === PythonEnvKind.Custom).length;
const hatchEnvs = envs.filter((e) => e.kind === PythonEnvKind.Hatch).length;
const microsoftStoreEnvs = envs.filter((e) => e.kind === PythonEnvKind.MicrosoftStore).length;
Expand All @@ -441,6 +487,22 @@ export class EnvsCollectionService extends PythonEnvsWatcher<PythonEnvCollection
e.kind === PythonEnvKind.OtherVirtual,
).length;

missingEnvironments.condaEnvsWithoutPrefix = condaEnvs.filter((e) => !e.executable.sysPrefix).length;

await Promise.all(
condaEnvs.map(async (e) => {
if (e.executable.sysPrefix) {
const metadataFolder = fsPath.join(e.executable.sysPrefix, 'conda-meta');
if (!(await pathExists(metadataFolder))) {
missingEnvironments.invalidCondaEnvs += 1;
}
}
}),
);
missingEnvironments.invalidCondaEnvs = envs
.filter((e) => e.kind === PythonEnvKind.Conda)
.filter((e) => e.executable.sysPrefix && e.executable.sysPrefix).length;

const nativeEnvironmentsWithoutPython = nativeEnvs.filter((e) => e.executable === undefined).length;
const nativeCondaEnvs = nativeEnvs.filter(
(e) => this.nativeFinder.categoryToKind(e.kind) === PythonEnvKind.Conda,
Expand Down Expand Up @@ -493,9 +555,12 @@ export class EnvsCollectionService extends PythonEnvsWatcher<PythonEnvCollection
nativeDuration,
workspaceFolderCount: (workspace.workspaceFolders || []).length,
interpreters: this.cache.getAllEnvs().length,
condaInfoEnvs,
condaInfoEnvsDirs,
canSpawnConda,
environmentsWithoutPython,
activeStateEnvs,
condaEnvs,
condaEnvs: condaEnvs.length,
customEnvs,
hatchEnvs,
microsoftStoreEnvs,
Expand Down
47 changes: 47 additions & 0 deletions src/client/telemetry/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1145,8 +1145,17 @@ export interface IEventNamePropertyMapping {
"duration" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true, "owner": "donjayamanne" },
"nativeDuration" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true, "owner": "donjayamanne" },
"interpreters" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true , "owner": "donjayamanne"},
"envsWithDuplicatePrefixes" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true , "owner": "donjayamanne"},
"envsNotFound" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true , "owner": "donjayamanne"},
"condaInfoEnvs" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true , "owner": "donjayamanne"},
"condaInfoEnvsDirs" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true , "owner": "donjayamanne"},
"condaEnvsInEnvDir" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true , "owner": "donjayamanne"},
"nativeCondaEnvsInEnvDir" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true , "owner": "donjayamanne"},
"invalidCondaEnvs" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true , "owner": "donjayamanne"},
"condaEnvsWithoutPrefix" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true , "owner": "donjayamanne"},
"environmentsWithoutPython" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true, "owner": "donjayamanne" },
"usingNativeLocator" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "owner": "donjayamanne" },
"canSpawnConda" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "owner": "donjayamanne" },
"activeStateEnvs" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true, "owner": "donjayamanne" },
"condaEnvs" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true, "owner": "donjayamanne" },
"customEnvs" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true, "owner": "donjayamanne" },
Expand Down Expand Up @@ -1207,6 +1216,44 @@ export interface IEventNamePropertyMapping {
* The number of the interpreters discovered
*/
interpreters?: number;
/**
* The number of the interpreters with duplicate prefixes
*/
envsWithDuplicatePrefixes?: number;
/**
* The number of the interpreters returned by `conda info`
*/
condaInfoEnvs?: number;
/**
* The number of the envs_dirs returned by `conda info`
*/
condaInfoEnvsDirs?: number;
/**
* The number of conda interpreters that are in the one of the global conda env locations.
* Global conda envs locations are returned by `conda info` in the `envs_dirs` setting.
*/
condaEnvsInEnvDir?: number;
/**
* The number of native conda interpreters that are in the one of the global conda env locations.
* Global conda envs locations are returned by `conda info` in the `envs_dirs` setting.
*/
nativeCondaEnvsInEnvDir?: number;
/**
* The number of conda interpreters without the `conda-meta` directory.
*/
invalidCondaEnvs?: number;
/**
* The number of conda interpreters without the prefix.
*/
condaEnvsWithoutPrefix?: number;
/**
* Conda exe can be spawned.
*/
canSpawnConda?: boolean;
/**
* The number of the interpreters not found in disc.
*/
envsNotFount?: number;
/**
* Whether or not we're using the native locator.
*/
Expand Down
Loading