diff --git a/news/2 Fixes/9973.md b/news/2 Fixes/9973.md new file mode 100644 index 00000000000..edffc7aa7c0 --- /dev/null +++ b/news/2 Fixes/9973.md @@ -0,0 +1 @@ +Support notebook debugging in the web extension. \ No newline at end of file diff --git a/package.json b/package.json index 2fa4daff732..2799feef976 100644 --- a/package.json +++ b/package.json @@ -291,7 +291,7 @@ "title": "%jupyter.command.jupyter.debug.title%", "icon": "$(bug)", "category": "Jupyter", - "enablement": "notebookKernelCount > 0 && !jupyter.notebookeditor.debuggingInProgress && !jupyter.notebookeditor.runByLineInProgress && !jupyter.webExtension" + "enablement": "notebookKernelCount > 0 && !jupyter.notebookeditor.debuggingInProgress && !jupyter.notebookeditor.runByLineInProgress" }, { "command": "jupyter.filterKernels", @@ -304,28 +304,27 @@ "title": "%jupyter.command.jupyter.runByLine.title%", "icon": "$(debug-line-by-line)", "category": "Jupyter", - "enablement": "notebookKernelCount > 0 && !jupyter.notebookeditor.debuggingInProgress && !jupyter.notebookeditor.runByLineInProgress && !jupyter.webExtension" + "enablement": "notebookKernelCount > 0 && !jupyter.notebookeditor.debuggingInProgress && !jupyter.notebookeditor.runByLineInProgress" }, { "command": "jupyter.runAndDebugCell", "title": "%jupyter.command.jupyter.debugCell.title%", "icon": "$(debug-alt-small)", - "category": "Jupyter", - "enablement": "!jupyter.webExtension" + "category": "Jupyter" }, { "command": "jupyter.runByLineNext", "title": "%jupyter.command.jupyter.runByLineNext.title%", "icon": "$(debug-line-by-line)", "category": "Jupyter", - "enablement": "jupyter.notebookeditor.runByLineInProgress && !jupyter.webExtension" + "enablement": "jupyter.notebookeditor.runByLineInProgress" }, { "command": "jupyter.runByLineStop", "title": "%jupyter.command.jupyter.runByLineStop.title%", "icon": "$(debug-continue-small)", "category": "Jupyter", - "enablement": "notebookKernelCount > 0 && jupyter.notebookeditor.runByLineInProgress && !jupyter.webExtension" + "enablement": "notebookKernelCount > 0 && jupyter.notebookeditor.runByLineInProgress" }, { "command": "jupyter.viewOutput", @@ -383,25 +382,25 @@ "command": "jupyter.debugcell", "title": "%jupyter.command.jupyter.debugcell.title%", "category": "Jupyter", - "enablement": "isWorkspaceTrusted && !jupyter.webExtension" + "enablement": "isWorkspaceTrusted" }, { "command": "jupyter.debugstepover", "title": "%jupyter.command.jupyter.debugstepover.title%", "category": "Jupyter", - "enablement": "isWorkspaceTrusted && !jupyter.webExtension" + "enablement": "isWorkspaceTrusted" }, { "command": "jupyter.debugstop", "title": "%jupyter.command.jupyter.debugstop.title%", "category": "Jupyter", - "enablement": "isWorkspaceTrusted && !jupyter.webExtension" + "enablement": "isWorkspaceTrusted" }, { "command": "jupyter.debugcontinue", "title": "%jupyter.command.jupyter.debugcontinue.title%", "category": "Jupyter", - "enablement": "isWorkspaceTrusted && !jupyter.webExtension" + "enablement": "isWorkspaceTrusted" }, { "command": "jupyter.insertCellBelowPosition", diff --git a/src/kernels/debugging/jupyterDebugService.node.ts b/src/kernels/debugging/jupyterDebugService.node.ts index 01a04676b50..0906a8337bc 100644 --- a/src/kernels/debugging/jupyterDebugService.node.ts +++ b/src/kernels/debugging/jupyterDebugService.node.ts @@ -1,6 +1,5 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import { IDisposable } from '@fluentui/react'; import { inject, injectable } from 'inversify'; import * as net from 'net'; import * as path from '../../platform/vscode-path/path'; @@ -24,7 +23,7 @@ import { } from 'vscode'; import { DebugProtocol } from 'vscode-debugprotocol'; import { traceInfo, traceError } from '../../platform/logging'; -import { IDisposableRegistry } from '../../platform/common/types'; +import { IDisposable, IDisposableRegistry } from '../../platform/common/types'; import { createDeferred } from '../../platform/common/utils/async'; import { noop } from '../../platform/common/utils/misc'; import { EXTENSION_ROOT_DIR } from '../../platform/constants.node'; diff --git a/src/platform/debugger/jupyter/debugger.node.ts b/src/platform/debugger/jupyter/debugger.ts similarity index 100% rename from src/platform/debugger/jupyter/debugger.node.ts rename to src/platform/debugger/jupyter/debugger.ts diff --git a/src/platform/debugger/jupyter/helper.node.ts b/src/platform/debugger/jupyter/helper.ts similarity index 100% rename from src/platform/debugger/jupyter/helper.node.ts rename to src/platform/debugger/jupyter/helper.ts diff --git a/src/platform/debugger/jupyter/kernelDebugAdapter.node.ts b/src/platform/debugger/jupyter/kernelDebugAdapter.ts similarity index 90% rename from src/platform/debugger/jupyter/kernelDebugAdapter.node.ts rename to src/platform/debugger/jupyter/kernelDebugAdapter.ts index 6b918198240..d3076505118 100644 --- a/src/platform/debugger/jupyter/kernelDebugAdapter.node.ts +++ b/src/platform/debugger/jupyter/kernelDebugAdapter.ts @@ -35,13 +35,8 @@ import { IKernelDebugAdapterConfig, KernelDebugMode } from '../types'; -import { - assertIsDebugConfig, - getMessageSourceAndHookIt, - isShortNamePath, - shortNameMatchesLongName -} from './helper.node'; -import { IFileSystem } from '../../common/platform/types'; +import { assertIsDebugConfig, getMessageSourceAndHookIt, isShortNamePath, shortNameMatchesLongName } from './helper'; +import { executeSilently } from '../../../kernels/helpers'; // For info on the custom requests implemented by jupyter see: // https://jupyter-client.readthedocs.io/en/stable/messaging.html#debug-request @@ -64,7 +59,6 @@ export class KernelDebugAdapter implements DebugAdapter, IKernelDebugAdapter, ID private session: DebugSession, private notebookDocument: NotebookDocument, private readonly jupyterSession: IJupyterSession, - private fs: IFileSystem, private readonly kernel: IKernel | undefined, private readonly platformService: IPlatformService ) { @@ -195,16 +189,11 @@ export class KernelDebugAdapter implements DebugAdapter, IKernelDebugAdapter, ID } dispose() { - this.disposables.forEach((d) => d.dispose()); - // clean temp files - this.cellToFile.forEach((tempPath) => { - const norm = path.normalize(tempPath); - try { - void this.fs.deleteLocalFile(norm); - } catch { - traceError('Error deleting temporary debug files'); - } + // On dispose, delete our temp cell files + this.deleteDumpCells().catch(() => { + traceError('Error deleting temporary debug files.'); }); + this.disposables.forEach((d) => d.dispose()); } public stackTrace(args: DebugProtocol.StackTraceArguments): Thenable { @@ -275,6 +264,35 @@ export class KernelDebugAdapter implements DebugAdapter, IKernelDebugAdapter, ID return undefined; } + // Use our jupyter session to delete all the cells + private async deleteDumpCells() { + const fileValues = [...this.cellToFile.values()]; + // Need to have our Jupyter Session and some dumpCell files to delete + if (this.jupyterSession && fileValues.length) { + // Create our python string of file names + const fileListString = fileValues + .map((filePath) => { + return '"' + filePath + '"'; + }) + .join(','); + + // Insert into our delete snippet + const deleteFilesCode = `import os +_VSCODE_fileList = [${fileListString}] +for file in _VSCODE_fileList: + try: + os.remove(file) + except: + pass +del _VSCODE_fileList`; + + return executeSilently(this.jupyterSession, deleteFilesCode, { + traceErrors: true, + traceErrorsMessage: 'Error deleting temporary debugging files' + }); + } + } + private async sendRequestToJupyterSession(message: DebugProtocol.ProtocolMessage) { if (this.jupyterSession.disposed || this.jupyterSession.status === 'dead') { traceInfo(`Skipping sending message ${message.type} because session is disposed`); diff --git a/src/platform/debugger/jupyter/notebook/debugCellControllers.node.ts b/src/platform/debugger/jupyter/notebook/debugCellControllers.ts similarity index 96% rename from src/platform/debugger/jupyter/notebook/debugCellControllers.node.ts rename to src/platform/debugger/jupyter/notebook/debugCellControllers.ts index b52e3849db4..bc69e80d2b8 100644 --- a/src/platform/debugger/jupyter/notebook/debugCellControllers.node.ts +++ b/src/platform/debugger/jupyter/notebook/debugCellControllers.ts @@ -8,7 +8,7 @@ import { IKernel } from '../../../../kernels/types'; import { sendTelemetryEvent } from '../../../../telemetry'; import { DebuggingTelemetry } from '../../constants'; import { IDebuggingDelegate, IKernelDebugAdapter } from '../../types'; -import { cellDebugSetup } from '../helper.node'; +import { cellDebugSetup } from '../helper'; export class DebugCellController implements IDebuggingDelegate { constructor( diff --git a/src/platform/debugger/jupyter/notebook/debuggingManager.node.ts b/src/platform/debugger/jupyter/notebook/debuggingManager.ts similarity index 97% rename from src/platform/debugger/jupyter/notebook/debuggingManager.node.ts rename to src/platform/debugger/jupyter/notebook/debuggingManager.ts index f8bc0268912..b8f490f4467 100644 --- a/src/platform/debugger/jupyter/notebook/debuggingManager.node.ts +++ b/src/platform/debugger/jupyter/notebook/debuggingManager.ts @@ -20,7 +20,7 @@ import { import * as path from '../../../vscode-path/path'; import { IKernel, IKernelProvider } from '../../../../kernels/types'; import { IConfigurationService, IDisposable } from '../../../common/types'; -import { KernelDebugAdapter } from '../kernelDebugAdapter.node'; +import { KernelDebugAdapter } from '../kernelDebugAdapter'; import { IExtensionSingleActivationService } from '../../../activation/types'; import { ContextKey } from '../../../common/contextKey'; import { IApplicationShell, ICommandManager, IVSCodeNotebook } from '../../../common/application/types'; @@ -31,12 +31,11 @@ import { IPlatformService } from '../../../common/platform/types'; import { IDebuggingManager, IKernelDebugAdapterConfig, KernelDebugMode } from '../../types'; import { DebuggingTelemetry, pythonKernelDebugAdapter } from '../../constants'; import { sendTelemetryEvent } from '../../../../telemetry'; -import { DebugCellController } from './debugCellControllers.node'; -import { assertIsDebugConfig, IpykernelCheckResult, isUsingIpykernel6OrLater } from '../helper.node'; -import { Debugger } from '../debugger.node'; +import { DebugCellController } from './debugCellControllers'; +import { assertIsDebugConfig, IpykernelCheckResult, isUsingIpykernel6OrLater } from '../helper'; +import { Debugger } from '../debugger'; import { INotebookControllerManager } from '../../../../notebooks/types'; -import { IFileSystem } from '../../../common/platform/types'; -import { RunByLineController } from './runByLineController.node'; +import { RunByLineController } from './runByLineController'; /** * The DebuggingManager maintains the mapping between notebook documents and debug sessions. @@ -58,7 +57,6 @@ export class DebuggingManager implements IExtensionSingleActivationService, IDeb @inject(ICommandManager) private readonly commandManager: ICommandManager, @inject(IApplicationShell) private readonly appShell: IApplicationShell, @inject(IVSCodeNotebook) private readonly vscNotebook: IVSCodeNotebook, - @inject(IFileSystem) private fs: IFileSystem, @inject(IConfigurationService) private settings: IConfigurationService, @inject(IPlatformService) private platform: IPlatformService ) { @@ -381,7 +379,6 @@ export class DebuggingManager implements IExtensionSingleActivationService, IDeb session, debug.document, kernel.session, - this.fs, kernel, this.platform ); diff --git a/src/platform/debugger/jupyter/notebook/runByLineController.node.ts b/src/platform/debugger/jupyter/notebook/runByLineController.ts similarity index 99% rename from src/platform/debugger/jupyter/notebook/runByLineController.node.ts rename to src/platform/debugger/jupyter/notebook/runByLineController.ts index 7b55ad42905..0912ee13238 100644 --- a/src/platform/debugger/jupyter/notebook/runByLineController.node.ts +++ b/src/platform/debugger/jupyter/notebook/runByLineController.ts @@ -14,7 +14,7 @@ import { sendTelemetryEvent } from '../../../../telemetry'; import { DebuggingTelemetry } from '../../constants'; import { IDebuggingDelegate, IKernelDebugAdapter, KernelDebugMode } from '../../types'; import { Commands } from '../../../common/constants'; -import { cellDebugSetup } from '../helper.node'; +import { cellDebugSetup } from '../helper'; export class RunByLineController implements IDebuggingDelegate { private lastPausedThreadId: number | undefined; diff --git a/src/platform/serviceRegistry.node.ts b/src/platform/serviceRegistry.node.ts index c7debf5b414..363df476e27 100644 --- a/src/platform/serviceRegistry.node.ts +++ b/src/platform/serviceRegistry.node.ts @@ -33,7 +33,7 @@ import { GlobalActivation } from './common/globalActivation'; import { PreReleaseChecker } from './common/prereleaseChecker.node'; import { IConfigurationService, IDataScienceCommandListener, IExtensionContext } from './common/types'; import { DebugLocationTrackerFactory } from './debugger/debugLocationTrackerFactory.node'; -import { DebuggingManager } from './debugger/jupyter/notebook/debuggingManager.node'; +import { DebuggingManager } from './debugger/jupyter/notebook/debuggingManager'; import { IDebugLocationTracker, IDebuggingManager } from './debugger/types'; import { DataScienceErrorHandler } from './errors/errorHandler'; import { IDataScienceErrorHandler } from './errors/types'; diff --git a/src/platform/serviceRegistry.web.ts b/src/platform/serviceRegistry.web.ts index b8cbd890fc1..b928e80f3ac 100644 --- a/src/platform/serviceRegistry.web.ts +++ b/src/platform/serviceRegistry.web.ts @@ -27,6 +27,8 @@ import { GlobalActivation } from './common/globalActivation'; import { IExtensionSingleActivationService } from './activation/types'; import { ExtensionSideRenderer, IExtensionSideRenderer } from '../webviews/extension-side/renderer'; import { OutputCommandListener } from './logging/outputCommandListener'; +import { IDebuggingManager } from './debugger/types'; +import { DebuggingManager } from './debugger/jupyter/notebook/debuggingManager'; import { ExportDialog } from './export/exportDialog'; import { ExportFormat, IExport, IExportDialog, IFileConverter } from './export/types'; import { FileConverter } from './export/fileConverter.web'; @@ -56,4 +58,8 @@ export function registerTypes(context: IExtensionContext, serviceManager: IServi registerApiTypes(serviceManager); registerActivationTypes(serviceManager); registerDevToolTypes(context, serviceManager, isDevMode); + + serviceManager.addSingleton(IDebuggingManager, DebuggingManager, undefined, [ + IExtensionSingleActivationService + ]); } diff --git a/src/test/debugger/jupyter/helpers.unit.test.ts b/src/test/debugger/jupyter/helpers.unit.test.ts index b6148efed5c..09eb3b622f5 100644 --- a/src/test/debugger/jupyter/helpers.unit.test.ts +++ b/src/test/debugger/jupyter/helpers.unit.test.ts @@ -2,7 +2,7 @@ // Licensed under the MIT License. import { expect } from 'chai'; -import { isShortNamePath } from '../../../platform/debugger/jupyter/helper.node'; +import { isShortNamePath } from '../../../platform/debugger/jupyter/helper'; suite('Debugging - Helpers', () => { suite('isShortNamePath', async () => {