Skip to content

Commit 4325ac1

Browse files
authored
Log Conda not existing message as an information instead of an error (microsoft#1820)
Fixes microsoft#1817 Fixes microsoft#1821
1 parent 0429d13 commit 4325ac1

File tree

10 files changed

+53
-14
lines changed

10 files changed

+53
-14
lines changed

news/3 Code Health/1817.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Log Conda not existing message as an information instead of an error.

news/3 Code Health/1821.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Make use of `ILogger` to log messages instead of using `console.error`.

src/client/common/logger.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// tslint:disable:no-console
2+
13
import { injectable } from 'inversify';
24
import { ILogger } from './types';
35

@@ -19,6 +21,13 @@ export class Logger implements ILogger {
1921
console.warn(`${PREFIX}${message}`);
2022
}
2123
}
24+
public logInformation(message: string, ex?: Error) {
25+
if (ex) {
26+
console.info(`${PREFIX}${message}`, ex);
27+
} else {
28+
console.info(`${PREFIX}${message}`);
29+
}
30+
}
2231
}
2332
// tslint:disable-next-line:no-any
2433
export function error(title: string = '', message: any) {

src/client/common/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export const ILogger = Symbol('ILogger');
4141
export interface ILogger {
4242
logError(message: string, error?: Error);
4343
logWarning(message: string, error?: Error);
44+
logInformation(message: string, error?: Error);
4445
}
4546

4647
export enum InstallerResponse {

src/client/debugger/configProviders/configurationProviderUtils.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { Uri } from 'vscode';
99
import { IApplicationShell } from '../../common/application/types';
1010
import { IFileSystem } from '../../common/platform/types';
1111
import { IPythonExecutionFactory } from '../../common/process/types';
12+
import { ILogger } from '../../common/types';
1213
import { IServiceContainer } from '../../ioc/types';
1314
import { IConfigurationProviderUtils } from './types';
1415

@@ -18,9 +19,11 @@ const PSERVE_SCRIPT_FILE_NAME = 'pserve.py';
1819
export class ConfigurationProviderUtils implements IConfigurationProviderUtils {
1920
private readonly executionFactory: IPythonExecutionFactory;
2021
private readonly fs: IFileSystem;
22+
private readonly logger: ILogger;
2123
constructor(@inject(IServiceContainer) private serviceContainer: IServiceContainer) {
2224
this.executionFactory = this.serviceContainer.get<IPythonExecutionFactory>(IPythonExecutionFactory);
2325
this.fs = this.serviceContainer.get<IFileSystem>(IFileSystem);
26+
this.logger = this.serviceContainer.get<ILogger>(ILogger);
2427
}
2528
public async getPyramidStartupScriptFilePath(resource?: Uri): Promise<string | undefined> {
2629
try {
@@ -30,7 +33,7 @@ export class ConfigurationProviderUtils implements IConfigurationProviderUtils {
3033
return await this.fs.fileExists(pserveFilePath) ? pserveFilePath : undefined;
3134
} catch (ex) {
3235
const message = 'Unable to locate \'pserve.py\' required for debugging of Pyramid applications.';
33-
console.error(message, ex);
36+
this.logger.logError(message, ex);
3437
const app = this.serviceContainer.get<IApplicationShell>(IApplicationShell);
3538
app.showErrorMessage(message);
3639
return;

src/client/interpreter/locators/services/condaService.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ export class CondaService implements ICondaService {
142142
// Failed because either:
143143
// 1. conda is not installed.
144144
// 2. `conda env list has changed signature.
145-
this.logger.logError('Failed to get conda environment list from conda', ex);
145+
this.logger.logInformation('Failed to get conda environment list from conda', ex);
146146
}
147147
}
148148
public getInterpreterPath(condaEnvironmentPath: string): string {

src/client/interpreter/locators/services/pipEnvService.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@ import { Uri } from 'vscode';
77
import { IApplicationShell, IWorkspaceService } from '../../../common/application/types';
88
import { IFileSystem } from '../../../common/platform/types';
99
import { IProcessServiceFactory } from '../../../common/process/types';
10-
import { ICurrentProcess } from '../../../common/types';
11-
import { IEnvironmentVariablesProvider } from '../../../common/variables/types';
10+
import { ICurrentProcess, ILogger } from '../../../common/types';
1211
import { IServiceContainer } from '../../../ioc/types';
1312
import { IInterpreterHelper, InterpreterType, IPipEnvService, PythonInterpreter } from '../../contracts';
1413
import { CacheableLocatorService } from './cacheableLocatorService';
@@ -22,15 +21,15 @@ export class PipEnvService extends CacheableLocatorService implements IPipEnvSer
2221
private readonly processServiceFactory: IProcessServiceFactory;
2322
private readonly workspace: IWorkspaceService;
2423
private readonly fs: IFileSystem;
25-
private readonly envVarsProvider: IEnvironmentVariablesProvider;
24+
private readonly logger: ILogger;
2625

2726
constructor(@inject(IServiceContainer) serviceContainer: IServiceContainer) {
2827
super('PipEnvService', serviceContainer);
2928
this.helper = this.serviceContainer.get<IInterpreterHelper>(IInterpreterHelper);
3029
this.processServiceFactory = this.serviceContainer.get<IProcessServiceFactory>(IProcessServiceFactory);
3130
this.workspace = this.serviceContainer.get<IWorkspaceService>(IWorkspaceService);
3231
this.fs = this.serviceContainer.get<IFileSystem>(IFileSystem);
33-
this.envVarsProvider = this.serviceContainer.get<IEnvironmentVariablesProvider>(IEnvironmentVariablesProvider);
32+
this.logger = this.serviceContainer.get<ILogger>(ILogger);
3433
}
3534
// tslint:disable-next-line:no-empty
3635
public dispose() { }
@@ -127,7 +126,7 @@ export class PipEnvService extends CacheableLocatorService implements IPipEnvSer
127126
}
128127
// tslint:disable-next-line:no-empty
129128
} catch (error) {
130-
console.error(error);
129+
this.logger.logWarning('Error in invoking PipEnv', error);
131130
const errorMessage = error.message || error;
132131
const appShell = this.serviceContainer.get<IApplicationShell>(IApplicationShell);
133132
appShell.showWarningMessage(`Workspace contains pipfile but attempt to run 'pipenv --venv' failed with '${errorMessage}'. Make sure pipenv is on the PATH.`);

src/test/debugger/configProvider/provider.test.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { IApplicationShell, IDocumentManager, IWorkspaceService } from '../../..
1313
import { PYTHON_LANGUAGE } from '../../../client/common/constants';
1414
import { IFileSystem, IPlatformService } from '../../../client/common/platform/types';
1515
import { IPythonExecutionFactory, IPythonExecutionService } from '../../../client/common/process/types';
16-
import { IConfigurationService, IPythonSettings } from '../../../client/common/types';
16+
import { IConfigurationService, ILogger, IPythonSettings } from '../../../client/common/types';
1717
import { PythonDebugConfigurationProvider, PythonV2DebugConfigurationProvider } from '../../../client/debugger';
1818
import { DebugOptions, LaunchRequestArguments } from '../../../client/debugger/Common/Contracts';
1919
import { PythonLaunchDebugConfiguration } from '../../../client/debugger/configProviders/baseProvider';
@@ -32,6 +32,7 @@ import { IServiceContainer } from '../../../client/ioc/types';
3232
let fileSystem: TypeMoq.IMock<IFileSystem>;
3333
let appShell: TypeMoq.IMock<IApplicationShell>;
3434
let pythonExecutionService: TypeMoq.IMock<IPythonExecutionService>;
35+
let logger: TypeMoq.IMock<ILogger>;
3536
setup(() => {
3637
serviceContainer = TypeMoq.Mock.ofType<IServiceContainer>();
3738
debugProvider = new provider.class(serviceContainer.object);
@@ -46,6 +47,7 @@ import { IServiceContainer } from '../../../client/ioc/types';
4647
platformService = TypeMoq.Mock.ofType<IPlatformService>();
4748
fileSystem = TypeMoq.Mock.ofType<IFileSystem>();
4849
appShell = TypeMoq.Mock.ofType<IApplicationShell>();
50+
logger = TypeMoq.Mock.ofType<ILogger>();
4951

5052
pythonExecutionService = TypeMoq.Mock.ofType<IPythonExecutionService>();
5153
pythonExecutionService.setup((x: any) => x.then).returns(() => undefined);
@@ -58,6 +60,7 @@ import { IServiceContainer } from '../../../client/ioc/types';
5860
serviceContainer.setup(c => c.get(TypeMoq.It.isValue(IFileSystem))).returns(() => fileSystem.object);
5961
serviceContainer.setup(c => c.get(TypeMoq.It.isValue(IApplicationShell))).returns(() => appShell.object);
6062
serviceContainer.setup(c => c.get(TypeMoq.It.isValue(IConfigurationProviderUtils))).returns(() => new ConfigurationProviderUtils(serviceContainer.object));
63+
serviceContainer.setup(c => c.get(TypeMoq.It.isValue(ILogger))).returns(() => logger.object);
6164

6265
const settings = TypeMoq.Mock.ofType<IPythonSettings>();
6366
settings.setup(s => s.pythonPath).returns(() => pythonPath);
@@ -350,6 +353,8 @@ import { IServiceContainer } from '../../../client/ioc/types';
350353
.verifiable(TypeMoq.Times.exactly(pyramidExists && addPyramidDebugOption ? 1 : 0));
351354
appShell.setup(a => a.showErrorMessage(TypeMoq.It.isAny()))
352355
.verifiable(TypeMoq.Times.exactly(pyramidExists || !addPyramidDebugOption ? 0 : 1));
356+
logger.setup(a => a.logError(TypeMoq.It.isAny(), TypeMoq.It.isAny()))
357+
.verifiable(TypeMoq.Times.exactly(pyramidExists || !addPyramidDebugOption ? 0 : 1));
353358
const options = addPyramidDebugOption ? { debugOptions: [DebugOptions.Pyramid], pyramid: true } : {};
354359

355360
const debugConfig = await debugProvider.resolveDebugConfiguration!(workspaceFolder, options as any as DebugConfiguration);
@@ -366,6 +371,7 @@ import { IServiceContainer } from '../../../client/ioc/types';
366371
pythonExecutionService.verifyAll();
367372
fileSystem.verifyAll();
368373
appShell.verifyAll();
374+
logger.verifyAll();
369375
}
370376
test('Program is set for Pyramid (windows)', async () => {
371377
await testPyramidConfiguration(true, false, false);

src/test/interpreters/condaService.test.ts

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,9 @@ suite('Interpreters Conda Service', () => {
3737
let registryInterpreterLocatorService: TypeMoq.IMock<IInterpreterLocatorService>;
3838
let serviceContainer: TypeMoq.IMock<IServiceContainer>;
3939
let procServiceFactory: TypeMoq.IMock<IProcessServiceFactory>;
40+
let logger: TypeMoq.IMock<ILogger>;
4041
setup(async () => {
41-
const logger = TypeMoq.Mock.ofType<ILogger>();
42+
logger = TypeMoq.Mock.ofType<ILogger>();
4243
processService = TypeMoq.Mock.ofType<IProcessService>();
4344
platformService = TypeMoq.Mock.ofType<IPlatformService>();
4445
registryInterpreterLocatorService = TypeMoq.Mock.ofType<IInterpreterLocatorService>();
@@ -415,7 +416,6 @@ suite('Interpreters Conda Service', () => {
415416
test('Returns conda environments when conda exists', async () => {
416417
const stateFactory = TypeMoq.Mock.ofType<IPersistentStateFactory>();
417418
serviceContainer.setup(c => c.get(TypeMoq.It.isValue(IPersistentStateFactory))).returns(() => stateFactory.object);
418-
// tslint:disable-next-line:no-any
419419
const state = new MockState(undefined);
420420
stateFactory.setup(s => s.createGlobalPersistentState(TypeMoq.It.isValue('CONDA_ENVIRONMENTS'), TypeMoq.It.isValue(undefined))).returns(() => state);
421421

@@ -425,10 +425,24 @@ suite('Interpreters Conda Service', () => {
425425
assert.equal(environments, undefined, 'Conda environments do not match');
426426
});
427427

428+
test('Logs information message when conda does not exist', async () => {
429+
const stateFactory = TypeMoq.Mock.ofType<IPersistentStateFactory>();
430+
serviceContainer.setup(c => c.get(TypeMoq.It.isValue(IPersistentStateFactory))).returns(() => stateFactory.object);
431+
const state = new MockState(undefined);
432+
stateFactory.setup(s => s.createGlobalPersistentState(TypeMoq.It.isValue('CONDA_ENVIRONMENTS'), TypeMoq.It.isValue(undefined))).returns(() => state);
433+
434+
processService.setup(p => p.exec(TypeMoq.It.isValue('conda'), TypeMoq.It.isValue(['--version']), TypeMoq.It.isAny())).returns(() => Promise.reject(new Error('Not Found')));
435+
processService.setup(p => p.exec(TypeMoq.It.isValue('conda'), TypeMoq.It.isValue(['env', 'list']), TypeMoq.It.isAny())).returns(() => Promise.reject(new Error('Not Found')));
436+
logger.setup(l => l.logInformation(TypeMoq.It.isAny(), TypeMoq.It.isAny()))
437+
.verifiable(TypeMoq.Times.once());
438+
const environments = await condaService.getCondaEnvironments(true);
439+
assert.equal(environments, undefined, 'Conda environments do not match');
440+
logger.verifyAll();
441+
});
442+
428443
test('Returns cached conda environments', async () => {
429444
const stateFactory = TypeMoq.Mock.ofType<IPersistentStateFactory>();
430445
serviceContainer.setup(c => c.get(TypeMoq.It.isValue(IPersistentStateFactory))).returns(() => stateFactory.object);
431-
// tslint:disable-next-line:no-any
432446
const state = new MockState({ data: 'CachedInfo' });
433447
stateFactory.setup(s => s.createGlobalPersistentState(TypeMoq.It.isValue('CONDA_ENVIRONMENTS'), TypeMoq.It.isValue(undefined))).returns(() => state);
434448

@@ -441,7 +455,6 @@ suite('Interpreters Conda Service', () => {
441455
test('Subsequent list of environments will be retrieved from cache', async () => {
442456
const stateFactory = TypeMoq.Mock.ofType<IPersistentStateFactory>();
443457
serviceContainer.setup(c => c.get(TypeMoq.It.isValue(IPersistentStateFactory))).returns(() => stateFactory.object);
444-
// tslint:disable-next-line:no-any
445458
const state = new MockState(undefined);
446459
stateFactory.setup(s => s.createGlobalPersistentState(TypeMoq.It.isValue('CONDA_ENVIRONMENTS'), TypeMoq.It.isValue(undefined))).returns(() => state);
447460

src/test/interpreters/pipEnvService.test.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { IApplicationShell, IWorkspaceService } from '../../client/common/applic
1313
import { EnumEx } from '../../client/common/enumUtils';
1414
import { IFileSystem } from '../../client/common/platform/types';
1515
import { IProcessService, IProcessServiceFactory } from '../../client/common/process/types';
16-
import { ICurrentProcess, IPersistentState, IPersistentStateFactory } from '../../client/common/types';
16+
import { ICurrentProcess, ILogger, IPersistentState, IPersistentStateFactory } from '../../client/common/types';
1717
import { IEnvironmentVariablesProvider } from '../../client/common/variables/types';
1818
import { IInterpreterHelper, IInterpreterLocatorService } from '../../client/interpreter/contracts';
1919
import { PipEnvService } from '../../client/interpreter/locators/services/pipEnvService';
@@ -39,6 +39,7 @@ suite('Interpreters - PipEnv', () => {
3939
let persistentStateFactory: TypeMoq.IMock<IPersistentStateFactory>;
4040
let envVarsProvider: TypeMoq.IMock<IEnvironmentVariablesProvider>;
4141
let procServiceFactory: TypeMoq.IMock<IProcessServiceFactory>;
42+
let logger: TypeMoq.IMock<ILogger>;
4243
setup(() => {
4344
serviceContainer = TypeMoq.Mock.ofType<IServiceContainer>();
4445
const workspaceService = TypeMoq.Mock.ofType<IWorkspaceService>();
@@ -50,6 +51,7 @@ suite('Interpreters - PipEnv', () => {
5051
persistentStateFactory = TypeMoq.Mock.ofType<IPersistentStateFactory>();
5152
envVarsProvider = TypeMoq.Mock.ofType<IEnvironmentVariablesProvider>();
5253
procServiceFactory = TypeMoq.Mock.ofType<IProcessServiceFactory>();
54+
logger = TypeMoq.Mock.ofType<ILogger>();
5355
processService.setup((x: any) => x.then).returns(() => undefined);
5456
procServiceFactory.setup(p => p.create(TypeMoq.It.isAny())).returns(() => Promise.resolve(processService.object));
5557

@@ -73,6 +75,7 @@ suite('Interpreters - PipEnv', () => {
7375
serviceContainer.setup(c => c.get(TypeMoq.It.isValue(IApplicationShell))).returns(() => appShell.object);
7476
serviceContainer.setup(c => c.get(TypeMoq.It.isValue(IPersistentStateFactory))).returns(() => persistentStateFactory.object);
7577
serviceContainer.setup(c => c.get(TypeMoq.It.isValue(IEnvironmentVariablesProvider))).returns(() => envVarsProvider.object);
78+
serviceContainer.setup(c => c.get(TypeMoq.It.isValue(ILogger))).returns(() => logger.object);
7679

7780
pipEnvService = new PipEnvService(serviceContainer.object);
7881
});
@@ -97,22 +100,25 @@ suite('Interpreters - PipEnv', () => {
97100
processService.setup(p => p.exec(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.reject(''));
98101
fileSystem.setup(fs => fs.fileExists(TypeMoq.It.isValue(path.join(rootWorkspace, 'Pipfile')))).returns(() => Promise.resolve(true));
99102
appShell.setup(a => a.showWarningMessage(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve('')).verifiable(TypeMoq.Times.once());
103+
logger.setup(l => l.logWarning(TypeMoq.It.isAny(), TypeMoq.It.isAny())).verifiable(TypeMoq.Times.once());
100104
const environments = await pipEnvService.getInterpreters(resource);
101105

102106
expect(environments).to.be.deep.equal([]);
103107
appShell.verifyAll();
104-
appShell.verifyAll();
108+
logger.verifyAll();
105109
});
106110
test(`Should display warning message if there is a \'PipFile\' but \'pipenv --venv\' failes with stderr ${testSuffix}`, async () => {
107111
const env = {};
108112
currentProcess.setup(c => c.env).returns(() => env);
109113
processService.setup(p => p.exec(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve({ stderr: 'PipEnv Failed', stdout: '' }));
110114
fileSystem.setup(fs => fs.fileExists(TypeMoq.It.isValue(path.join(rootWorkspace, 'Pipfile')))).returns(() => Promise.resolve(true));
111115
appShell.setup(a => a.showWarningMessage(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve('')).verifiable(TypeMoq.Times.once());
116+
logger.setup(l => l.logWarning(TypeMoq.It.isAny(), TypeMoq.It.isAny())).verifiable(TypeMoq.Times.once());
112117
const environments = await pipEnvService.getInterpreters(resource);
113118

114119
expect(environments).to.be.deep.equal([]);
115120
appShell.verifyAll();
121+
logger.verifyAll();
116122
});
117123
test(`Should return interpreter information${testSuffix}`, async () => {
118124
const env = {};

0 commit comments

Comments
 (0)