Skip to content

Commit 3b24031

Browse files
author
Kartik Raj
committed
Modify resolveEnv()
1 parent 1f00f38 commit 3b24031

File tree

3 files changed

+98
-28
lines changed

3 files changed

+98
-28
lines changed

src/client/pythonEnvironments/base/info/index.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -152,13 +152,22 @@ export type PythonEnvInfo = _PythonEnvInfo & {
152152
* @param environment2 - one of the two envs to compare
153153
*/
154154
export function areSameEnvironment(
155-
environment1: PythonEnvInfo,
156-
environment2: PythonEnvInfo,
155+
environment1: PythonEnvInfo | string,
156+
environment2: PythonEnvInfo | string,
157157
): boolean {
158-
if (!environment1 || !environment2) {
159-
return false;
158+
let path1: string;
159+
let path2: string;
160+
if (typeof environment1 === 'string') {
161+
path1 = environment1;
162+
} else {
163+
path1 = environment1.executable.filename;
160164
}
161-
if (arePathsSame(environment1.executable.filename, environment2.executable.filename)) {
165+
if (typeof environment2 === 'string') {
166+
path2 = environment2;
167+
} else {
168+
path2 = environment2.executable.filename;
169+
}
170+
if (arePathsSame(path1, path2)) {
162171
return true;
163172
}
164173
return false;

src/client/pythonEnvironments/collection/environmentsReducer.ts

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import { cloneDeep, isEqual } from 'lodash';
55
import { Event, EventEmitter } from 'vscode';
66
import { traceVerbose } from '../../common/logger';
7+
import { createDeferred } from '../../common/utils/async';
78
import { areSameEnvironment, PythonEnvInfo, PythonEnvKind } from '../base/info';
89
import {
910
ILocator, IPythonEnvsIterator, PythonEnvUpdatedEvent, QueryForEvent,
@@ -20,8 +21,30 @@ export class PythonEnvsReducer implements ILocator {
2021

2122
constructor(private readonly pythonEnvsManager: ILocator) {}
2223

23-
public resolveEnv(env: string | PythonEnvInfo): Promise<PythonEnvInfo | undefined> {
24-
return this.pythonEnvsManager.resolveEnv(env);
24+
public async resolveEnv(env: string | PythonEnvInfo): Promise<PythonEnvInfo | undefined> {
25+
let environment: PythonEnvInfo | undefined;
26+
const waitForUpdatesDeferred = createDeferred<void>();
27+
const iterator = this.iterEnvs();
28+
iterator.onUpdated!((event) => {
29+
if (event === null) {
30+
waitForUpdatesDeferred.resolve();
31+
} else if (environment && areSameEnvironment(environment, event.new)) {
32+
environment = event.new;
33+
}
34+
});
35+
let result = await iterator.next();
36+
while (!result.done) {
37+
if (areSameEnvironment(result.value, env)) {
38+
environment = result.value;
39+
}
40+
// eslint-disable-next-line no-await-in-loop
41+
result = await iterator.next();
42+
}
43+
if (!environment) {
44+
return undefined;
45+
}
46+
await waitForUpdatesDeferred.promise;
47+
return this.pythonEnvsManager.resolveEnv(environment);
2548
}
2649

2750
public iterEnvs(query?: QueryForEvent<PythonEnvsChangedEvent>): IPythonEnvsIterator {

src/test/pythonEnvironments/collection/environmentsReducer.unit.test.ts

Lines changed: 59 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ import { createEnv, getEnvs, SimpleLocator } from '../base/common';
1818
suite('Environments Reducer', () => {
1919
suite('iterEnvs()', () => {
2020
test('Iterator only yields unique environments', async () => {
21-
const env1 = createEnv('env1', '3.5.12b1', PythonEnvKind.Venv, path.join('path', 'to', 'exec1'));
22-
const env2 = createEnv('env2', '3.8.1', PythonEnvKind.Conda, path.join('path', 'to', 'exec2'));
21+
const env1 = createEnv('env1', '3.5', PythonEnvKind.Venv, path.join('path', 'to', 'exec1'));
22+
const env2 = createEnv('env2', '3.8', PythonEnvKind.Conda, path.join('path', 'to', 'exec2'));
2323
const env3 = createEnv('env3', '2.7', PythonEnvKind.System, path.join('path', 'to', 'exec3'));
24-
const env4 = createEnv('env4', '3.9.0rc2', PythonEnvKind.Unknown, path.join('path', 'to', 'exec2')); // Same as env2
25-
const env5 = createEnv('env5', '3.8', PythonEnvKind.Venv, path.join('path', 'to', 'exec1')); // Same as env1
24+
const env4 = createEnv('env4', '3.8.1', PythonEnvKind.Unknown, path.join('path', 'to', 'exec2')); // Same as env2
25+
const env5 = createEnv('env5', '3.5.12b1', PythonEnvKind.Venv, path.join('path', 'to', 'exec1')); // Same as env1
2626
const environmentsToBeIterated = [env1, env2, env3, env4, env5]; // Contains 3 unique environments
2727
const pythonEnvManager = new SimpleLocator(environmentsToBeIterated);
2828
const reducer = new PythonEnvsReducer(pythonEnvManager);
@@ -36,11 +36,11 @@ suite('Environments Reducer', () => {
3636

3737
test('Single updates for multiple environments are sent correctly followed by the null event', async () => {
3838
// Arrange
39-
const env1 = createEnv('env1', '3.5.12b1', PythonEnvKind.Unknown, path.join('path', 'to', 'exec1'));
40-
const env2 = createEnv('env2', '3.8.1', PythonEnvKind.Unknown, path.join('path', 'to', 'exec2'));
39+
const env1 = createEnv('env1', '3.5', PythonEnvKind.Unknown, path.join('path', 'to', 'exec1'));
40+
const env2 = createEnv('env2', '3.8', PythonEnvKind.Unknown, path.join('path', 'to', 'exec2'));
4141
const env3 = createEnv('env3', '2.7', PythonEnvKind.System, path.join('path', 'to', 'exec3'));
42-
const env4 = createEnv('env4', '3.9.0rc2', PythonEnvKind.Conda, path.join('path', 'to', 'exec2')); // Same as env2;
43-
const env5 = createEnv('env5', '3.8', PythonEnvKind.Venv, path.join('path', 'to', 'exec1')); // Same as env1;
42+
const env4 = createEnv('env4', '3.8.1', PythonEnvKind.Conda, path.join('path', 'to', 'exec2')); // Same as env2;
43+
const env5 = createEnv('env5', '3.5.12b1', PythonEnvKind.Venv, path.join('path', 'to', 'exec1')); // Same as env1;
4444
const environmentsToBeIterated = [env1, env2, env3, env4, env5]; // Contains 3 unique environments
4545
const pythonEnvManager = new SimpleLocator(environmentsToBeIterated);
4646
const onUpdatedEvents: (PythonEnvUpdatedEvent | null)[] = [];
@@ -160,21 +160,59 @@ suite('Environments Reducer', () => {
160160
assert.deepEqual(events, expected);
161161
});
162162

163-
test('Calls locator manager to resolves environments', async () => {
164-
const env = createEnv('env1', '3.8', PythonEnvKind.Unknown, path.join('path', 'to', 'exec'));
165-
const resolvedEnv = createEnv('env1', '3.8.1', PythonEnvKind.Conda, 'resolved/path/to/exec');
166-
const pythonEnvManager = new SimpleLocator([], {
167-
resolve: async (e: PythonEnvInfo) => {
168-
if (e === env) {
169-
return resolvedEnv;
170-
}
171-
return undefined;
172-
},
163+
suite('resolveEnv()', () => {
164+
test('Iterates environments from the reducer to get resolved environment, then calls into locator manager to resolve environment further and return it', async () => {
165+
const env1 = createEnv('env1', '3.8', PythonEnvKind.Unknown, path.join('path', 'to', 'exec'));
166+
const env2 = createEnv('env2', '2.7', PythonEnvKind.System, path.join('path', 'to', 'exec3'));
167+
const env3 = createEnv('env3', '3.8.1', PythonEnvKind.Conda, path.join('path', 'to', 'exec'));
168+
const env4 = createEnv('env4', '3.8.1', PythonEnvKind.Conda, path.join('path', 'to', 'exec2'));
169+
const env5 = createEnv('env5', '3.5.12b1', PythonEnvKind.Venv, path.join('path', 'to', 'exec1'));
170+
const env6 = createEnv('env6', '3.8.1', PythonEnvKind.System, path.join('path', 'to', 'exec'));
171+
const environmentsToBeIterated = [env1, env2, env3, env4, env5, env6]; // env1 env3 env6 are same
172+
173+
const env13 = mergeEnvironments(env1, env3);
174+
const env136 = mergeEnvironments(env13, env6);
175+
const expectedResolvedEnv = createEnv('resolvedEnv', '3.8.1', PythonEnvKind.Conda, 'resolved/path/to/exec');
176+
const pythonEnvManager = new SimpleLocator(environmentsToBeIterated, {
177+
resolve: async (e: PythonEnvInfo) => {
178+
if (isEqual(e, env136)) {
179+
return expectedResolvedEnv;
180+
}
181+
return undefined;
182+
},
183+
});
184+
const reducer = new PythonEnvsReducer(pythonEnvManager);
185+
186+
// Trying to resolve the environment corresponding to env1 env3 env6
187+
const expected = await reducer.resolveEnv(path.join('path', 'to', 'exec'));
188+
189+
assert.deepEqual(expected, expectedResolvedEnv);
173190
});
174-
const reducer = new PythonEnvsReducer(pythonEnvManager);
175191

176-
const expected = await reducer.resolveEnv(env);
192+
test("If the reducer isn't able to resolve environment, return undefined", async () => {
193+
const env1 = createEnv('env1', '3.8', PythonEnvKind.Unknown, path.join('path', 'to', 'exec'));
194+
const env2 = createEnv('env2', '2.7', PythonEnvKind.System, path.join('path', 'to', 'exec3'));
195+
const env3 = createEnv('env3', '3.8.1', PythonEnvKind.Conda, path.join('path', 'to', 'exec'));
196+
const env4 = createEnv('env4', '3.8.1', PythonEnvKind.Conda, path.join('path', 'to', 'exec2'));
197+
const env5 = createEnv('env5', '3.5.12b1', PythonEnvKind.Venv, path.join('path', 'to', 'exec1'));
198+
const env6 = createEnv('env6', '3.8.1', PythonEnvKind.System, path.join('path', 'to', 'exec'));
199+
const environmentsToBeIterated = [env1, env2, env3, env4, env5, env6]; // env1 env3 env6 are same
200+
201+
const env13 = mergeEnvironments(env1, env3);
202+
const env136 = mergeEnvironments(env13, env6);
203+
const pythonEnvManager = new SimpleLocator(environmentsToBeIterated, {
204+
resolve: async (e: PythonEnvInfo) => {
205+
if (isEqual(e, env136)) {
206+
return createEnv('resolvedEnv', '3.8.1', PythonEnvKind.Conda, 'resolved/path/to/exec');
207+
}
208+
return undefined;
209+
},
210+
});
211+
const reducer = new PythonEnvsReducer(pythonEnvManager);
212+
213+
const expected = await reducer.resolveEnv(path.join('path', 'to', 'execNeverSeenBefore'));
177214

178-
assert.deepEqual(expected, resolvedEnv);
215+
assert.deepEqual(expected, undefined);
216+
});
179217
});
180218
});

0 commit comments

Comments
 (0)