Skip to content

Commit fd260fb

Browse files
committed
Wrap yields with a try catch (#15931)
* Log parsing errors in verbose mode only * Fix conda logging * Wrap yields with try catch
1 parent 86cbc12 commit fd260fb

File tree

9 files changed

+114
-73
lines changed

9 files changed

+114
-73
lines changed

src/client/pythonEnvironments/base/locators/lowLevel/filesLocator.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
/* eslint-disable max-classes-per-file */
66

77
import { Event, EventEmitter } from 'vscode';
8+
import { traceError } from '../../../../common/logger';
89
import { DirEntry } from '../../../../common/utils/filesystem';
910
import { iterPythonExecutablesInDir } from '../../../common/commonUtils';
1011
import { resolvePath } from '../../../common/externalDependencies';
@@ -65,7 +66,11 @@ async function* iterMinimalEnvsFromExecutables(
6566
for await (const executable of executables) {
6667
const filename = typeof executable === 'string' ? executable : executable.filename;
6768
const normFile = resolvePath(filename);
68-
yield getFastEnvInfo(defaultKind, normFile);
69+
try {
70+
yield getFastEnvInfo(defaultKind, normFile);
71+
} catch (ex) {
72+
traceError(`Failed to process environment: ${normFile}`, ex);
73+
}
6974
}
7075
}
7176

src/client/pythonEnvironments/base/locators/lowLevel/workspaceVirtualEnvLocator.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import { uniq } from 'lodash';
55
import * as path from 'path';
66
import { Uri } from 'vscode';
7-
import { traceVerbose } from '../../../../common/logger';
7+
import { traceError, traceVerbose } from '../../../../common/logger';
88
import { chain, iterable } from '../../../../common/utils/async';
99
import {
1010
findInterpretersInDir,
@@ -126,8 +126,12 @@ export class WorkspaceVirtualEnvironmentLocator extends FSWatchingLocator {
126126
// We don't know the environment type so skip this one.
127127
traceVerbose(`Workspace Virtual Environment: [skipped] ${filename}`);
128128
} else {
129-
yield buildSimpleVirtualEnvInfo(filename, kind);
130-
traceVerbose(`Workspace Virtual Environment: [added] ${filename}`);
129+
try {
130+
yield buildSimpleVirtualEnvInfo(filename, kind);
131+
traceVerbose(`Workspace Virtual Environment: [added] ${filename}`);
132+
} catch (ex) {
133+
traceError(`Failed to process environment: ${filename}`, ex);
134+
}
131135
}
132136
} else {
133137
traceVerbose(`Workspace Virtual Environment: [skipped] ${filename}`);

src/client/pythonEnvironments/discovery/locators/services/condaLocator.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { IPythonEnvsIterator, Locator } from '../../../base/locator';
77
import { getInterpreterPathFromDir, getPythonVersionFromPath } from '../../../common/commonUtils';
88
import { AnacondaCompanyName, Conda } from './conda';
99
import { resolveEnvFromIterator } from '../../../base/locatorUtils';
10-
import { traceVerbose } from '../../../../common/logger';
10+
import { traceError, traceVerbose } from '../../../../common/logger';
1111

1212
export class CondaEnvironmentLocator extends Locator {
1313
// Locating conda binary is expensive, since it potentially involves spawning or
@@ -54,8 +54,12 @@ export class CondaEnvironmentLocator extends Locator {
5454
if (name) {
5555
info.name = name;
5656
}
57-
traceVerbose(`Found conda environment: ${info}`);
58-
yield info;
57+
traceVerbose(`Found conda environment: ${executable}`);
58+
try {
59+
yield info;
60+
} catch (ex) {
61+
traceError(`Failed to process environment: ${executable}`, ex);
62+
}
5963
}
6064
}
6165
}

src/client/pythonEnvironments/discovery/locators/services/customVirtualEnvLocator.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
import { uniq } from 'lodash';
55
import * as path from 'path';
6-
import { traceVerbose } from '../../../../common/logger';
6+
import { traceError, traceVerbose } from '../../../../common/logger';
77
import { chain, iterable } from '../../../../common/utils/async';
88
import { getUserHomeDir } from '../../../../common/utils/platform';
99
import { PythonEnvInfo, PythonEnvKind, PythonEnvSource } from '../../../base/info';
@@ -134,12 +134,16 @@ export class CustomVirtualEnvironmentLocator extends FSWatchingLocator {
134134
// python.exe or python in the same directory in the case of virtual
135135
// environments.
136136
if (await looksLikeBasicVirtualPython(entry)) {
137-
// We should extract the kind here to avoid doing is*Environment()
138-
// check multiple times. Those checks are file system heavy and
139-
// we can use the kind to determine this anyway.
140-
const kind = await getVirtualEnvKind(filename);
141-
yield buildSimpleVirtualEnvInfo(filename, kind);
142-
traceVerbose(`Custom Virtual Environment: [added] ${filename}`);
137+
try {
138+
// We should extract the kind here to avoid doing is*Environment()
139+
// check multiple times. Those checks are file system heavy and
140+
// we can use the kind to determine this anyway.
141+
const kind = await getVirtualEnvKind(filename);
142+
yield buildSimpleVirtualEnvInfo(filename, kind);
143+
traceVerbose(`Custom Virtual Environment: [added] ${filename}`);
144+
} catch (ex) {
145+
traceError(`Failed to process environment: ${filename}`, ex);
146+
}
143147
} else {
144148
traceVerbose(`Custom Virtual Environment: [skipped] ${filename}`);
145149
}

src/client/pythonEnvironments/discovery/locators/services/globalVirtualEnvronmentLocator.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
import { uniq } from 'lodash';
55
import * as path from 'path';
6-
import { traceVerbose } from '../../../../common/logger';
6+
import { traceError, traceVerbose } from '../../../../common/logger';
77
import { chain, iterable } from '../../../../common/utils/async';
88
import { getEnvironmentVariable, getOSType, getUserHomeDir, OSType } from '../../../../common/utils/platform';
99
import { PythonEnvInfo, PythonEnvKind, PythonEnvSource } from '../../../base/info';
@@ -138,8 +138,12 @@ export class GlobalVirtualEnvironmentLocator extends FSWatchingLocator {
138138
// We don't know the environment type so skip this one.
139139
traceVerbose(`Global Virtual Environment: [skipped] ${filename}`);
140140
} else {
141-
yield buildSimpleVirtualEnvInfo(filename, kind);
142-
traceVerbose(`Global Virtual Environment: [added] ${filename}`);
141+
try {
142+
yield buildSimpleVirtualEnvInfo(filename, kind);
143+
traceVerbose(`Global Virtual Environment: [added] ${filename}`);
144+
} catch (ex) {
145+
traceError(`Failed to process environment: ${filename}`, ex);
146+
}
143147
}
144148
} else {
145149
traceVerbose(`Global Virtual Environment: [skipped] ${filename}`);

src/client/pythonEnvironments/discovery/locators/services/poetryLocator.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import { uniq } from 'lodash';
77
import * as path from 'path';
88
import { Uri } from 'vscode';
9-
import { traceVerbose } from '../../../../common/logger';
9+
import { traceError, traceVerbose } from '../../../../common/logger';
1010
import { chain, iterable } from '../../../../common/utils/async';
1111
import { PythonEnvInfo, PythonEnvKind, PythonEnvSource } from '../../../base/info';
1212
import { buildEnvInfo } from '../../../base/info/env';
@@ -118,11 +118,15 @@ export class PoetryLocator extends FSWatchingLocator {
118118
`Poetry Virtual Environment: [skipped] ${filename} (reason: Not poetry environment)`,
119119
);
120120
} else {
121-
// We should extract the kind here to avoid doing is*Environment()
122-
// check multiple times. Those checks are file system heavy and
123-
// we can use the kind to determine this anyway.
124-
yield buildVirtualEnvInfo(filename, kind, undefined, isLocal);
125-
traceVerbose(`Poetry Virtual Environment: [added] ${filename}`);
121+
try {
122+
// We should extract the kind here to avoid doing is*Environment()
123+
// check multiple times. Those checks are file system heavy and
124+
// we can use the kind to determine this anyway.
125+
yield buildVirtualEnvInfo(filename, kind, undefined, isLocal);
126+
traceVerbose(`Poetry Virtual Environment: [added] ${filename}`);
127+
} catch (ex) {
128+
traceError(`Failed to process environment: ${filename}`, ex);
129+
}
126130
}
127131
}
128132
}

src/client/pythonEnvironments/discovery/locators/services/posixKnownPathsLocator.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Licensed under the MIT License.
33

44
import * as path from 'path';
5-
import { traceError } from '../../../../common/logger';
5+
import { traceError, traceVerbose } from '../../../../common/logger';
66
import { Architecture } from '../../../../common/utils/platform';
77
import { PythonEnvInfo, PythonEnvKind, PythonEnvSource, PythonReleaseLevel, PythonVersion } from '../../../base/info';
88
import { buildEnvInfo } from '../../../base/info/env';
@@ -22,8 +22,14 @@ export class PosixKnownPathsLocator extends Locator {
2222
// the binaries specified in .python-version file in the cwd. We should not be reporting
2323
// those binaries as environments.
2424
const knownDirs = (await commonPosixBinPaths()).filter((dirname) => !isPyenvShimDir(dirname));
25-
const exes = await getPythonBinFromPosixPaths(knownDirs);
26-
yield* exes.map(buildPathEnvInfo);
25+
const pythonBinaries = await getPythonBinFromPosixPaths(knownDirs);
26+
for (const bin of pythonBinaries) {
27+
try {
28+
yield buildPathEnvInfo(bin);
29+
} catch (ex) {
30+
traceError(`Failed to process environment: ${bin}`, ex);
31+
}
32+
}
2733
};
2834
return iterator();
2935
}
@@ -38,7 +44,7 @@ export class PosixKnownPathsLocator extends Locator {
3844
try {
3945
version = parseVersion(path.basename(bin));
4046
} catch (ex) {
41-
traceError(`Failed to parse version from path: ${bin}`, ex);
47+
traceVerbose(`Failed to parse version from path: ${bin}`, ex);
4248
version = {
4349
major: -1,
4450
minor: -1,

src/client/pythonEnvironments/discovery/locators/services/pyenvLocator.ts

Lines changed: 48 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
import { uniq } from 'lodash';
55
import * as path from 'path';
6+
import { traceError } from '../../../../common/logger';
67
import { getEnvironmentVariable, getOSType, getUserHomeDir, OSType } from '../../../../common/utils/platform';
78
import { PythonEnvInfo, PythonEnvKind, PythonEnvSource } from '../../../base/info';
89
import { buildEnvInfo } from '../../../base/info/env';
@@ -266,50 +267,53 @@ async function* getPyenvEnvironments(): AsyncIterableIterator<PythonEnvInfo> {
266267
const interpreterPath = await getInterpreterPathFromDir(subDirPath);
267268

268269
if (interpreterPath) {
269-
// The sub-directory name sometimes can contain distro and python versions.
270-
// here we attempt to extract the texts out of the name.
271-
const versionStrings = await parsePyenvVersion(envDirName);
272-
273-
// Here we look for near by files, or config files to see if we can get python version info
274-
// without running python itself.
275-
const pythonVersion = await getPythonVersionFromPath(interpreterPath, versionStrings?.pythonVer);
276-
277-
// Pyenv environments can fall in to these three categories:
278-
// 1. Global Installs : These are environments that are created when you install
279-
// a supported python distribution using `pyenv install <distro>` command.
280-
// These behave similar to globally installed version of python or distribution.
281-
//
282-
// 2. Virtual Envs : These are environments that are created when you use
283-
// `pyenv virtualenv <distro> <env-name>`. These are similar to environments
284-
// created using `python -m venv <env-name>`.
285-
//
286-
// 3. Conda Envs : These are environments that are created when you use
287-
// `pyenv virtualenv <miniconda|anaconda> <env-name>`. These are similar to
288-
// environments created using `conda create -n <env-name>.
289-
//
290-
// All these environments are fully handled by `pyenv` and should be activated using
291-
// `pyenv local|global <env-name>` or `pyenv shell <env-name>`
292-
//
293-
// For the display name we are going to treat these as `pyenv` environments.
294-
const display = `${envDirName}:pyenv`;
295-
296-
const org = versionStrings && versionStrings.distro ? versionStrings.distro : '';
297-
298-
const fileInfo = await getFileInfo(interpreterPath);
299-
300-
const envInfo = buildEnvInfo({
301-
kind: PythonEnvKind.Pyenv,
302-
executable: interpreterPath,
303-
location: subDirPath,
304-
version: pythonVersion,
305-
source: [PythonEnvSource.Pyenv],
306-
display,
307-
org,
308-
fileInfo,
309-
});
310-
envInfo.name = envDirName;
311-
312-
yield envInfo;
270+
try {
271+
// The sub-directory name sometimes can contain distro and python versions.
272+
// here we attempt to extract the texts out of the name.
273+
const versionStrings = await parsePyenvVersion(envDirName);
274+
275+
// Here we look for near by files, or config files to see if we can get python version info
276+
// without running python itself.
277+
const pythonVersion = await getPythonVersionFromPath(interpreterPath, versionStrings?.pythonVer);
278+
279+
// Pyenv environments can fall in to these three categories:
280+
// 1. Global Installs : These are environments that are created when you install
281+
// a supported python distribution using `pyenv install <distro>` command.
282+
// These behave similar to globally installed version of python or distribution.
283+
//
284+
// 2. Virtual Envs : These are environments that are created when you use
285+
// `pyenv virtualenv <distro> <env-name>`. These are similar to environments
286+
// created using `python -m venv <env-name>`.
287+
//
288+
// 3. Conda Envs : These are environments that are created when you use
289+
// `pyenv virtualenv <miniconda|anaconda> <env-name>`. These are similar to
290+
// environments created using `conda create -n <env-name>.
291+
//
292+
// All these environments are fully handled by `pyenv` and should be activated using
293+
// `pyenv local|global <env-name>` or `pyenv shell <env-name>`
294+
//
295+
// For the display name we are going to treat these as `pyenv` environments.
296+
const display = `${envDirName}:pyenv`;
297+
298+
const org = versionStrings && versionStrings.distro ? versionStrings.distro : '';
299+
300+
const fileInfo = await getFileInfo(interpreterPath);
301+
302+
const envInfo = buildEnvInfo({
303+
kind: PythonEnvKind.Pyenv,
304+
executable: interpreterPath,
305+
location: subDirPath,
306+
version: pythonVersion,
307+
source: [PythonEnvSource.Pyenv],
308+
display,
309+
org,
310+
fileInfo,
311+
});
312+
envInfo.name = envDirName;
313+
yield envInfo;
314+
} catch (ex) {
315+
traceError(`Failed to process environment: ${interpreterPath}`, ex);
316+
}
313317
}
314318
}
315319
}

src/client/pythonEnvironments/discovery/locators/services/windowsRegistryLocator.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Licensed under the MIT License.
33

44
import { uniq } from 'lodash';
5-
import { traceVerbose } from '../../../../common/logger';
5+
import { traceError, traceVerbose } from '../../../../common/logger';
66
import { Architecture } from '../../../../common/utils/platform';
77
import {
88
PythonEnvInfo,
@@ -32,7 +32,13 @@ export class WindowsRegistryLocator extends Locator {
3232
const buildRegistryEnvInfo = (data: IRegistryInterpreterData) => this.buildRegistryEnvInfo(data);
3333
const iterator = async function* () {
3434
const interpreters = await getRegistryInterpreters();
35-
yield* interpreters.map(buildRegistryEnvInfo);
35+
for (const interpreter of interpreters) {
36+
try {
37+
yield buildRegistryEnvInfo(interpreter);
38+
} catch (ex) {
39+
traceError(`Failed to process environment: ${interpreter}`, ex);
40+
}
41+
}
3642
};
3743
return iterator();
3844
}

0 commit comments

Comments
 (0)