Skip to content

Commit

Permalink
Gather additional data to determine failures in identifying conda envs (
Browse files Browse the repository at this point in the history
  • Loading branch information
DonJayamanne authored and eleanorjboyd committed Jul 30, 2024
1 parent b5a52af commit 490e483
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 2 deletions.
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

0 comments on commit 490e483

Please sign in to comment.