Skip to content

Commit a51a150

Browse files
committed
pr feedback.
1 parent 1ba9ab4 commit a51a150

File tree

8 files changed

+171
-124
lines changed

8 files changed

+171
-124
lines changed

build/esbuild/build.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ async function buildAll() {
320320
build(
321321
path.join(extensionFolder, 'src', 'webviews', 'webview-side', 'dataframe-renderer', 'index.ts'),
322322
path.join(extensionFolder, 'dist', 'webviews', 'webview-side', 'dataframeRenderer', 'dataframeRenderer.js'),
323-
{ target: 'web', watch: isWatchMode }
323+
{ target: 'web', watch: watchAll }
324324
),
325325
build(
326326
path.join(extensionFolder, 'src', 'webviews', 'webview-side', 'variable-view', 'index.tsx'),

src/kernels/execution/cellExecutionMessageHandler.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,14 @@ export function getParentHeaderMsgId(msg: KernelMessage.IMessage): string | unde
7979
return undefined;
8080
}
8181

82+
/**
83+
* Gets the cell ID, preferring the metadata id from Deepnote blocks,
84+
* otherwise falling back to the cell's document URI.
85+
*/
86+
function getCellId(cell: NotebookCell): string {
87+
return (cell.metadata?.id as string | undefined) || cell.document.uri.toString();
88+
}
89+
8290
/**
8391
* Responsible for handling of jupyter messages as a result of execution of individual cells.
8492
*/
@@ -635,7 +643,7 @@ export class CellExecutionMessageHandler implements IDisposable {
635643
}
636644
}
637645
// Use cell metadata id if available (from Deepnote blocks), otherwise fall back to cell's internal id
638-
const cellId = (this.cell.metadata?.id as string | undefined) || this.cell.document.uri.toString();
646+
const cellId = getCellId(this.cell);
639647
const cellOutput = cellOutputToVSCCellOutput(output, this.cell.index, cellId);
640648
const displayId =
641649
'transient' in output &&
@@ -1006,7 +1014,7 @@ export class CellExecutionMessageHandler implements IDisposable {
10061014
// If the last output is the desired stream type.
10071015
if (this.lastUsedStreamOutput?.stream === msg.content.name) {
10081016
// Use cell metadata id if available (from Deepnote blocks), otherwise fall back to cell's internal id
1009-
const cellId = (this.cell.metadata?.id as string | undefined) || this.cell.document.uri.toString();
1017+
const cellId = getCellId(this.cell);
10101018
const output = cellOutputToVSCCellOutput(
10111019
{
10121020
output_type: 'stream',
@@ -1022,7 +1030,7 @@ export class CellExecutionMessageHandler implements IDisposable {
10221030
// Replace the current outputs with a single new output.
10231031
const text = concatMultilineString(msg.content.text);
10241032
// Use cell metadata id if available (from Deepnote blocks), otherwise fall back to cell's internal id
1025-
const cellId = (this.cell.metadata?.id as string | undefined) || this.cell.document.uri.toString();
1033+
const cellId = getCellId(this.cell);
10261034
const output = cellOutputToVSCCellOutput(
10271035
{
10281036
output_type: 'stream',
@@ -1039,7 +1047,7 @@ export class CellExecutionMessageHandler implements IDisposable {
10391047
// Create a new output
10401048
const text = formatStreamText(concatMultilineString(msg.content.text));
10411049
// Use cell metadata id if available (from Deepnote blocks), otherwise fall back to cell's internal id
1042-
const cellId = (this.cell.metadata?.id as string | undefined) || this.cell.document.uri.toString();
1050+
const cellId = getCellId(this.cell);
10431051
const output = cellOutputToVSCCellOutput(
10441052
{
10451053
output_type: 'stream',
@@ -1167,9 +1175,7 @@ export class CellExecutionMessageHandler implements IDisposable {
11671175
new NotebookCellOutput(outputToBeUpdated.outputItems, outputToBeUpdated.outputContainer.metadata)
11681176
);
11691177
// Use cell metadata id if available (from Deepnote blocks), otherwise fall back to cell's internal id
1170-
const cellId =
1171-
(outputToBeUpdated.cell.metadata?.id as string | undefined) ||
1172-
outputToBeUpdated.cell.document.uri.toString();
1178+
const cellId = getCellId(outputToBeUpdated.cell);
11731179
const newOutput = cellOutputToVSCCellOutput(
11741180
{
11751181
...output,

src/notebooks/deepnote/deepnoteInitNotebookRunner.node.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ export class DeepnoteInitNotebookRunner {
234234
}
235235

236236
const block = codeBlocks[i];
237-
const percentComplete = Math.floor((i / codeBlocks.length) * 100);
237+
const percentComplete = Math.min(100, Math.floor(((i + 1) / codeBlocks.length) * 100));
238238

239239
// Show more detailed progress with percentage
240240
progress(

src/notebooks/deepnote/deepnoteKernelAutoSelector.node.ts

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ import {
1212
notebooks,
1313
NotebookController,
1414
CancellationTokenSource,
15-
Disposable
15+
Disposable,
16+
l10n
1617
} from 'vscode';
1718
import { IExtensionSyncActivationService } from '../../platform/activation/types';
1819
import { IDisposableRegistry } from '../../platform/common/types';
@@ -127,8 +128,10 @@ export class DeepnoteKernelAutoSelector implements IDeepnoteKernelAutoSelector,
127128
// Always try to ensure kernel is selected (this will reuse existing controllers)
128129
// Don't await - let it happen in background so notebook opens quickly
129130
void this.ensureKernelSelected(notebook).catch((error) => {
130-
logger.error(`Failed to auto-select Deepnote kernel for ${getDisplayPath(notebook.uri)}: ${error}`);
131-
void window.showErrorMessage(`Failed to load Deepnote kernel: ${error}`);
131+
logger.error(`Failed to auto-select Deepnote kernel for ${getDisplayPath(notebook.uri)}`, error);
132+
void window.showErrorMessage(
133+
l10n.t('Failed to load Deepnote kernel. Please check the output for details.')
134+
);
132135
});
133136
}
134137

@@ -240,7 +243,7 @@ export class DeepnoteKernelAutoSelector implements IDeepnoteKernelAutoSelector,
240243
logger.info(`Init notebook cancelled for project ${projectId}`);
241244
return;
242245
}
243-
logger.error(`Error running init notebook: ${error}`);
246+
logger.error('Error running init notebook', error);
244247
// Continue anyway - don't block user if init fails
245248
} finally {
246249
// Always clean up the CTS and event listeners
@@ -253,7 +256,7 @@ export class DeepnoteKernelAutoSelector implements IDeepnoteKernelAutoSelector,
253256
return window.withProgress(
254257
{
255258
location: ProgressLocation.Notification,
256-
title: 'Loading Deepnote Kernel',
259+
title: l10n.t('Loading Deepnote Kernel'),
257260
cancellable: true
258261
},
259262
async (progress, progressToken) => {
@@ -277,7 +280,7 @@ export class DeepnoteKernelAutoSelector implements IDeepnoteKernelAutoSelector,
277280
notebook.uri
278281
)}`
279282
);
280-
progress.report({ message: 'Reusing existing kernel...' });
283+
progress.report({ message: l10n.t('Reusing existing kernel...') });
281284

282285
// Ensure server is registered with the provider (it might have been unregistered on close)
283286
if (connectionMetadata.serverInfo) {
@@ -317,7 +320,7 @@ export class DeepnoteKernelAutoSelector implements IDeepnoteKernelAutoSelector,
317320

318321
// No existing controller, so create a new one
319322
logger.info(`Creating new Deepnote kernel for ${getDisplayPath(notebook.uri)}`);
320-
progress.report({ message: 'Setting up Deepnote kernel...' });
323+
progress.report({ message: l10n.t('Setting up Deepnote kernel...') });
321324

322325
// Check if Python extension is installed
323326
if (!this.pythonExtensionChecker.isPythonExtensionInstalled) {
@@ -327,7 +330,7 @@ export class DeepnoteKernelAutoSelector implements IDeepnoteKernelAutoSelector,
327330
}
328331

329332
// Get active Python interpreter
330-
progress.report({ message: 'Finding Python interpreter...' });
333+
progress.report({ message: l10n.t('Finding Python interpreter...') });
331334
const interpreter = await this.interpreterService.getActiveInterpreter(notebook.uri);
332335
if (!interpreter) {
333336
logger.warn(
@@ -339,7 +342,7 @@ export class DeepnoteKernelAutoSelector implements IDeepnoteKernelAutoSelector,
339342
logger.info(`Using base interpreter: ${getDisplayPath(interpreter.uri)}`);
340343

341344
// Ensure deepnote-toolkit is installed in a venv and get the venv interpreter
342-
progress.report({ message: 'Installing Deepnote toolkit...' });
345+
progress.report({ message: l10n.t('Installing Deepnote toolkit...') });
343346
const venvInterpreter = await this.toolkitInstaller.ensureInstalled(
344347
interpreter,
345348
baseFileUri,
@@ -353,7 +356,7 @@ export class DeepnoteKernelAutoSelector implements IDeepnoteKernelAutoSelector,
353356
logger.info(`Deepnote toolkit venv ready at: ${getDisplayPath(venvInterpreter.uri)}`);
354357

355358
// Start the Deepnote server using the venv interpreter
356-
progress.report({ message: 'Starting Deepnote server...' });
359+
progress.report({ message: l10n.t('Starting Deepnote server...') });
357360
const serverInfo = await this.serverStarter.getOrStartServer(
358361
venvInterpreter,
359362
baseFileUri,
@@ -375,7 +378,7 @@ export class DeepnoteKernelAutoSelector implements IDeepnoteKernelAutoSelector,
375378
this.notebookServerHandles.set(notebookKey, serverProviderHandle.handle);
376379

377380
// Connect to the server and get available kernel specs
378-
progress.report({ message: 'Connecting to kernel...' });
381+
progress.report({ message: l10n.t('Connecting to kernel...') });
379382
const connectionInfo = createJupyterConnectionInfo(
380383
serverProviderHandle,
381384
{
@@ -409,10 +412,15 @@ export class DeepnoteKernelAutoSelector implements IDeepnoteKernelAutoSelector,
409412

410413
if (!kernelSpec) {
411414
logger.warn(
412-
`⚠️ Venv kernel spec '${expectedKernelName}' not found! Falling back to generic Python kernel.`
415+
l10n.t(
416+
"⚠️ Venv kernel spec '{expectedKernelName}' not found! Falling back to generic Python kernel.",
417+
{ expectedKernelName }
418+
)
413419
);
414420
logger.warn(
415-
`This may cause import errors if packages are installed to the venv but kernel uses system Python.`
421+
l10n.t(
422+
'This may cause import errors if packages are installed to the venv but kernel uses system Python.'
423+
)
416424
);
417425
kernelSpec =
418426
kernelSpecs.find((s) => s.language === 'python') ||
@@ -429,7 +437,7 @@ export class DeepnoteKernelAutoSelector implements IDeepnoteKernelAutoSelector,
429437
await disposeAsync(sessionManager);
430438
}
431439

432-
progress.report({ message: 'Finalizing kernel setup...' });
440+
progress.report({ message: l10n.t('Finalizing kernel setup...') });
433441
const newConnectionMetadata = DeepnoteKernelConnectionMetadata.create({
434442
interpreter,
435443
kernelSpec,
@@ -467,7 +475,7 @@ export class DeepnoteKernelAutoSelector implements IDeepnoteKernelAutoSelector,
467475

468476
if (project) {
469477
// Create requirements.txt first (needs to be ready for init notebook)
470-
progress.report({ message: 'Creating requirements.txt...' });
478+
progress.report({ message: l10n.t('Creating requirements.txt...') });
471479
await this.requirementsHelper.createRequirementsFile(project, progressToken);
472480
logger.info(`Created requirements.txt for project ${projectId}`);
473481

@@ -504,7 +512,7 @@ export class DeepnoteKernelAutoSelector implements IDeepnoteKernelAutoSelector,
504512
controller.controller.updateNotebookAffinity(notebook, NotebookControllerAffinity.Preferred);
505513

506514
logger.info(`Successfully auto-selected Deepnote kernel for ${getDisplayPath(notebook.uri)}`);
507-
progress.report({ message: 'Kernel ready!' });
515+
progress.report({ message: l10n.t('Kernel ready!') });
508516

509517
// Dispose the loading controller once the real one is ready
510518
const loadingController = this.loadingControllers.get(notebookKey);
@@ -514,7 +522,7 @@ export class DeepnoteKernelAutoSelector implements IDeepnoteKernelAutoSelector,
514522
logger.info(`Disposed loading controller for ${notebookKey}`);
515523
}
516524
} catch (ex) {
517-
logger.error(`Failed to auto-select Deepnote kernel: ${ex}`);
525+
logger.error('Failed to auto-select Deepnote kernel', ex);
518526
throw ex;
519527
}
520528
}
@@ -526,7 +534,7 @@ export class DeepnoteKernelAutoSelector implements IDeepnoteKernelAutoSelector,
526534
const loadingController = notebooks.createNotebookController(
527535
`deepnote-loading-${notebookKey}`,
528536
DEEPNOTE_NOTEBOOK_TYPE,
529-
'Loading Deepnote Kernel...'
537+
l10n.t('Loading Deepnote Kernel...')
530538
);
531539

532540
// Set it as the preferred controller immediately

src/notebooks/deepnote/deepnoteRequirementsHelper.node.ts

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,23 @@
11
import { inject, injectable } from 'inversify';
2-
import { workspace, CancellationToken, window } from 'vscode';
2+
import { workspace, CancellationToken, window, Uri, l10n } from 'vscode';
33
import * as fs from 'fs';
4-
import * as path from '../../platform/vscode-path/path';
4+
55
import type { DeepnoteProject } from './deepnoteTypes';
66
import { ILogger } from '../../platform/logging/types';
77
import { IPersistentStateFactory } from '../../platform/common/types';
88

99
const DONT_ASK_OVERWRITE_REQUIREMENTS_KEY = 'DEEPNOTE_DONT_ASK_OVERWRITE_REQUIREMENTS';
1010

11+
export const IDeepnoteRequirementsHelper = Symbol('IDeepnoteRequirementsHelper');
12+
export interface IDeepnoteRequirementsHelper {
13+
createRequirementsFile(project: DeepnoteProject, token: CancellationToken): Promise<void>;
14+
}
15+
1116
/**
1217
* Helper class for creating requirements.txt files from Deepnote project settings.
1318
*/
1419
@injectable()
15-
export class DeepnoteRequirementsHelper {
20+
export class DeepnoteRequirementsHelper implements IDeepnoteRequirementsHelper {
1621
constructor(
1722
@inject(ILogger) private readonly logger: ILogger,
1823
@inject(IPersistentStateFactory) private readonly persistentStateFactory: IPersistentStateFactory
@@ -36,6 +41,17 @@ export class DeepnoteRequirementsHelper {
3641
return;
3742
}
3843

44+
// Validate and normalize requirements: ensure they are valid strings, trim them, and remove empty entries
45+
const normalizedRequirements = requirements
46+
.filter((req) => typeof req === 'string') // Keep only string entries
47+
.map((req) => req.trim()) // Trim whitespace
48+
.filter((req) => req.length > 0); // Remove empty strings
49+
50+
if (normalizedRequirements.length === 0) {
51+
this.logger.info(`No valid requirements found in project ${project.project.id}`);
52+
return;
53+
}
54+
3955
// Get the workspace folder to determine where to create the requirements.txt file
4056
const workspaceFolders = workspace.workspaceFolders;
4157
if (!workspaceFolders || workspaceFolders.length === 0) {
@@ -48,11 +64,11 @@ export class DeepnoteRequirementsHelper {
4864
return;
4965
}
5066

51-
const workspaceRoot = workspaceFolders[0].uri.fsPath;
52-
const requirementsPath = path.join(workspaceRoot, 'requirements.txt');
67+
// Use Uri.joinPath to build the filesystem path using the Uri API
68+
const requirementsPath = Uri.joinPath(workspaceFolders[0].uri, 'requirements.txt').fsPath;
5369

54-
// Convert requirements array to text format first
55-
const requirementsText = requirements.join('\n') + '\n';
70+
// Convert normalized requirements array to text format
71+
const requirementsText = normalizedRequirements.join('\n') + '\n';
5672

5773
// Check if requirements.txt already exists
5874
const fileExists = await fs.promises
@@ -77,12 +93,14 @@ export class DeepnoteRequirementsHelper {
7793

7894
if (!dontAskState.value) {
7995
// User hasn't chosen "Don't Ask Again", so prompt them
80-
const yes = 'Yes';
81-
const no = 'No';
82-
const dontAskAgain = "Don't Ask Again";
96+
const yes = l10n.t('Yes');
97+
const no = l10n.t('No');
98+
const dontAskAgain = l10n.t("Don't Ask Again");
8399

84100
const response = await window.showWarningMessage(
85-
`A requirements.txt file already exists in this workspace. Do you want to override it with requirements from your Deepnote project?`,
101+
l10n.t(
102+
'A requirements.txt file already exists in this workspace. Do you want to override it with requirements from your Deepnote project?'
103+
),
86104
{ modal: true },
87105
yes,
88106
no,
@@ -131,15 +149,10 @@ export class DeepnoteRequirementsHelper {
131149
}
132150

133151
this.logger.info(
134-
`Created requirements.txt with ${requirements.length} dependencies at ${requirementsPath}`
152+
`Created requirements.txt with ${normalizedRequirements.length} dependencies at ${requirementsPath}`
135153
);
136154
} catch (error) {
137155
this.logger.error(`Error creating requirements.txt:`, error);
138156
}
139157
}
140158
}
141-
142-
export const IDeepnoteRequirementsHelper = Symbol('IDeepnoteRequirementsHelper');
143-
export interface IDeepnoteRequirementsHelper {
144-
createRequirementsFile(project: DeepnoteProject, token: CancellationToken): Promise<void>;
145-
}

0 commit comments

Comments
 (0)