Skip to content

Commit 2677f00

Browse files
committed
pr feedback
1 parent 9b00473 commit 2677f00

File tree

4 files changed

+46
-34
lines changed

4 files changed

+46
-34
lines changed

src/kernels/deepnote/deepnoteServerStarter.node.ts

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -117,12 +117,9 @@ export class DeepnoteServerStarter implements IDeepnoteServerStarter, IExtension
117117

118118
Cancellation.throwIfCanceled(token);
119119

120-
// Ensure toolkit is installed
120+
// Ensure toolkit is installed (will throw typed errors on failure)
121121
logger.info(`Ensuring deepnote-toolkit is installed for ${fileKey}...`);
122-
const installed = await this.toolkitInstaller.ensureInstalled(interpreter, deepnoteFileUri, token);
123-
if (!installed) {
124-
throw new Error('Failed to install deepnote-toolkit. Please check the output for details.');
125-
}
122+
await this.toolkitInstaller.ensureInstalled(interpreter, deepnoteFileUri, token);
126123

127124
Cancellation.throwIfCanceled(token);
128125

@@ -227,22 +224,27 @@ export class DeepnoteServerStarter implements IDeepnoteServerStarter, IExtension
227224
throw new DeepnoteServerTimeoutError(serverInfo.url, 120000, output?.stderr || undefined);
228225
}
229226
} catch (error) {
230-
// Clean up leaked server before rethrowing
231-
await this.stopServerImpl(deepnoteFileUri);
232-
233-
// If this is already a DeepnoteKernelError, rethrow it
227+
// If this is already a DeepnoteKernelError, clean up and rethrow it
234228
if (error instanceof DeepnoteServerTimeoutError || error instanceof DeepnoteServerStartupError) {
229+
await this.stopServerImpl(deepnoteFileUri);
235230
throw error;
236231
}
237232

238-
// Otherwise wrap in a generic server startup error
233+
// Capture output BEFORE cleaning up (stopServerImpl deletes it)
239234
const output = this.serverOutputByFile.get(fileKey);
235+
const capturedStdout = output?.stdout || '';
236+
const capturedStderr = output?.stderr || '';
237+
238+
// Clean up leaked server after capturing output
239+
await this.stopServerImpl(deepnoteFileUri);
240+
241+
// Wrap in a generic server startup error with captured output
240242
throw new DeepnoteServerStartupError(
241243
interpreter.uri.fsPath,
242244
port,
243245
'unknown',
244-
output?.stdout || '',
245-
output?.stderr || '',
246+
capturedStdout,
247+
capturedStderr,
246248
error instanceof Error ? error : undefined
247249
);
248250
}

src/kernels/deepnote/deepnoteToolkitInstaller.node.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { DeepnoteVenvCreationError, DeepnoteToolkitInstallError } from '../../pl
2020
export class DeepnoteToolkitInstaller implements IDeepnoteToolkitInstaller {
2121
private readonly venvPythonPaths: Map<string, Uri> = new Map();
2222
// Track in-flight installations per venv path to prevent concurrent installs
23-
private readonly pendingInstallations: Map<string, Promise<PythonEnvironment | undefined>> = new Map();
23+
private readonly pendingInstallations: Map<string, Promise<PythonEnvironment>> = new Map();
2424

2525
constructor(
2626
@inject(IProcessServiceFactory) private readonly processServiceFactory: IProcessServiceFactory,
@@ -63,7 +63,7 @@ export class DeepnoteToolkitInstaller implements IDeepnoteToolkitInstaller {
6363
baseInterpreter: PythonEnvironment,
6464
deepnoteFileUri: Uri,
6565
token?: CancellationToken
66-
): Promise<PythonEnvironment | undefined> {
66+
): Promise<PythonEnvironment> {
6767
const venvPath = this.getVenvPath(deepnoteFileUri);
6868
const venvKey = venvPath.fsPath;
6969

@@ -120,7 +120,7 @@ export class DeepnoteToolkitInstaller implements IDeepnoteToolkitInstaller {
120120
deepnoteFileUri: Uri,
121121
venvPath: Uri,
122122
token?: CancellationToken
123-
): Promise<PythonEnvironment | undefined> {
123+
): Promise<PythonEnvironment> {
124124
try {
125125
Cancellation.throwIfCanceled(token);
126126

@@ -271,9 +271,9 @@ export class DeepnoteToolkitInstaller implements IDeepnoteToolkitInstaller {
271271
throw ex;
272272
}
273273

274-
// Otherwise, log and wrap in a generic toolkit install error
274+
// Otherwise, log full details and wrap in a generic toolkit install error
275275
logger.error(`Failed to set up deepnote-toolkit: ${ex}`);
276-
this.outputChannel.appendLine(`Error setting up deepnote-toolkit: ${ex}`);
276+
this.outputChannel.appendLine('Failed to set up deepnote-toolkit; see logs for details');
277277

278278
throw new DeepnoteToolkitInstallError(
279279
baseInterpreter.uri.fsPath,

src/kernels/deepnote/types.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,15 @@ export interface IDeepnoteToolkitInstaller {
7272
* @param baseInterpreter The base Python interpreter to use for creating the venv
7373
* @param deepnoteFileUri The URI of the .deepnote file (used to create a unique venv per file)
7474
* @param token Cancellation token to cancel the operation
75-
* @returns The Python interpreter from the venv if installed successfully, undefined otherwise
75+
* @returns The Python interpreter from the venv
76+
* @throws {DeepnoteVenvCreationError} If venv creation fails
77+
* @throws {DeepnoteToolkitInstallError} If toolkit installation fails
7678
*/
7779
ensureInstalled(
7880
baseInterpreter: PythonEnvironment,
7981
deepnoteFileUri: vscode.Uri,
8082
token?: vscode.CancellationToken
81-
): Promise<PythonEnvironment | undefined>;
83+
): Promise<PythonEnvironment>;
8284

8385
/**
8486
* Gets the venv Python interpreter if toolkit is installed, undefined otherwise.

src/notebooks/deepnote/deepnoteKernelAutoSelector.node.ts

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -345,16 +345,13 @@ export class DeepnoteKernelAutoSelector implements IDeepnoteKernelAutoSelector,
345345
logger.info(`Using base interpreter: ${getDisplayPath(interpreter.uri)}`);
346346

347347
// Ensure deepnote-toolkit is installed in a venv and get the venv interpreter
348+
// Will throw typed errors on failure (DeepnoteVenvCreationError or DeepnoteToolkitInstallError)
348349
progress.report({ message: l10n.t('Installing Deepnote toolkit...') });
349350
const venvInterpreter = await this.toolkitInstaller.ensureInstalled(
350351
interpreter,
351352
baseFileUri,
352353
progressToken
353354
);
354-
if (!venvInterpreter) {
355-
logger.error('Failed to set up Deepnote toolkit environment');
356-
return; // Exit gracefully
357-
}
358355

359356
logger.info(`Deepnote toolkit venv ready at: ${getDisplayPath(venvInterpreter.uri)}`);
360357

@@ -567,22 +564,32 @@ export class DeepnoteKernelAutoSelector implements IDeepnoteKernelAutoSelector,
567564
logger.error(error.getErrorReport());
568565

569566
// Show user-friendly error with actions
570-
const actions: string[] = ['Show Output', 'Copy Error Details'];
567+
const showOutputAction = l10n.t('Show Output');
568+
const copyErrorAction = l10n.t('Copy Error Details');
569+
const actions: string[] = [showOutputAction, copyErrorAction];
570+
571+
const troubleshootingHeader = l10n.t('Troubleshooting:');
572+
const troubleshootingSteps = error.troubleshootingSteps
573+
.slice(0, 3)
574+
.map((step, i) => `${i + 1}. ${step}`)
575+
.join('\n');
571576

572577
const selectedAction = await window.showErrorMessage(
573-
`${error.userMessage}\n\nTroubleshooting:\n${error.troubleshootingSteps
574-
.slice(0, 3)
575-
.map((step, i) => `${i + 1}. ${step}`)
576-
.join('\n')}`,
578+
`${error.userMessage}\n\n${troubleshootingHeader}\n${troubleshootingSteps}`,
577579
{ modal: false },
578580
...actions
579581
);
580582

581-
if (selectedAction === 'Show Output') {
583+
if (selectedAction === showOutputAction) {
582584
this.outputChannel.show();
583-
} else if (selectedAction === 'Copy Error Details') {
584-
await env.clipboard.writeText(error.getErrorReport());
585-
void window.showInformationMessage('Error details copied to clipboard');
585+
} else if (selectedAction === copyErrorAction) {
586+
try {
587+
await env.clipboard.writeText(error.getErrorReport());
588+
void window.showInformationMessage(l10n.t('Error details copied to clipboard'));
589+
} catch (clipboardError) {
590+
logger.error('Failed to copy error details to clipboard', clipboardError);
591+
void window.showErrorMessage(l10n.t('Failed to copy error details to clipboard'));
592+
}
586593
}
587594

588595
return;
@@ -592,13 +599,14 @@ export class DeepnoteKernelAutoSelector implements IDeepnoteKernelAutoSelector,
592599
const errorMessage = error instanceof Error ? error.message : String(error);
593600
logger.error(`Deepnote kernel error: ${errorMessage}`);
594601

602+
const showOutputAction = l10n.t('Show Output');
595603
const selectedAction = await window.showErrorMessage(
596604
l10n.t('Failed to load Deepnote kernel: {0}', errorMessage),
597605
{ modal: false },
598-
'Show Output'
606+
showOutputAction
599607
);
600608

601-
if (selectedAction === 'Show Output') {
609+
if (selectedAction === showOutputAction) {
602610
this.outputChannel.show();
603611
}
604612
}

0 commit comments

Comments
 (0)