Skip to content

Commit 444bc12

Browse files
committed
fix: improve no-python conda handling
1 parent 16caca3 commit 444bc12

4 files changed

Lines changed: 144 additions & 63 deletions

File tree

src/common/localize.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export namespace Common {
1313
export const yes = l10n.t('Yes');
1414
export const no = l10n.t('No');
1515
export const quickCreate = l10n.t('Quick Create');
16+
export const installPython = l10n.t('Install Python');
1617
}
1718

1819
export namespace Interpreter {
@@ -139,6 +140,11 @@ export namespace CondaStrings {
139140

140141
export const quickCreateCondaNoEnvRoot = l10n.t('No conda environment root found');
141142
export const quickCreateCondaNoName = l10n.t('Could not generate a name for env');
143+
144+
export const condaMissingPython = l10n.t('No Python found in the selected conda environment');
145+
export const condaMissingPythonNoFix = l10n.t(
146+
'No Python found in the selected conda environment. Please select another environment or install Python manually.',
147+
);
142148
}
143149

144150
export namespace ProjectCreatorString {

src/managers/conda/condaEnvManager.ts

Lines changed: 52 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,12 @@ import {
1818
ResolveEnvironmentContext,
1919
SetEnvironmentScope,
2020
} from '../../api';
21+
import { CondaStrings } from '../../common/localize';
22+
import { createDeferred, Deferred } from '../../common/utils/deferred';
23+
import { showErrorMessage, withProgress } from '../../common/window.apis';
24+
import { NativePythonFinder } from '../common/nativePythonFinder';
2125
import {
26+
checkForNoPythonCondaEnvironment,
2227
clearCondaCache,
2328
createCondaEnvironment,
2429
deleteCondaEnvironment,
@@ -33,15 +38,10 @@ import {
3338
setCondaForWorkspace,
3439
setCondaForWorkspaces,
3540
} from './condaUtils';
36-
import { NativePythonFinder } from '../common/nativePythonFinder';
37-
import { createDeferred, Deferred } from '../../common/utils/deferred';
38-
import { showErrorMessage, withProgress } from '../../common/window.apis';
39-
import { CondaStrings } from '../../common/localize';
4041

4142
export class CondaEnvManager implements EnvironmentManager, Disposable {
4243
private collection: PythonEnvironment[] = [];
4344
private fsPathToEnv: Map<string, PythonEnvironment> = new Map();
44-
private disposablesMap: Map<string, Disposable> = new Map();
4545
private globalEnv: PythonEnvironment | undefined;
4646

4747
private readonly _onDidChangeEnvironment = new EventEmitter<DidChangeEnvironmentEventArgs>();
@@ -70,7 +70,8 @@ export class CondaEnvManager implements EnvironmentManager, Disposable {
7070
iconPath?: IconPath;
7171

7272
public dispose() {
73-
this.disposablesMap.forEach((d) => d.dispose());
73+
this.collection = [];
74+
this.fsPathToEnv.clear();
7475
}
7576

7677
private _initialized: Deferred<void> | undefined;
@@ -166,20 +167,7 @@ export class CondaEnvManager implements EnvironmentManager, Disposable {
166167
);
167168
}
168169
if (result) {
169-
this.disposablesMap.set(
170-
result.envId.id,
171-
new Disposable(() => {
172-
if (result) {
173-
this.collection = this.collection.filter((env) => env.envId.id !== result?.envId.id);
174-
Array.from(this.fsPathToEnv.entries())
175-
.filter(([, env]) => env.envId.id === result?.envId.id)
176-
.forEach(([uri]) => this.fsPathToEnv.delete(uri));
177-
this.disposablesMap.delete(result.envId.id);
178-
}
179-
}),
180-
);
181-
this.collection.push(result);
182-
this._onDidChangeEnvironments.fire([{ kind: EnvironmentChangeKind.add, environment: result }]);
170+
this.addEnvironment(result);
183171
}
184172

185173
return result;
@@ -189,12 +177,28 @@ export class CondaEnvManager implements EnvironmentManager, Disposable {
189177
}
190178
}
191179

180+
private addEnvironment(environment: PythonEnvironment, raiseEvent: boolean = true): void {
181+
this.collection.push(environment);
182+
if (raiseEvent) {
183+
this._onDidChangeEnvironments.fire([{ kind: EnvironmentChangeKind.add, environment: environment }]);
184+
}
185+
}
186+
187+
private removeEnvironment(environment: PythonEnvironment, raiseEvent: boolean = true): void {
188+
this.collection = this.collection.filter((env) => env.envId.id !== environment.envId.id);
189+
Array.from(this.fsPathToEnv.entries())
190+
.filter(([, env]) => env.envId.id === environment.envId.id)
191+
.forEach(([uri]) => this.fsPathToEnv.delete(uri));
192+
if (raiseEvent) {
193+
this._onDidChangeEnvironments.fire([{ kind: EnvironmentChangeKind.remove, environment }]);
194+
}
195+
}
196+
192197
async remove(context: PythonEnvironment): Promise<void> {
193198
try {
194199
const projects = this.getProjectsForEnvironment(context);
200+
this.removeEnvironment(context, false);
195201
await deleteCondaEnvironment(context, this.log);
196-
this.disposablesMap.get(context.envId.id)?.dispose();
197-
198202
setImmediate(() => {
199203
this._onDidChangeEnvironments.fire([{ kind: EnvironmentChangeKind.remove, environment: context }]);
200204
projects.forEach((project) =>
@@ -207,9 +211,6 @@ export class CondaEnvManager implements EnvironmentManager, Disposable {
207211
}
208212
async refresh(context: RefreshEnvironmentsScope): Promise<void> {
209213
if (context === undefined) {
210-
this.disposablesMap.forEach((d) => d.dispose());
211-
this.disposablesMap.clear();
212-
213214
await withProgress(
214215
{
215216
location: ProgressLocation.Window,
@@ -252,18 +253,22 @@ export class CondaEnvManager implements EnvironmentManager, Disposable {
252253
}
253254

254255
async set(scope: SetEnvironmentScope, environment?: PythonEnvironment | undefined): Promise<void> {
256+
const checkedEnv = environment
257+
? await checkForNoPythonCondaEnvironment(this.nativeFinder, this, environment, this.api, this.log)
258+
: undefined;
259+
255260
if (scope === undefined) {
256-
await setCondaForGlobal(environment?.environmentPath?.fsPath);
261+
await setCondaForGlobal(checkedEnv?.environmentPath?.fsPath);
257262
} else if (scope instanceof Uri) {
258263
const folder = this.api.getPythonProject(scope);
259264
const fsPath = folder?.uri?.fsPath ?? scope.fsPath;
260265
if (fsPath) {
261-
if (environment) {
262-
this.fsPathToEnv.set(fsPath, environment);
266+
if (checkedEnv) {
267+
this.fsPathToEnv.set(fsPath, checkedEnv);
263268
} else {
264269
this.fsPathToEnv.delete(fsPath);
265270
}
266-
await setCondaForWorkspace(fsPath, environment?.environmentPath.fsPath);
271+
await setCondaForWorkspace(fsPath, checkedEnv?.environmentPath.fsPath);
267272
}
268273
} else if (Array.isArray(scope) && scope.every((u) => u instanceof Uri)) {
269274
const projects: PythonProject[] = [];
@@ -278,25 +283,38 @@ export class CondaEnvManager implements EnvironmentManager, Disposable {
278283
const before: Map<string, PythonEnvironment | undefined> = new Map();
279284
projects.forEach((p) => {
280285
before.set(p.uri.fsPath, this.fsPathToEnv.get(p.uri.fsPath));
281-
if (environment) {
282-
this.fsPathToEnv.set(p.uri.fsPath, environment);
286+
if (checkedEnv) {
287+
this.fsPathToEnv.set(p.uri.fsPath, checkedEnv);
283288
} else {
284289
this.fsPathToEnv.delete(p.uri.fsPath);
285290
}
286291
});
287292

288293
await setCondaForWorkspaces(
289294
projects.map((p) => p.uri.fsPath),
290-
environment?.environmentPath.fsPath,
295+
checkedEnv?.environmentPath.fsPath,
291296
);
292297

293298
projects.forEach((p) => {
294299
const b = before.get(p.uri.fsPath);
295-
if (b?.envId.id !== environment?.envId.id) {
296-
this._onDidChangeEnvironment.fire({ uri: p.uri, old: b, new: environment });
300+
if (b?.envId.id !== checkedEnv?.envId.id) {
301+
this._onDidChangeEnvironment.fire({ uri: p.uri, old: b, new: checkedEnv });
297302
}
298303
});
299304
}
305+
306+
if (environment && checkedEnv && checkedEnv.envId.id !== environment.envId.id) {
307+
this.removeEnvironment(environment, false);
308+
this.addEnvironment(checkedEnv, false);
309+
setImmediate(() => {
310+
this._onDidChangeEnvironments.fire([
311+
{ kind: EnvironmentChangeKind.remove, environment },
312+
{ kind: EnvironmentChangeKind.add, environment: checkedEnv },
313+
]);
314+
const uri = scope ? (scope instanceof Uri ? scope : scope[0]) : undefined;
315+
this._onDidChangeEnvironment.fire({ uri, old: environment, new: checkedEnv });
316+
});
317+
}
300318
}
301319

302320
async resolve(context: ResolveEnvironmentContext): Promise<PythonEnvironment | undefined> {

src/managers/conda/condaPackageManager.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ import {
1717
PythonEnvironment,
1818
PythonEnvironmentApi,
1919
} from '../../api';
20-
import { getCommonCondaPackagesToInstall, managePackages, refreshPackages } from './condaUtils';
21-
import { withProgress } from '../../common/window.apis';
2220
import { showErrorMessageWithLogs } from '../../common/errors/utils';
2321
import { CondaStrings } from '../../common/localize';
22+
import { withProgress } from '../../common/window.apis';
23+
import { getCommonCondaPackagesToInstall, managePackages, refreshPackages } from './condaUtils';
2424

2525
function getChanges(before: Package[], after: Package[]): { kind: PackageChangeKind; pkg: Package }[] {
2626
const changes: { kind: PackageChangeKind; pkg: Package }[] = [];
@@ -79,7 +79,7 @@ export class CondaPackageManager implements PackageManager, Disposable {
7979
async (_progress, token) => {
8080
try {
8181
const before = this.packages.get(environment.envId.id) ?? [];
82-
const after = await managePackages(environment, manageOptions, this.api, this, token);
82+
const after = await managePackages(environment, manageOptions, this.api, this, token, this.log);
8383
const changes = getChanges(before, after);
8484
this.packages.set(environment.envId.id, after);
8585
this._onDidChangePackages.fire({ environment: environment, manager: this, changes });

0 commit comments

Comments
 (0)