Skip to content

Commit c64ff49

Browse files
committed
Normalize file paths across environment managers to ensure consistent handling of paths
1 parent e4b1332 commit c64ff49

7 files changed

Lines changed: 125 additions & 78 deletions

File tree

src/managers/builtin/sysPythonManager.ts

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
} from '../../api';
2020
import { SysManagerStrings } from '../../common/localize';
2121
import { createDeferred, Deferred } from '../../common/utils/deferred';
22+
import { normalizePath } from '../../common/utils/pathUtils';
2223
import { NativePythonFinder } from '../common/nativePythonFinder';
2324
import { getLatest } from '../common/utils';
2425
import {
@@ -134,7 +135,7 @@ export class SysPythonManager implements EnvironmentManager {
134135
}
135136

136137
if (scope instanceof Uri) {
137-
const env = this.fsPathToEnv.get(scope.fsPath);
138+
const env = this.fsPathToEnv.get(normalizePath(scope.fsPath));
138139
if (env) {
139140
return [env];
140141
}
@@ -171,10 +172,11 @@ export class SysPythonManager implements EnvironmentManager {
171172
return;
172173
}
173174

175+
const normalizedPwPath = normalizePath(pw.uri.fsPath);
174176
if (environment) {
175-
this.fsPathToEnv.set(pw.uri.fsPath, environment);
177+
this.fsPathToEnv.set(normalizedPwPath, environment);
176178
} else {
177-
this.fsPathToEnv.delete(pw.uri.fsPath);
179+
this.fsPathToEnv.delete(normalizedPwPath);
178180
}
179181
await setSystemEnvForWorkspace(pw.uri.fsPath, environment?.environmentPath.fsPath);
180182
}
@@ -191,11 +193,12 @@ export class SysPythonManager implements EnvironmentManager {
191193

192194
const before: Map<string, PythonEnvironment | undefined> = new Map();
193195
projects.forEach((p) => {
194-
before.set(p.uri.fsPath, this.fsPathToEnv.get(p.uri.fsPath));
196+
const normalizedPath = normalizePath(p.uri.fsPath);
197+
before.set(p.uri.fsPath, this.fsPathToEnv.get(normalizedPath));
195198
if (environment) {
196-
this.fsPathToEnv.set(p.uri.fsPath, environment);
199+
this.fsPathToEnv.set(normalizedPath, environment);
197200
} else {
198-
this.fsPathToEnv.delete(p.uri.fsPath);
201+
this.fsPathToEnv.delete(normalizedPath);
199202
}
200203
});
201204

@@ -282,24 +285,28 @@ export class SysPythonManager implements EnvironmentManager {
282285
}
283286

284287
private findEnvironmentByPath(fsPath: string): PythonEnvironment | undefined {
285-
const normalized = path.normalize(fsPath); // /opt/homebrew/bin/python3.12
288+
const normalized = normalizePath(fsPath);
286289
return this.collection.find((e) => {
287-
const n = path.normalize(e.environmentPath.fsPath);
288-
return n === normalized || path.dirname(n) === normalized || path.dirname(path.dirname(n)) === normalized;
290+
const n = normalizePath(e.environmentPath.fsPath);
291+
return (
292+
n === normalized ||
293+
normalizePath(path.dirname(e.environmentPath.fsPath)) === normalized ||
294+
normalizePath(path.dirname(path.dirname(e.environmentPath.fsPath))) === normalized
295+
);
289296
});
290297
}
291298

292299
private fromEnvMap(uri: Uri): PythonEnvironment | undefined {
293300
// Find environment directly using the URI mapping
294-
const env = this.fsPathToEnv.get(uri.fsPath);
301+
const env = this.fsPathToEnv.get(normalizePath(uri.fsPath));
295302
if (env) {
296303
return env;
297304
}
298305

299306
// Find environment using the Python project for the Uri
300307
const project = this.api.getPythonProject(uri);
301308
if (project) {
302-
return this.fsPathToEnv.get(project.uri.fsPath);
309+
return this.fsPathToEnv.get(normalizePath(project.uri.fsPath));
303310
}
304311

305312
return this.globalEnv;
@@ -332,7 +339,7 @@ export class SysPythonManager implements EnvironmentManager {
332339
}
333340

334341
// Try to find workspace environments
335-
const paths = this.api.getPythonProjects().map((p) => p.uri.fsPath);
342+
const paths = this.api.getPythonProjects().map((p) => normalizePath(p.uri.fsPath));
336343

337344
// Iterate over each path
338345
for (const p of paths) {

src/managers/builtin/venvManager.ts

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -291,15 +291,15 @@ export class VenvManager implements EnvironmentManager {
291291
}
292292

293293
private updateCollection(environment: PythonEnvironment): void {
294-
this.collection = this.collection.filter(
295-
(e) => e.environmentPath.fsPath !== environment.environmentPath.fsPath,
296-
);
294+
const envPath = normalizePath(environment.environmentPath.fsPath);
295+
this.collection = this.collection.filter((e) => normalizePath(e.environmentPath.fsPath) !== envPath);
297296
}
298297

299298
private updateFsPathToEnv(environment: PythonEnvironment): Uri[] {
299+
const envPath = normalizePath(environment.environmentPath.fsPath);
300300
const changed: Uri[] = [];
301301
this.fsPathToEnv.forEach((env, uri) => {
302-
if (env.environmentPath.fsPath === environment.environmentPath.fsPath) {
302+
if (normalizePath(env.environmentPath.fsPath) === envPath) {
303303
this.fsPathToEnv.delete(uri);
304304
changed.push(Uri.file(uri));
305305
}
@@ -361,7 +361,7 @@ export class VenvManager implements EnvironmentManager {
361361
return [];
362362
}
363363

364-
const env = this.fsPathToEnv.get(scope.fsPath);
364+
const env = this.fsPathToEnv.get(normalizePath(scope.fsPath));
365365
return env ? [env] : [];
366366
}
367367

@@ -378,7 +378,7 @@ export class VenvManager implements EnvironmentManager {
378378
return this.globalEnv;
379379
}
380380

381-
let env = this.fsPathToEnv.get(project.uri.fsPath);
381+
let env = this.fsPathToEnv.get(normalizePath(project.uri.fsPath));
382382
if (!env) {
383383
env = this.findEnvironmentByPath(project.uri.fsPath);
384384
}
@@ -414,11 +414,12 @@ export class VenvManager implements EnvironmentManager {
414414
}
415415
}
416416

417-
const before = this.fsPathToEnv.get(pw.uri.fsPath);
417+
const normalizedPwPath = normalizePath(pw.uri.fsPath);
418+
const before = this.fsPathToEnv.get(normalizedPwPath);
418419
if (environment) {
419-
this.fsPathToEnv.set(pw.uri.fsPath, environment);
420+
this.fsPathToEnv.set(normalizedPwPath, environment);
420421
} else {
421-
this.fsPathToEnv.delete(pw.uri.fsPath);
422+
this.fsPathToEnv.delete(normalizedPwPath);
422423
}
423424
await setVenvForWorkspace(pw.uri.fsPath, environment?.environmentPath.fsPath);
424425

@@ -439,11 +440,12 @@ export class VenvManager implements EnvironmentManager {
439440

440441
const before: Map<string, PythonEnvironment | undefined> = new Map();
441442
projects.forEach((p) => {
442-
before.set(p.uri.fsPath, this.fsPathToEnv.get(p.uri.fsPath));
443+
const normalizedPath = normalizePath(p.uri.fsPath);
444+
before.set(p.uri.fsPath, this.fsPathToEnv.get(normalizedPath));
443445
if (environment) {
444-
this.fsPathToEnv.set(p.uri.fsPath, environment);
446+
this.fsPathToEnv.set(normalizedPath, environment);
445447
} else {
446-
this.fsPathToEnv.delete(p.uri.fsPath);
448+
this.fsPathToEnv.delete(normalizedPath);
447449
}
448450
});
449451

src/managers/common/utils.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,13 @@ export function isGreater(a: string | undefined, b: string | undefined): boolean
6868

6969
export function sortEnvironments(collection: PythonEnvironment[]): PythonEnvironment[] {
7070
return collection.sort((a, b) => {
71+
// Environments with errors should be sorted to the end
72+
if (a.error && !b.error) {
73+
return 1;
74+
}
75+
if (!a.error && b.error) {
76+
return -1;
77+
}
7178
if (a.version !== b.version) {
7279
return isGreater(a.version, b.version) ? -1 : 1;
7380
}
@@ -83,8 +90,12 @@ export function getLatest(collection: PythonEnvironment[]): PythonEnvironment |
8390
if (collection.length === 0) {
8491
return undefined;
8592
}
86-
let latest = collection[0];
87-
for (const env of collection) {
93+
// Filter out environments with errors first, then find latest
94+
const nonErroredEnvs = collection.filter((e) => !e.error);
95+
const candidates = nonErroredEnvs.length > 0 ? nonErroredEnvs : collection;
96+
97+
let latest = candidates[0];
98+
for (const env of candidates) {
8899
if (isGreater(env.version, latest.version)) {
89100
latest = env;
90101
}

src/managers/conda/condaEnvManager.ts

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
import { CondaStrings } from '../../common/localize';
2323
import { traceError } from '../../common/logging';
2424
import { createDeferred, Deferred } from '../../common/utils/deferred';
25+
import { normalizePath } from '../../common/utils/pathUtils';
2526
import { showErrorMessage, withProgress } from '../../common/window.apis';
2627
import { NativePythonFinder } from '../common/nativePythonFinder';
2728
import { CondaSourcingStatus } from './condaSourcingUtils';
@@ -261,13 +262,13 @@ export class CondaEnvManager implements EnvironmentManager, Disposable {
261262
async get(scope: GetEnvironmentScope): Promise<PythonEnvironment | undefined> {
262263
await this.initialize();
263264
if (scope instanceof Uri) {
264-
let env = this.fsPathToEnv.get(scope.fsPath);
265+
let env = this.fsPathToEnv.get(normalizePath(scope.fsPath));
265266
if (env) {
266267
return env;
267268
}
268269
const project = this.api.getPythonProject(scope);
269270
if (project) {
270-
env = this.fsPathToEnv.get(project.uri.fsPath);
271+
env = this.fsPathToEnv.get(normalizePath(project.uri.fsPath));
271272
if (env) {
272273
return env;
273274
}
@@ -288,10 +289,11 @@ export class CondaEnvManager implements EnvironmentManager, Disposable {
288289
const folder = this.api.getPythonProject(scope);
289290
const fsPath = folder?.uri?.fsPath ?? scope.fsPath;
290291
if (fsPath) {
292+
const normalizedFsPath = normalizePath(fsPath);
291293
if (checkedEnv) {
292-
this.fsPathToEnv.set(fsPath, checkedEnv);
294+
this.fsPathToEnv.set(normalizedFsPath, checkedEnv);
293295
} else {
294-
this.fsPathToEnv.delete(fsPath);
296+
this.fsPathToEnv.delete(normalizedFsPath);
295297
}
296298
await setCondaForWorkspace(fsPath, checkedEnv?.environmentPath.fsPath);
297299
}
@@ -307,11 +309,12 @@ export class CondaEnvManager implements EnvironmentManager, Disposable {
307309

308310
const before: Map<string, PythonEnvironment | undefined> = new Map();
309311
projects.forEach((p) => {
310-
before.set(p.uri.fsPath, this.fsPathToEnv.get(p.uri.fsPath));
312+
const normalizedPath = normalizePath(p.uri.fsPath);
313+
before.set(p.uri.fsPath, this.fsPathToEnv.get(normalizedPath));
311314
if (checkedEnv) {
312-
this.fsPathToEnv.set(p.uri.fsPath, checkedEnv);
315+
this.fsPathToEnv.set(normalizedPath, checkedEnv);
313316
} else {
314-
this.fsPathToEnv.delete(p.uri.fsPath);
317+
this.fsPathToEnv.delete(normalizedPath);
315318
}
316319
});
317320

@@ -405,7 +408,7 @@ export class CondaEnvManager implements EnvironmentManager, Disposable {
405408
});
406409

407410
// Try to find workspace environments
408-
const paths = this.api.getPythonProjects().map((p) => p.uri.fsPath);
411+
const paths = this.api.getPythonProjects().map((p) => normalizePath(p.uri.fsPath));
409412
for (const p of paths) {
410413
const env = await getCondaForWorkspace(p);
411414

@@ -436,7 +439,7 @@ export class CondaEnvManager implements EnvironmentManager, Disposable {
436439
// is a subfolder of one of the environments
437440
const found = pathSorted.find((e) => {
438441
const t = this.api.getPythonProject(e.environmentPath)?.uri.fsPath;
439-
return t && path.normalize(t) === p;
442+
return t && normalizePath(t) === p;
440443
});
441444
if (found) {
442445
this.fsPathToEnv.set(p, found);
@@ -448,15 +451,15 @@ export class CondaEnvManager implements EnvironmentManager, Disposable {
448451

449452
private fromEnvMap(uri: Uri): PythonEnvironment | undefined {
450453
// Find environment directly using the URI mapping
451-
const env = this.fsPathToEnv.get(uri.fsPath);
454+
const env = this.fsPathToEnv.get(normalizePath(uri.fsPath));
452455
if (env) {
453456
return env;
454457
}
455458

456459
// Find environment using the Python project for the Uri
457460
const project = this.api.getPythonProject(uri);
458461
if (project) {
459-
return this.fsPathToEnv.get(project.uri.fsPath);
462+
return this.fsPathToEnv.get(normalizePath(project.uri.fsPath));
460463
}
461464

462465
return undefined;
@@ -470,10 +473,14 @@ export class CondaEnvManager implements EnvironmentManager, Disposable {
470473
}
471474

472475
private findEnvironmentByPath(fsPath: string): PythonEnvironment | undefined {
473-
const normalized = path.normalize(fsPath);
476+
const normalized = normalizePath(fsPath);
474477
return this.collection.find((e) => {
475-
const n = path.normalize(e.environmentPath.fsPath);
476-
return n === normalized || path.dirname(n) === normalized || path.dirname(path.dirname(n)) === normalized;
478+
const n = normalizePath(e.environmentPath.fsPath);
479+
return (
480+
n === normalized ||
481+
normalizePath(path.dirname(e.environmentPath.fsPath)) === normalized ||
482+
normalizePath(path.dirname(path.dirname(e.environmentPath.fsPath))) === normalized
483+
);
477484
});
478485
}
479486

src/managers/pipenv/pipenvManager.ts

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
} from '../../api';
1717
import { PipenvStrings } from '../../common/localize';
1818
import { createDeferred, Deferred } from '../../common/utils/deferred';
19+
import { normalizePath } from '../../common/utils/pathUtils';
1920
import { withProgress } from '../../common/window.apis';
2021
import { NativePythonFinder } from '../common/nativePythonFinder';
2122
import {
@@ -101,7 +102,7 @@ export class PipenvManager implements EnvironmentManager {
101102
if (envPath) {
102103
const env = this.findEnvironmentByPath(envPath);
103104
if (env) {
104-
this.fsPathToEnv.set(project.uri.fsPath, env);
105+
this.fsPathToEnv.set(normalizePath(project.uri.fsPath), env);
105106
}
106107
}
107108
}
@@ -114,8 +115,11 @@ export class PipenvManager implements EnvironmentManager {
114115
}
115116

116117
private findEnvironmentByPath(fsPath: string): PythonEnvironment | undefined {
118+
const normalized = normalizePath(fsPath);
117119
return this.collection.find(
118-
(env) => env.environmentPath.fsPath === fsPath || env.execInfo?.run.executable === fsPath,
120+
(env) =>
121+
normalizePath(env.environmentPath.fsPath) === normalized ||
122+
(env.execInfo?.run.executable && normalizePath(env.execInfo.run.executable) === normalized),
119123
);
120124
}
121125

@@ -171,7 +175,7 @@ export class PipenvManager implements EnvironmentManager {
171175
if (scope instanceof Uri) {
172176
const project = this.api.getPythonProject(scope);
173177
if (project) {
174-
const env = this.fsPathToEnv.get(project.uri.fsPath);
178+
const env = this.fsPathToEnv.get(normalizePath(project.uri.fsPath));
175179
return env ? [env] : [];
176180
}
177181
}
@@ -199,11 +203,12 @@ export class PipenvManager implements EnvironmentManager {
199203
return;
200204
}
201205

202-
const before = this.fsPathToEnv.get(project.uri.fsPath);
206+
const normalizedPath = normalizePath(project.uri.fsPath);
207+
const before = this.fsPathToEnv.get(normalizedPath);
203208
if (environment) {
204-
this.fsPathToEnv.set(project.uri.fsPath, environment);
209+
this.fsPathToEnv.set(normalizedPath, environment);
205210
} else {
206-
this.fsPathToEnv.delete(project.uri.fsPath);
211+
this.fsPathToEnv.delete(normalizedPath);
207212
}
208213

209214
await setPipenvForWorkspace(project.uri.fsPath, environment?.environmentPath.fsPath);
@@ -226,11 +231,12 @@ export class PipenvManager implements EnvironmentManager {
226231

227232
const before: Map<string, PythonEnvironment | undefined> = new Map();
228233
projects.forEach((p) => {
229-
before.set(p.uri.fsPath, this.fsPathToEnv.get(p.uri.fsPath));
234+
const normalizedPath = normalizePath(p.uri.fsPath);
235+
before.set(p.uri.fsPath, this.fsPathToEnv.get(normalizedPath));
230236
if (environment) {
231-
this.fsPathToEnv.set(p.uri.fsPath, environment);
237+
this.fsPathToEnv.set(normalizedPath, environment);
232238
} else {
233-
this.fsPathToEnv.delete(p.uri.fsPath);
239+
this.fsPathToEnv.delete(normalizedPath);
234240
}
235241
});
236242

@@ -258,7 +264,7 @@ export class PipenvManager implements EnvironmentManager {
258264
if (scope instanceof Uri) {
259265
const project = this.api.getPythonProject(scope);
260266
if (project) {
261-
return this.fsPathToEnv.get(project.uri.fsPath);
267+
return this.fsPathToEnv.get(normalizePath(project.uri.fsPath));
262268
}
263269
}
264270

0 commit comments

Comments
 (0)