Skip to content

Commit 7f8b194

Browse files
committed
Address comments
1 parent 2d2cf77 commit 7f8b194

File tree

5 files changed

+131
-83
lines changed

5 files changed

+131
-83
lines changed

src/client/pythonEnvironments/base/info/envInfoHelpers.ts renamed to src/client/pythonEnvironments/base/info/env.ts

Lines changed: 83 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@
44
import { cloneDeep } from 'lodash';
55
import * as path from 'path';
66
import {
7-
PythonEnvInfo, PythonEnvKind, PythonExecutableInfo, PythonVersion,
7+
FileInfo,
8+
PythonDistroInfo,
9+
PythonEnvInfo, PythonEnvKind, PythonVersion,
810
} from '.';
11+
import { Architecture } from '../../../common/utils/platform';
912
import { arePathsSame } from '../../common/externalDependencies';
10-
import { areEqualVersions } from './versionHelpers';
13+
import { areEqualVersions, areEquivalentVersions } from './pythonVersion';
1114

1215
export function areSameEnvironment(
1316
left: string | PythonEnvInfo,
@@ -25,14 +28,9 @@ export function areSameEnvironment(
2528
const leftVersion = typeof left === 'string' ? undefined : left.version;
2629
const rightVersion = typeof right === 'string' ? undefined : right.version;
2730
if (leftVersion && rightVersion) {
28-
if (areEqualVersions(leftVersion, rightVersion)) {
29-
return true;
30-
}
31-
3231
if (
33-
allowPartialMatch
34-
&& leftVersion.major === rightVersion.major
35-
&& leftVersion.minor === rightVersion.minor
32+
areEqualVersions(leftVersion, rightVersion)
33+
|| (allowPartialMatch && areEquivalentVersions(leftVersion, rightVersion))
3634
) {
3735
return true;
3836
}
@@ -48,7 +46,7 @@ export function areSameEnvironment(
4846
* weighted by most important to least important fields.
4947
* Wn > Wn-1 + Wn-2 + ... W0
5048
*/
51-
function getVersionInfoHeuristic(version:PythonVersion): number {
49+
function getPythonVersionInfoHeuristic(version:PythonVersion): number {
5250
let infoLevel = 0;
5351
if (version.major > 0) {
5452
infoLevel += 20; // W4
@@ -75,32 +73,56 @@ function getVersionInfoHeuristic(version:PythonVersion): number {
7573

7674
/**
7775
* Returns a heuristic value on how much information is available in the given executable object.
78-
* @param {PythonExecutableInfo} executable executable object to generate heuristic from.
76+
* @param {FileInfo} executable executable object to generate heuristic from.
7977
* @returns A heuristic value indicating the amount of info available in the object
8078
* weighted by most important to least important fields.
8179
* Wn > Wn-1 + Wn-2 + ... W0
8280
*/
83-
function getExecutableInfoHeuristic(executable:PythonExecutableInfo): number {
81+
function getFileInfoHeuristic(file:FileInfo): number {
8482
let infoLevel = 0;
85-
if (executable.filename.length > 0) {
86-
infoLevel += 10; // W3
87-
}
88-
89-
if (executable.sysPrefix.length > 0) {
83+
if (file.filename.length > 0) {
9084
infoLevel += 5; // W2
9185
}
9286

93-
if (executable.mtime) {
87+
if (file.mtime) {
9488
infoLevel += 2; // W1
9589
}
9690

97-
if (executable.ctime) {
91+
if (file.ctime || file.mtime) {
9892
infoLevel += 1; // W0
9993
}
10094

10195
return infoLevel;
10296
}
10397

98+
/**
99+
* Returns a heuristic value on how much information is available in the given distro object.
100+
* @param {PythonDistroInfo} distro distro object to generate heuristic from.
101+
* @returns A heuristic value indicating the amount of info available in the object
102+
* weighted by most important to least important fields.
103+
* Wn > Wn-1 + Wn-2 + ... W0
104+
*/
105+
function getDistroInfoHeuristic(distro:PythonDistroInfo):number {
106+
let infoLevel = 0;
107+
if (distro.org.length > 0) {
108+
infoLevel += 20; // W3
109+
}
110+
111+
if (distro.defaultDisplayName) {
112+
infoLevel += 10; // W2
113+
}
114+
115+
if (distro.binDir) {
116+
infoLevel += 5; // W1
117+
}
118+
119+
if (distro.version) {
120+
infoLevel += 2;
121+
}
122+
123+
return infoLevel;
124+
}
125+
104126
/**
105127
* Gets a prioritized list of environment types for identification.
106128
* @returns {PythonEnvKind[]} : List of environments ordered by identification priority
@@ -144,35 +166,58 @@ export function getPrioritizedEnvironmentKind(): PythonEnvKind[] {
144166
}
145167

146168
/**
147-
* Selects an environment kind based on the environment selection priority. This should
169+
* Selects an environment based on the environment selection priority. This should
148170
* match the priority in the environment identifier.
149-
* @param left
150-
* @param right
151171
*/
152-
function pickEnvironmentKind(left: PythonEnvInfo, right: PythonEnvInfo): PythonEnvKind {
172+
export function sortEnvInfoByPriority(...envs: PythonEnvInfo[]): PythonEnvInfo[] {
153173
// tslint:disable-next-line: no-suspicious-comment
154174
// TODO: When we consolidate the PythonEnvKind and EnvironmentType we should have
155175
// one location where we define priority and
156176
const envKindByPriority:PythonEnvKind[] = getPrioritizedEnvironmentKind();
157-
158-
return envKindByPriority.find((env) => left.kind === env || right.kind === env) ?? PythonEnvKind.Unknown;
177+
return envs.sort(
178+
(a:PythonEnvInfo, b:PythonEnvInfo) => envKindByPriority.indexOf(a.kind) - envKindByPriority.indexOf(b.kind),
179+
);
159180
}
160181

161-
export function mergeEnvironments(left: PythonEnvInfo, right: PythonEnvInfo): PythonEnvInfo {
162-
const kind = pickEnvironmentKind(left, right);
163-
const version = (getVersionInfoHeuristic(left.version) > getVersionInfoHeuristic(right.version)
164-
? left.version : right.version
182+
/**
183+
* Merges properties of the `target` environment and `other` environment and returns the merged environment.
184+
* if the value in the `target` environment is not defined or has less information. This does not mutate
185+
* the `target` instead it returns a new object that contains the merged results.
186+
* @param {PythonEnvInfo} target : Properties of this object are favored.
187+
* @param {PythonEnvInfo} other : Properties of this object are used to fill the gaps in the merged result.
188+
*/
189+
export function mergeEnvironments(target: PythonEnvInfo, other: PythonEnvInfo): PythonEnvInfo {
190+
const merged = cloneDeep(target);
191+
192+
const version = cloneDeep(
193+
getPythonVersionInfoHeuristic(target.version) > getPythonVersionInfoHeuristic(other.version)
194+
? target.version : other.version,
165195
);
166-
const executable = (getExecutableInfoHeuristic(left.executable) > getExecutableInfoHeuristic(right.executable)
167-
? left.executable : right.executable
196+
197+
const executable = cloneDeep(
198+
getFileInfoHeuristic(target.executable) > getFileInfoHeuristic(other.executable)
199+
? target.executable : other.executable,
168200
);
169-
const preferredEnv:PythonEnvInfo = left.kind === kind ? left : right;
170-
const merged = cloneDeep(preferredEnv);
171-
merged.version = cloneDeep(version);
172-
merged.executable = cloneDeep(executable);
201+
executable.sysPrefix = target.executable.sysPrefix ?? other.executable.sysPrefix;
202+
203+
const distro = cloneDeep(
204+
getDistroInfoHeuristic(target.distro) > getDistroInfoHeuristic(other.distro)
205+
? target.distro : other.distro,
206+
);
207+
208+
merged.arch = merged.arch === Architecture.Unknown ? other.arch : target.arch;
209+
merged.defaultDisplayName = merged.defaultDisplayName ?? other.defaultDisplayName;
210+
merged.distro = distro;
211+
merged.executable = executable;
212+
213+
// No need to check this just use preferred kind. Since the first thing we do is figure out the
214+
// preferred env based on kind.
215+
merged.kind = target.kind;
216+
217+
merged.location = merged.location ?? other.location;
218+
merged.name = merged.name ?? other.name;
219+
merged.searchLocation = merged.searchLocation ?? other.searchLocation;
220+
merged.version = version;
173221

174-
// tslint:disable-next-line: no-suspicious-comment
175-
// TODO: compute id for the merged environment
176-
merged.id = '';
177222
return merged;
178223
}

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

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,21 @@ export enum PythonEnvKind {
2929
}
3030

3131
/**
32-
* Information about a Python binary/executable.
32+
* Information about a file.
3333
*/
34-
export type PythonExecutableInfo = {
34+
export type FileInfo = {
3535
filename: string;
36-
sysPrefix: string;
3736
ctime: number;
3837
mtime: number;
3938
};
4039

40+
/**
41+
* Information about a Python binary/executable.
42+
*/
43+
export type PythonExecutableInfo = FileInfo & {
44+
sysPrefix: string;
45+
};
46+
4147
/**
4248
* A (system-global) unique ID for a single Python environment.
4349
*/

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

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,40 @@ export function parseVersion(versionStr: string): PythonVersion {
3333
}
3434
return version;
3535
}
36+
37+
/**
38+
* Checks if all the fields in the version object match.
39+
* @param {PythonVersion} left
40+
* @param {PythonVersion} right
41+
* @returns {boolean}
42+
*/
43+
export function areEqualVersions(left: PythonVersion, right:PythonVersion): boolean {
44+
return (
45+
left.major === right.major
46+
&& left.minor === right.minor
47+
&& left.micro === right.micro
48+
&& left.release.level === right.release.level
49+
&& left.release.serial === right.release.serial
50+
);
51+
}
52+
53+
/**
54+
* Checks if major and minor version fields match. True here means that the python ABI is the
55+
* same, but the micro version could be different. But for the purpose this is being used
56+
* it does not matter.
57+
* @param {PythonVersion} left
58+
* @param {PythonVersion} right
59+
* @returns {boolean}
60+
*/
61+
export function areEquivalentVersions(left: PythonVersion, right:PythonVersion): boolean {
62+
if (left.major === 2 && right.major === 2) {
63+
// We are going to assume that if the major version is 2 then the version is 2.7
64+
return true;
65+
}
66+
67+
// In the case of 3.* if major and minor match we assume that they are equivalent versions
68+
return (
69+
left.major === right.major
70+
&& left.minor === right.minor
71+
);
72+
}

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

Lines changed: 0 additions & 41 deletions
This file was deleted.

src/client/pythonEnvironments/collection/environmentsReducer.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ import { cloneDeep, isEqual } from 'lodash';
55
import { Event, EventEmitter } from 'vscode';
66
import { traceVerbose } from '../../common/logger';
77
import { createDeferred } from '../../common/utils/async';
8-
import { areSameEnvironment, PythonEnvInfo, PythonEnvKind } from '../base/info';
8+
import { PythonEnvInfo, PythonEnvKind } from '../base/info';
9+
import { areSameEnvironment } from '../base/info/env';
910
import {
1011
ILocator, IPythonEnvsIterator, PythonEnvUpdatedEvent, QueryForEvent,
1112
} from '../base/locator';

0 commit comments

Comments
 (0)