Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

remove canDebug context key #7077

Merged
merged 6 commits into from
Aug 12, 2021
Merged
Show file tree
Hide file tree
Changes from 4 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
1 change: 1 addition & 0 deletions package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,7 @@
"DataScience.interactiveWindowModeBannerSwitchAlways": "Always",
"DataScience.interactiveWindowModeBannerSwitchNo": "No",
"DataScience.ipykernelNotInstalled": "IPyKernel not installed into interpreter {0}",
"DataScience.needIpykernel6": "Ipykernel 6 is needed for debugging, click Install to continue. Or you can run 'pip install ipykernel==6.0.3/conda install ipykernel=6'",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a better command line to recommend? I feel like pip install --upgrade ipykernel would work too? Or maybe that doesn't always work?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But at least the 6.0.3 version seems rather specific

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested this a lot. Unfortunately, --upgrade didn't upgrade mine from 5.5.5 to 6

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have an issue on the python extension to fix the installer. If that's fixed, I'll remove the commands from the message.
microsoft/vscode-python#16937

"DataScience.illegalEditorConfig": "CustomEditor and NativeNotebook experiments cannot be turned on together",
"DataScience.pythonExtensionRequired": "The Python extension is required to perform that task. Click Yes to open Python extension installation page.",
"DataScience.pythonExtensionRequiredToRunNotebook": "Python Extension required to run Python notebooks.",
Expand Down
4 changes: 4 additions & 0 deletions src/client/common/utils/localize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -940,6 +940,10 @@ export namespace DataScience {
'DataScience.ipykernelNotInstalled',
'IPyKernel not installed into interpreter {0}'
);
export const needIpykernel6 = localize(
'DataScience.needIpykernel6',
"Ipykernel 6 is needed for debugging, click Install to continue. Or you can run 'pip install ipykernel==6.0.3/conda install ipykernel=6'"
);
export const showDataViewerFail = localize(
'DataScience.showDataViewerFail',
'Failed to create the Data Viewer. Check the Jupyter tab of the Output window for more info.'
Expand Down
45 changes: 2 additions & 43 deletions src/client/datascience/commands/activeEditorContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
'use strict';

import { inject, injectable } from 'inversify';
import { NotebookDocument, TextEditor } from 'vscode';
import { TextEditor } from 'vscode';
import { ServerStatus } from '../../../datascience-ui/interactive-common/mainState';
import { IExtensionSingleActivationService } from '../../activation/types';
import { ICommandManager, IDocumentManager, IVSCodeNotebook } from '../../common/application/types';
Expand All @@ -13,15 +13,11 @@ import { ContextKey } from '../../common/contextKey';
import { traceError } from '../../common/logger';
import { IDisposable, IDisposableRegistry } from '../../common/types';
import { isNotebookCell } from '../../common/utils/misc';
import { PythonEnvironment } from '../../pythonEnvironments/info';
import { EditorContexts } from '../constants';
import { isJupyterNotebook, isPythonNotebook } from '../notebook/helpers/helpers';
import { INotebookControllerManager } from '../notebook/types';
import { VSCodeNotebookController } from '../notebook/vscodeNotebookController';
import {
IInteractiveWindow,
IInteractiveWindowProvider,
IKernelDependencyService,
INotebook,
INotebookEditor,
INotebookEditorProvider,
Expand All @@ -39,22 +35,18 @@ export class ActiveEditorContextService implements IExtensionSingleActivationSer
private pythonOrInteractiveOrNativeContext: ContextKey;
private canRestartNotebookKernelContext: ContextKey;
private canInterruptNotebookKernelContext: ContextKey;
private canDebug: ContextKey;
private hasNativeNotebookCells: ContextKey;
private isPythonFileActive: boolean = false;
private isPythonNotebook: ContextKey;
private hasNativeNotebookOpen: ContextKey;
private kernelCanDebugCache = new Map<PythonEnvironment, boolean>();
constructor(
@inject(IInteractiveWindowProvider) private readonly interactiveProvider: IInteractiveWindowProvider,
@inject(INotebookEditorProvider) private readonly notebookEditorProvider: INotebookEditorProvider,
@inject(IDocumentManager) private readonly docManager: IDocumentManager,
@inject(ICommandManager) private readonly commandManager: ICommandManager,
@inject(IDisposableRegistry) disposables: IDisposableRegistry,
@inject(INotebookProvider) private readonly notebookProvider: INotebookProvider,
@inject(IVSCodeNotebook) private readonly vscNotebook: IVSCodeNotebook,
@inject(IKernelDependencyService) private dependencyService: IKernelDependencyService,
@inject(INotebookControllerManager) private controllerManager: INotebookControllerManager
@inject(IVSCodeNotebook) private readonly vscNotebook: IVSCodeNotebook
) {
disposables.push(this);
this.nativeContext = new ContextKey(EditorContexts.IsNativeActive, this.commandManager);
Expand All @@ -66,7 +58,6 @@ export class ActiveEditorContextService implements IExtensionSingleActivationSer
EditorContexts.CanInterruptNotebookKernel,
this.commandManager
);
this.canDebug = new ContextKey(EditorContexts.CanDebug, this.commandManager);
this.interactiveContext = new ContextKey(EditorContexts.IsInteractiveActive, this.commandManager);
this.interactiveOrNativeContext = new ContextKey(
EditorContexts.IsInteractiveOrNativeActive,
Expand Down Expand Up @@ -101,7 +92,6 @@ export class ActiveEditorContextService implements IExtensionSingleActivationSer
this,
this.disposables
);
this.controllerManager.onNotebookControllerSelected(this.onNotebookControllerSelected, this, this.disposables);

// Do we already have python file opened.
if (this.docManager.activeTextEditor?.document.languageId === PYTHON_LANGUAGE) {
Expand All @@ -128,7 +118,6 @@ export class ActiveEditorContextService implements IExtensionSingleActivationSer
this.updateNativeNotebookContext();
this.updateNativeNotebookCellContext();
this.updateMergedContexts();
this.updateDebugContext(e?.notebook?.getMatchingInterpreter()).ignoreErrors();
}
private updateNativeNotebookContext() {
this.hasNativeNotebookOpen.set(this.vscNotebook.notebookDocuments.some(isJupyterNotebook)).ignoreErrors();
Expand Down Expand Up @@ -166,36 +155,6 @@ export class ActiveEditorContextService implements IExtensionSingleActivationSer
}
this.updateContextOfActiveNotebookKernel(activeEditor);
}
private onNotebookControllerSelected({
notebook,
controller
}: {
notebook: NotebookDocument;
controller: VSCodeNotebookController;
}) {
const activeDoc = this.vscNotebook.activeNotebookEditor?.document;
if (activeDoc === notebook) {
this.updateDebugContext(controller.connection.interpreter).ignoreErrors();
}
}
private async updateDebugContext(interpreter?: PythonEnvironment) {
if (interpreter) {
const cache = this.kernelCanDebugCache.get(interpreter);
if (cache) {
this.canDebug.set(cache).ignoreErrors();
} else {
this.canDebug.set(false).ignoreErrors();
}

const flag = await this.dependencyService.areDebuggingDependenciesInstalled(interpreter);
this.kernelCanDebugCache.set(interpreter, flag);
if (cache === undefined || cache !== flag) {
this.canDebug.set(flag).ignoreErrors();
}
} else {
this.canDebug.set(false).ignoreErrors();
}
}
private onDidChangeActiveTextEditor(e?: TextEditor) {
this.isPythonFileActive = e?.document.languageId === PYTHON_LANGUAGE && !isNotebookCell(e.document.uri);
this.updateNativeNotebookCellContext();
Expand Down
1 change: 0 additions & 1 deletion src/client/datascience/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,6 @@ export namespace EditorContexts {
export const HaveCellSelected = 'jupyter.havecellselected';
export const CanRestartNotebookKernel = 'jupyter.notebookeditor.canrestartNotebookkernel';
export const CanInterruptNotebookKernel = 'jupyter.notebookeditor.canInterruptNotebookKernel';
export const CanDebug = 'jupyter.notebookeditor.canDebug';
export const DebuggingInProgress = 'jupyter.notebookeditor.debuggingInProgress';
export const RunByLineInProgress = 'jupyter.notebookeditor.runByLineInProgress';
export const IsPythonNotebook = 'jupyter.ispythonnotebook';
Expand Down
24 changes: 0 additions & 24 deletions src/client/datascience/jupyter/kernels/kernelDependencyService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

import { inject, injectable, named } from 'inversify';
import { CancellationToken, Memento } from 'vscode';
import { IPythonInstaller } from '../../../api/types';
import { IApplicationShell, ICommandManager } from '../../../common/application/types';
import { createPromiseFromCancellation, wrapCancellationTokens } from '../../../common/cancellation';
import { isModulePresentInEnvironment } from '../../../common/installer/productInstaller';
Expand All @@ -18,12 +17,10 @@ import {
InstallerResponse,
IsCodeSpace,
Product,
ProductInstallStatus,
Resource
} from '../../../common/types';
import { Common, DataScience } from '../../../common/utils/localize';
import { noop } from '../../../common/utils/misc';
import { IServiceContainer } from '../../../ioc/types';
import { TraceOptions } from '../../../logging/trace';
import { PythonEnvironment } from '../../../pythonEnvironments/info';
import { sendTelemetryEvent } from '../../../telemetry';
Expand All @@ -42,7 +39,6 @@ export class KernelDependencyService implements IKernelDependencyService {
constructor(
@inject(IApplicationShell) private readonly appShell: IApplicationShell,
@inject(IInstaller) private readonly installer: IInstaller,
@inject(IServiceContainer) private serviceContainer: IServiceContainer,
@inject(IMemento) @named(GLOBAL_MEMENTO) private readonly memento: Memento,
@inject(IsCodeSpace) private readonly isCodeSpace: boolean,
@inject(ICommandManager) private readonly commandManager: ICommandManager
Expand Down Expand Up @@ -83,26 +79,6 @@ export class KernelDependencyService implements IKernelDependencyService {
return this.installer.isInstalled(Product.ipykernel, interpreter).then((installed) => installed === true);
}

// The requirement for debugging is ipykernel v6 or newer
public async areDebuggingDependenciesInstalled(
interpreter: PythonEnvironment,
_token?: CancellationToken
): Promise<boolean> {
try {
const installer = await this.serviceContainer.get<IPythonInstaller>(IPythonInstaller);
const result = await installer.isProductVersionCompatible(Product.ipykernel, '>=6.0.0', interpreter);
switch (result) {
case ProductInstallStatus.Installed:
return true;
case ProductInstallStatus.NotInstalled:
case ProductInstallStatus.NeedsUpgrade:
default:
return false;
}
} catch {
return false;
}
}
private handleKernelDependencyResponse(
resource: Resource,
response: KernelInterpreterDependencyResponse,
Expand Down
1 change: 0 additions & 1 deletion src/client/datascience/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1239,7 +1239,6 @@ export interface IKernelDependencyService {
disableUI?: boolean
): Promise<void>;
areDependenciesInstalled(interpreter: PythonEnvironment, _token?: CancellationToken): Promise<boolean>;
areDebuggingDependenciesInstalled(interpreter: PythonEnvironment, _token?: CancellationToken): Promise<boolean>;
}

export const IKernelVariableRequester = Symbol('IKernelVariableRequester');
Expand Down
71 changes: 55 additions & 16 deletions src/client/debugger/jupyter/debuggingManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
} from 'vscode';
import * as path from 'path';
import { IKernelProvider } from '../../datascience/jupyter/kernels/types';
import { IDisposable } from '../../common/types';
import { IDisposable, IInstaller, Product, ProductInstallStatus } from '../../common/types';
import { IKernelDebugAdapterConfig, KernelDebugAdapter, KernelDebugMode } from './kernelDebugAdapter';
import { IDebuggingCellMap, INotebookProvider } from '../../datascience/types';
import { IExtensionSingleActivationService } from '../../activation/types';
Expand All @@ -35,6 +35,7 @@ import { IFileSystem } from '../../common/platform/types';
import { IDebuggingManager } from '../types';
import { DebugProtocol } from 'vscode-debugprotocol';
import { pythonKernelDebugAdapter } from '../constants';
import { IPythonInstaller } from '../../api/types';

class Debugger {
private resolveFunc?: (value: DebugSession) => void;
Expand Down Expand Up @@ -92,7 +93,9 @@ 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(IFileSystem) private fs: IFileSystem,
@inject(IPythonInstaller) private pythonInstaller: IPythonInstaller,
@inject(IInstaller) private readonly installer: IInstaller
) {
this.debuggingInProgress = new ContextKey(EditorContexts.DebuggingInProgress, this.commandManager);
this.runByLineInProgress = new ContextKey(EditorContexts.RunByLineInProgress, this.commandManager);
Expand Down Expand Up @@ -174,22 +177,30 @@ export class DebuggingManager implements IExtensionSingleActivationService, IDeb
}
}),

this.commandManager.registerCommand(DSCommands.DebugNotebook, () => {
this.commandManager.registerCommand(DSCommands.DebugNotebook, async () => {
const editor = this.vscNotebook.activeNotebookEditor;
if (editor) {
this.updateToolbar(true);
void this.startDebugging(editor.document);
if (await this.checkForIpykernel6(editor.document)) {
this.updateToolbar(true);
void this.startDebugging(editor.document);
} else {
this.installIpykernel6(editor.document);
}
} else {
void this.appShell.showErrorMessage(DataScience.noNotebookToDebug());
}
}),

this.commandManager.registerCommand(DSCommands.RunByLine, (cell: NotebookCell) => {
this.commandManager.registerCommand(DSCommands.RunByLine, async (cell: NotebookCell) => {
const editor = this.vscNotebook.activeNotebookEditor;
if (editor) {
this.updateToolbar(true);
this.updateCellToolbar(true);
void this.startDebuggingCell(editor.document, KernelDebugMode.RunByLine, cell);
if (await this.checkForIpykernel6(editor.document)) {
this.updateToolbar(true);
this.updateCellToolbar(true);
void this.startDebuggingCell(editor.document, KernelDebugMode.RunByLine, cell);
} else {
this.installIpykernel6(editor.document);
}
} else {
void this.appShell.showErrorMessage(DataScience.noNotebookToDebug());
}
Expand All @@ -213,7 +224,7 @@ export class DebuggingManager implements IExtensionSingleActivationService, IDeb
}
}),

this.commandManager.registerCommand(DSCommands.RunAndDebugCell, (cell: NotebookCell | undefined) => {
this.commandManager.registerCommand(DSCommands.RunAndDebugCell, async (cell: NotebookCell | undefined) => {
const editor = this.vscNotebook.activeNotebookEditor;
if (!cell) {
const range = editor?.selections[0];
Expand All @@ -227,8 +238,12 @@ export class DebuggingManager implements IExtensionSingleActivationService, IDeb
}

if (editor) {
this.updateToolbar(true);
void this.startDebuggingCell(editor.document, KernelDebugMode.Cell, cell);
if (await this.checkForIpykernel6(editor.document)) {
this.updateToolbar(true);
void this.startDebuggingCell(editor.document, KernelDebugMode.Cell, cell);
} else {
this.installIpykernel6(editor.document);
}
} else {
void this.appShell.showErrorMessage(DataScience.noNotebookToDebug());
}
Expand Down Expand Up @@ -266,8 +281,6 @@ export class DebuggingManager implements IExtensionSingleActivationService, IDeb
request: 'attach',
internalConsoleOptions: 'neverOpen',
justMyCode: true,
// add the doc uri to the config
__document: doc.uri.toString(),
// add a property to the config to know if the session is runByLine
__mode: mode,
__cellIndex: cell.index
Expand All @@ -283,8 +296,6 @@ export class DebuggingManager implements IExtensionSingleActivationService, IDeb
request: 'attach',
internalConsoleOptions: 'neverOpen',
justMyCode: false,
// add the doc uri to the config
__document: doc.uri.toString(),
__mode: KernelDebugMode.Everything
};
return this.startDebuggingConfig(doc, config);
Expand Down Expand Up @@ -333,4 +344,32 @@ export class DebuggingManager implements IExtensionSingleActivationService, IDeb
await kernel.start({ document: doc });
}
}

private async checkForIpykernel6(doc: NotebookDocument): Promise<boolean> {
try {
const controller = this.notebookControllerManager.getSelectedNotebookController(doc);
const result = await this.pythonInstaller.isProductVersionCompatible(
Product.ipykernel,
'>=6.0.0',
controller?.connection.interpreter
);

return result === ProductInstallStatus.Installed;
} catch {
return false;
}
}

private async installIpykernel6(doc: NotebookDocument) {
const response = await this.appShell.showInformationMessage(
DataScience.needIpykernel6(),
{ modal: true },
DataScience.jupyterInstall()
);

if (response === DataScience.jupyterInstall()) {
const controller = this.notebookControllerManager.getSelectedNotebookController(doc);
this.installer.install(Product.ipykernel, controller?.connection.interpreter, undefined, true);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { IInstaller, InstallerResponse, Product } from '../../../../client/commo
import { Common, DataScience } from '../../../../client/common/utils/localize';
import { Commands } from '../../../../client/datascience/constants';
import { KernelDependencyService } from '../../../../client/datascience/jupyter/kernels/kernelDependencyService';
import { IServiceContainer } from '../../../../client/ioc/types';
import { EnvironmentType } from '../../../../client/pythonEnvironments/info';
import { createPythonInterpreter } from '../../../utils/interpreters';

Expand All @@ -23,20 +22,17 @@ suite('DataScience - Kernel Dependency Service', () => {
let appShell: IApplicationShell;
let cmdManager: ICommandManager;
let installer: IInstaller;
let serviceContainer: IServiceContainer;
let memento: Memento;
const interpreter = createPythonInterpreter({ displayName: 'name', envType: EnvironmentType.Conda, path: 'abc' });
setup(() => {
appShell = mock<IApplicationShell>();
installer = mock<IInstaller>();
serviceContainer = mock<IServiceContainer>();
cmdManager = mock<ICommandManager>();
memento = mock<Memento>();
when(memento.get(anything(), anything())).thenReturn(false);
dependencyService = new KernelDependencyService(
instance(appShell),
instance(installer),
instance(serviceContainer),
instance(memento),
false,
instance(cmdManager)
Expand Down