Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 26 additions & 17 deletions src/managers/builtin/sysPythonManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
} from '../../api';
import { SysManagerStrings } from '../../common/localize';
import { createDeferred, Deferred } from '../../common/utils/deferred';
import { normalizePath } from '../../common/utils/pathUtils';
import { NativePythonFinder } from '../common/nativePythonFinder';
import { getLatest } from '../common/utils';
import {
Expand Down Expand Up @@ -134,7 +135,7 @@ export class SysPythonManager implements EnvironmentManager {
}

if (scope instanceof Uri) {
const env = this.fsPathToEnv.get(scope.fsPath);
const env = this.fsPathToEnv.get(normalizePath(scope.fsPath));
if (env) {
return [env];
}
Expand Down Expand Up @@ -171,10 +172,11 @@ export class SysPythonManager implements EnvironmentManager {
return;
}

const normalizedPwPath = normalizePath(pw.uri.fsPath);
if (environment) {
this.fsPathToEnv.set(pw.uri.fsPath, environment);
this.fsPathToEnv.set(normalizedPwPath, environment);
} else {
this.fsPathToEnv.delete(pw.uri.fsPath);
this.fsPathToEnv.delete(normalizedPwPath);
}
await setSystemEnvForWorkspace(pw.uri.fsPath, environment?.environmentPath.fsPath);
}
Expand All @@ -191,11 +193,12 @@ export class SysPythonManager implements EnvironmentManager {

const before: Map<string, PythonEnvironment | undefined> = new Map();
projects.forEach((p) => {
before.set(p.uri.fsPath, this.fsPathToEnv.get(p.uri.fsPath));
const normalizedPath = normalizePath(p.uri.fsPath);
before.set(p.uri.fsPath, this.fsPathToEnv.get(normalizedPath));
if (environment) {
this.fsPathToEnv.set(p.uri.fsPath, environment);
this.fsPathToEnv.set(normalizedPath, environment);
} else {
this.fsPathToEnv.delete(p.uri.fsPath);
this.fsPathToEnv.delete(normalizedPath);
}
});

Expand Down Expand Up @@ -282,24 +285,28 @@ export class SysPythonManager implements EnvironmentManager {
}

private findEnvironmentByPath(fsPath: string): PythonEnvironment | undefined {
const normalized = path.normalize(fsPath); // /opt/homebrew/bin/python3.12
const normalized = normalizePath(fsPath);
return this.collection.find((e) => {
const n = path.normalize(e.environmentPath.fsPath);
return n === normalized || path.dirname(n) === normalized || path.dirname(path.dirname(n)) === normalized;
const n = normalizePath(e.environmentPath.fsPath);
return (
n === normalized ||
normalizePath(path.dirname(e.environmentPath.fsPath)) === normalized ||
normalizePath(path.dirname(path.dirname(e.environmentPath.fsPath))) === normalized
);
});
}

private fromEnvMap(uri: Uri): PythonEnvironment | undefined {
// Find environment directly using the URI mapping
const env = this.fsPathToEnv.get(uri.fsPath);
const env = this.fsPathToEnv.get(normalizePath(uri.fsPath));
if (env) {
return env;
}

// Find environment using the Python project for the Uri
const project = this.api.getPythonProject(uri);
if (project) {
return this.fsPathToEnv.get(project.uri.fsPath);
return this.fsPathToEnv.get(normalizePath(project.uri.fsPath));
}

return this.globalEnv;
Expand Down Expand Up @@ -332,24 +339,26 @@ export class SysPythonManager implements EnvironmentManager {
}

// Try to find workspace environments
const paths = this.api.getPythonProjects().map((p) => p.uri.fsPath);
const projects = this.api.getPythonProjects();

// Iterate over each path
for (const p of paths) {
const env = await getSystemEnvForWorkspace(p);
// Iterate over each project
for (const project of projects) {
const originalPath = project.uri.fsPath;
const normalizedPath = normalizePath(originalPath);
const env = await getSystemEnvForWorkspace(originalPath);

if (env) {
const found = this.findEnvironmentByPath(env);

if (found) {
this.fsPathToEnv.set(p, found);
this.fsPathToEnv.set(normalizedPath, found);
} else {
// If not found, resolve the path.
const resolved = await resolveSystemPythonEnvironmentPath(env, this.nativeFinder, this.api, this);

if (resolved) {
// If resolved add it to the collection.
this.fsPathToEnv.set(p, resolved);
this.fsPathToEnv.set(normalizedPath, resolved);
this.collection.push(resolved);
} else {
this.log.error(`Failed to resolve python environment: ${env}`);
Expand Down
47 changes: 25 additions & 22 deletions src/managers/builtin/venvManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -291,15 +291,15 @@ export class VenvManager implements EnvironmentManager {
}

private updateCollection(environment: PythonEnvironment): void {
this.collection = this.collection.filter(
(e) => e.environmentPath.fsPath !== environment.environmentPath.fsPath,
);
const envPath = normalizePath(environment.environmentPath.fsPath);
this.collection = this.collection.filter((e) => normalizePath(e.environmentPath.fsPath) !== envPath);
}

private updateFsPathToEnv(environment: PythonEnvironment): Uri[] {
const envPath = normalizePath(environment.environmentPath.fsPath);
const changed: Uri[] = [];
this.fsPathToEnv.forEach((env, uri) => {
if (env.environmentPath.fsPath === environment.environmentPath.fsPath) {
if (normalizePath(env.environmentPath.fsPath) === envPath) {
this.fsPathToEnv.delete(uri);
changed.push(Uri.file(uri));
}
Expand Down Expand Up @@ -361,7 +361,7 @@ export class VenvManager implements EnvironmentManager {
return [];
}

const env = this.fsPathToEnv.get(scope.fsPath);
const env = this.fsPathToEnv.get(normalizePath(scope.fsPath));
return env ? [env] : [];
}

Expand All @@ -378,7 +378,7 @@ export class VenvManager implements EnvironmentManager {
return this.globalEnv;
}

let env = this.fsPathToEnv.get(project.uri.fsPath);
let env = this.fsPathToEnv.get(normalizePath(project.uri.fsPath));
if (!env) {
env = this.findEnvironmentByPath(project.uri.fsPath);
}
Expand Down Expand Up @@ -414,11 +414,12 @@ export class VenvManager implements EnvironmentManager {
}
}

const before = this.fsPathToEnv.get(pw.uri.fsPath);
const normalizedPwPath = normalizePath(pw.uri.fsPath);
const before = this.fsPathToEnv.get(normalizedPwPath);
if (environment) {
this.fsPathToEnv.set(pw.uri.fsPath, environment);
this.fsPathToEnv.set(normalizedPwPath, environment);
} else {
this.fsPathToEnv.delete(pw.uri.fsPath);
this.fsPathToEnv.delete(normalizedPwPath);
}
await setVenvForWorkspace(pw.uri.fsPath, environment?.environmentPath.fsPath);

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

const before: Map<string, PythonEnvironment | undefined> = new Map();
projects.forEach((p) => {
before.set(p.uri.fsPath, this.fsPathToEnv.get(p.uri.fsPath));
const normalizedPath = normalizePath(p.uri.fsPath);
before.set(p.uri.fsPath, this.fsPathToEnv.get(normalizedPath));
if (environment) {
this.fsPathToEnv.set(p.uri.fsPath, environment);
this.fsPathToEnv.set(normalizedPath, environment);
} else {
this.fsPathToEnv.delete(p.uri.fsPath);
this.fsPathToEnv.delete(normalizedPath);
}
});

Expand Down Expand Up @@ -572,16 +574,17 @@ export class VenvManager implements EnvironmentManager {
this.fsPathToEnv.clear();

const sorted = sortEnvironments(this.collection);
const projectPaths = this.api.getPythonProjects().map((p) => normalizePath(p.uri.fsPath));
const projects = this.api.getPythonProjects();
const events: (() => void)[] = [];
// Iterates through all workspace projects
for (const p of projectPaths) {
const env = await getVenvForWorkspace(p);
for (const project of projects) {
const originalPath = project.uri.fsPath;
const normalizedPath = normalizePath(originalPath);
const env = await getVenvForWorkspace(originalPath);
if (env) {
// from env path find PythonEnvironment object in the collection.
let foundEnv = this.findEnvironmentByPath(env, sorted) ?? this.findEnvironmentByPath(env, globals);
const previousEnv = this.fsPathToEnv.get(p);
const pw = this.api.getPythonProject(Uri.file(p));
const previousEnv = this.fsPathToEnv.get(normalizedPath);
if (!foundEnv) {
// attempt to resolve
const resolved = await resolveVenvPythonEnvironmentPath(
Expand All @@ -601,20 +604,20 @@ export class VenvManager implements EnvironmentManager {
}
}
// Given found env, add it to the map and fire the event if needed.
this.fsPathToEnv.set(p, foundEnv);
if (pw && previousEnv?.envId.id !== foundEnv.envId.id) {
this.fsPathToEnv.set(normalizedPath, foundEnv);
if (previousEnv?.envId.id !== foundEnv.envId.id) {
events.push(() =>
this._onDidChangeEnvironment.fire({ uri: pw.uri, old: undefined, new: foundEnv }),
this._onDidChangeEnvironment.fire({ uri: project.uri, old: undefined, new: foundEnv }),
);
}
} else {
// Search through all known environments (e) and check if any are associated with the current project path. If so, add that environment and path in the map.
const found = sorted.find((e) => {
const t = this.api.getPythonProject(e.environmentPath)?.uri.fsPath;
return t && normalizePath(t) === p;
return t && normalizePath(t) === normalizedPath;
});
if (found) {
this.fsPathToEnv.set(p, found);
this.fsPathToEnv.set(normalizedPath, found);
}
}
}
Expand Down
15 changes: 13 additions & 2 deletions src/managers/common/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,13 @@ export function isGreater(a: string | undefined, b: string | undefined): boolean

export function sortEnvironments(collection: PythonEnvironment[]): PythonEnvironment[] {
return collection.sort((a, b) => {
// Environments with errors should be sorted to the end
if (a.error && !b.error) {
return 1;
}
if (!a.error && b.error) {
return -1;
}
if (a.version !== b.version) {
return isGreater(a.version, b.version) ? -1 : 1;
}
Expand All @@ -83,8 +90,12 @@ export function getLatest(collection: PythonEnvironment[]): PythonEnvironment |
if (collection.length === 0) {
return undefined;
}
let latest = collection[0];
for (const env of collection) {
// Filter out environments with errors first, then find latest
const nonErroredEnvs = collection.filter((e) => !e.error);
const candidates = nonErroredEnvs.length > 0 ? nonErroredEnvs : collection;

let latest = candidates[0];
for (const env of candidates) {
if (isGreater(env.version, latest.version)) {
latest = env;
}
Expand Down
Loading
Loading