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

Kernel selection UI #8866

Merged
merged 22 commits into from
Dec 11, 2019
Merged
Show file tree
Hide file tree
Changes from all 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 news/1 Enhancements/8866.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added kernel status and selection toolbar to the notebook editor.
3 changes: 3 additions & 0 deletions package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,9 @@
"DataScience.loadingMessage": "loading ...",
"DataScience.fetchingDataViewer": "Fetching data ...",
"DataScience.noRowsInDataViewer": "No rows match current filter",
"DataScience.jupyterServer": "Jupyter Server",
"DataScience.noKernel": "No Kernel",
"DataScience.localJupyterServer": "local",

Choose a reason for hiding this comment

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

This is a dup, we need to use the existing setting Settings.JupyterServerLocalLaunch.

Copy link

Choose a reason for hiding this comment

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

I'm going to keep this here, but use it only for display

"DataScience.pandasTooOldForViewingFormat": "Python package 'pandas' is version {0}. Version 0.20 or greater is required for viewing data.",
"DataScience.pandasRequiredForViewing": "Python package 'pandas' is required for viewing data.",
"DataScience.valuesColumn": "values",
Expand Down
3 changes: 3 additions & 0 deletions src/client/common/utils/localize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,9 @@ export namespace DataScience {
export const loadingMessage = localize('DataScience.loadingMessage', 'loading ...');
export const fetchingDataViewer = localize('DataScience.fetchingDataViewer', 'Fetching data ...');
export const noRowsInDataViewer = localize('DataScience.noRowsInDataViewer', 'No rows match current filter');
export const jupyterServer = localize('DataScience.jupyterServer', 'Jupyter Server');
export const noKernel = localize('DataScience.noKernel', 'No Kernel');
export const localJupyterServer = localize('DataScience.localJupyterServer', 'local');
export const pandasTooOldForViewingFormat = localize('DataScience.pandasTooOldForViewingFormat', 'Python package \'pandas\' is version {0}. Version 0.20 or greater is required for viewing data.');
export const pandasRequiredForViewing = localize('DataScience.pandasRequiredForViewing', 'Python package \'pandas\' is required for viewing data.');
export const valuesColumn = localize('DataScience.valuesColumn', 'values');
Expand Down
2 changes: 2 additions & 0 deletions src/client/datascience/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ export enum Telemetry {
ExpandAll = 'DATASCIENCE.EXPAND_ALL',
CollapseAll = 'DATASCIENCE.COLLAPSE_ALL',
SelectJupyterURI = 'DATASCIENCE.SELECT_JUPYTER_URI',
SelectLocalJupyterKernel = 'DATASCIENCE.SELECT_LOCAL_JUPYTER_KERNEL',
SelectRemoteJupyuterKernel = 'DATASCIENCE.SELECT_REMOTE_JUPYTER_KERNEL',
SetJupyterURIToLocal = 'DATASCIENCE.SET_JUPYTER_URI_LOCAL',
SetJupyterURIToUserSpecified = 'DATASCIENCE.SET_JUPYTER_URI_USER_SPECIFIED',
Interrupt = 'DATASCIENCE.INTERRUPT',
Expand Down
39 changes: 17 additions & 22 deletions src/client/datascience/datascience.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,16 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
'use strict';
import '../common/extensions';

import { JSONObject } from '@phosphor/coreutils';
import { inject, injectable, multiInject, named, optional } from 'inversify';
import { URL } from 'url';
import * as vscode from 'vscode';

import { ICommandManager, IDebugService, IDocumentManager, IWorkspaceService } from '../common/application/types';
import { PYTHON_ALLFILES, PYTHON_LANGUAGE } from '../common/constants';
import { ContextKey } from '../common/contextKey';
import '../common/extensions';
import { traceError } from '../common/logger';
import {
BANNER_NAME_DS_SURVEY,
GLOBAL_MEMENTO,
IConfigurationService,
IDisposable,
IDisposableRegistry,
IExtensionContext,
IMemento,
IPythonExtensionBanner
} from '../common/types';
import { BANNER_NAME_DS_SURVEY, GLOBAL_MEMENTO, IConfigurationService, IDisposable, IDisposableRegistry, IExtensionContext, IMemento, IPythonExtensionBanner } from '../common/types';
import { waitForPromise } from '../common/utils/async';
import { debounceAsync, swallowExceptions } from '../common/utils/decorators';
import * as localize from '../common/utils/localize';
Expand All @@ -32,14 +21,8 @@ import { captureTelemetry, sendTelemetryEvent } from '../telemetry';
import { hasCells } from './cellFactory';
import { Commands, EditorContexts, Settings, Telemetry } from './constants';
import { createRemoteConnectionInfo } from './jupyter/jupyterUtils';
import {
ICodeWatcher,
IDataScience,
IDataScienceCodeLensProvider,
IDataScienceCommandListener,
IJupyterSessionManagerFactory,
INotebookEditorProvider
} from './types';
import { KernelSelector, KernelSpecInterpreter } from './jupyter/kernels/kernelSelector';
import { ICodeWatcher, IConnection, IDataScience, IDataScienceCodeLensProvider, IDataScienceCommandListener, IJupyterSessionManagerFactory, INotebookEditorProvider } from './types';

interface ISelectUriQuickPickItem extends vscode.QuickPickItem {
newChoice: boolean;
Expand All @@ -66,7 +49,8 @@ export class DataScience implements IDataScience {
@inject(IDebugService) private debugService: IDebugService,
@inject(IMemento) @named(GLOBAL_MEMENTO) private globalState: vscode.Memento,
@inject(IJupyterSessionManagerFactory) private jupyterSessionManagerFactory: IJupyterSessionManagerFactory,
@inject(IMultiStepInputFactory) private readonly multiStepFactory: IMultiStepInputFactory
@inject(IMultiStepInputFactory) private readonly multiStepFactory: IMultiStepInputFactory,
@inject(KernelSelector) private kernelSelector: KernelSelector
) {
this.dataScienceSurveyBanner = this.serviceContainer.get<IPythonExtensionBanner>(IPythonExtensionBanner, BANNER_NAME_DS_SURVEY);
}
Expand Down Expand Up @@ -242,6 +226,17 @@ export class DataScience implements IDataScience {
return multiStep.run(this.startSelectingURI.bind(this), {});
}

@captureTelemetry(Telemetry.SelectLocalJupyterKernel)
public async selectLocalJupyterKernel(): Promise<KernelSpecInterpreter> {
return this.kernelSelector.selectLocalKernel();
}

@captureTelemetry(Telemetry.SelectRemoteJupyuterKernel)
public async selectRemoteJupyterKernel(connInfo: IConnection): Promise<KernelSpecInterpreter> {
const session = await this.jupyterSessionManagerFactory.create(connInfo);
return this.kernelSelector.selectRemoteKernel(session);
}

public async debugCell(file: string, startLine: number, startChar: number, endLine: number, endChar: number): Promise<void> {
this.dataScienceSurveyBanner.showBanner().ignoreErrors();

Expand Down
61 changes: 60 additions & 1 deletion src/client/datascience/interactive-common/interactiveBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { ConfigurationTarget, Event, EventEmitter, Position, Range, Selection, T
import { Disposable } from 'vscode-jsonrpc';
import * as vsls from 'vsls/vscode';

import { ServerStatus } from '../../../datascience-ui/interactive-common/mainState';
import {
IApplicationShell,
IDocumentManager,
Expand All @@ -31,8 +32,9 @@ import { IInterpreterService, PythonInterpreter } from '../../interpreter/contra
import { captureTelemetry, sendTelemetryEvent } from '../../telemetry';
import { generateCellRangesFromDocument } from '../cellFactory';
import { CellMatcher } from '../cellMatcher';
import { Identifiers, Telemetry } from '../constants';
import { Identifiers, Settings, Telemetry } from '../constants';
import { ColumnWarningSize } from '../data-viewing/types';
import { DataScience } from '../datascience';
import {
IAddedSysInfo,
ICopyCode,
Expand All @@ -48,6 +50,7 @@ import {
import { JupyterInstallError } from '../jupyter/jupyterInstallError';
import { JupyterSelfCertsError } from '../jupyter/jupyterSelfCertsError';
import { JupyterKernelPromiseFailedError } from '../jupyter/kernels/jupyterKernelPromiseFailedError';
import { KernelSpecInterpreter } from '../jupyter/kernels/kernelSelector';
import { CssMessages } from '../messages';
import {
CellState,
Expand Down Expand Up @@ -110,6 +113,7 @@ export abstract class InteractiveBase extends WebViewHost<IInteractiveWindowMapp
@unmanaged() private jupyterVariables: IJupyterVariables,
@unmanaged() private jupyterDebugger: IJupyterDebugger,
@unmanaged() protected ipynbProvider: INotebookEditorProvider,
@unmanaged() private dataScience: DataScience,
@unmanaged() protected errorHandler: IDataScienceErrorHandler,
@unmanaged() rootPath: string,
@unmanaged() scripts: string[],
Expand Down Expand Up @@ -261,6 +265,14 @@ export abstract class InteractiveBase extends WebViewHost<IInteractiveWindowMapp
this.handleMessage(message, payload, this.requestOnigasm);
break;

case InteractiveWindowMessages.SelectKernel:
this.handleMessage(message, payload, this.selectKernel);
break;

case InteractiveWindowMessages.SelectJupyterServer:
this.handleMessage(message, payload, this.selectServer);
break;

default:
break;
}
Expand Down Expand Up @@ -1068,6 +1080,25 @@ export abstract class InteractiveBase extends WebViewHost<IInteractiveWindowMapp
if (this.notebook) {
const uri: Uri = await this.getNotebookIdentity();
this.postMessage(InteractiveWindowMessages.NotebookExecutionActivated, uri.toString()).ignoreErrors();

const statusChangeHandler = async (status: ServerStatus) => {
if (this.notebook) {
const settings = this.configuration.getSettings();
const kernelSpec = this.notebook.getKernelSpec();

if (kernelSpec) {
const name = kernelSpec.display_name;

await this.postMessage(InteractiveWindowMessages.UpdateKernel, {
jupyterServerStatus: status,
localizedUri: settings.datascience.jupyterServerURI.toLowerCase() === Settings.JupyterServerLocalLaunch ?
localize.DataScience.localJupyterServer() : settings.datascience.jupyterServerURI,
displayName: name
});
}
}
};
this.notebook.onSessionStatusChanged(statusChangeHandler);
}

traceInfo('Connected to jupyter server.');
Expand Down Expand Up @@ -1265,4 +1296,32 @@ export abstract class InteractiveBase extends WebViewHost<IInteractiveWindowMapp
this.postMessage(InteractiveWindowMessages.LoadOnigasmAssemblyResponse, undefined).ignoreErrors();
}
}

private async selectServer() {
await this.dataScience.selectJupyterURI();
}

private async selectKernel() {
const settings = this.configuration.getSettings();

let kernel: KernelSpecInterpreter | undefined;

if (settings.datascience.jupyterServerURI.toLowerCase() === Settings.JupyterServerLocalLaunch) {
kernel = await this.dataScience.selectLocalJupyterKernel();
} else if (this.notebook) {
const connInfo = this.notebook.server.getConnectionInfo();

if (connInfo) {
kernel = await this.dataScience.selectRemoteJupyterKernel(connInfo);
}
}

if (kernel && kernel.kernelSpec && this.notebook) {
// Tell the kernel. A status update should fire that changes our display
await this.notebook.setKernelSpec(kernel.kernelSpec);

Choose a reason for hiding this comment

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

Should't this be done first, before we update the UI?
What if this fails.

Copy link

Choose a reason for hiding this comment

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

Yeah that's probably better. Let me try that. I think I can eliminate the status update then too.


In reply to: 356777545 [](ancestors = 356777545)


// Add in a new sys info
await this.addSysInfo(SysInfoReason.New);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Licensed under the MIT License.
'use strict';
import * as monacoEditor from 'monaco-editor/esm/vs/editor/editor.api';

import { IServerState } from '../../../datascience-ui/interactive-common/mainState';
import { CssMessages, IGetCssRequest, IGetCssResponse, IGetMonacoThemeRequest } from '../messages';
import { IGetMonacoThemeResponse } from '../monacoMessages';
import { ICell, IInteractiveWindowInfo, IJupyterVariable, IJupyterVariablesResponse } from '../types';
Expand Down Expand Up @@ -83,7 +83,10 @@ export enum InteractiveWindowMessages {
ExecutionRendered = 'rendered_execution',
FocusedCellEditor = 'focused_cell_editor',
MonacoReady = 'monaco_ready',
ClearAllOutputs = 'clear_all_outputs'
ClearAllOutputs = 'clear_all_outputs',
SelectKernel = 'select_kernel',
UpdateKernel = 'update_kernel',
SelectJupyterServer = 'select_jupyter_server'
}

export enum NativeCommandType {
Expand All @@ -107,6 +110,8 @@ export enum NativeCommandType {
RunAndAdd,
RunAndMove,
RunBelow,
SelectKernel,
SelectServer,
ToggleLineNumbers,
ToggleOutput,
ToggleVariableExplorer,
Expand Down Expand Up @@ -283,6 +288,8 @@ export class IInteractiveWindowMapping {
public [InteractiveWindowMessages.CopyCodeCell]: ICopyCode;
public [InteractiveWindowMessages.NotebookExecutionActivated]: string;
public [InteractiveWindowMessages.RestartKernel]: never | undefined;
public [InteractiveWindowMessages.SelectKernel]: IServerState | undefined;
public [InteractiveWindowMessages.SelectJupyterServer]: never | undefined;
public [InteractiveWindowMessages.Export]: ICell[];
public [InteractiveWindowMessages.GetAllCells]: ICell;
public [InteractiveWindowMessages.ReturnAllCells]: ICell[];
Expand Down Expand Up @@ -354,4 +361,5 @@ export class IInteractiveWindowMapping {
public [InteractiveWindowMessages.FocusedCellEditor]: IFocusedCellEditor;
public [InteractiveWindowMessages.MonacoReady]: never | undefined;
public [InteractiveWindowMessages.ClearAllOutputs]: never | undefined;
public [InteractiveWindowMessages.UpdateKernel]: IServerState | undefined;
}
5 changes: 4 additions & 1 deletion src/client/datascience/interactive-ipynb/nativeEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ import { IInterpreterService } from '../../interpreter/contracts';
import { captureTelemetry, sendTelemetryEvent } from '../../telemetry';
import { concatMultilineStringInput, splitMultilineString } from '../common';
import { EditorContexts, Identifiers, NativeKeyboardCommandTelemetryLookup, NativeMouseCommandTelemetryLookup, Telemetry } from '../constants';
import { DataScience } from '../datascience';
import { InteractiveBase } from '../interactive-common/interactiveBase';
import { IEditCell, IInsertCell, INativeCommand, InteractiveWindowMessages, IRemoveCell, ISaveAll, ISubmitNewCell, ISwapCells } from '../interactive-common/interactiveWindowTypes';
import { InvalidNotebookFileError } from '../jupyter/invalidNotebookFileError';
import { CellState, ICell, ICodeCssGenerator, IDataScienceErrorHandler, IDataViewerProvider, IInteractiveWindowInfo, IInteractiveWindowListener, IJupyterDebugger, IJupyterExecution, IJupyterVariables, INotebookEditor, INotebookEditorProvider, INotebookExporter, INotebookImporter, INotebookServerOptions, IStatusProvider, IThemeFinder } from '../types';
import { CellState, ICell, ICodeCssGenerator, IDataScience, IDataScienceErrorHandler, IDataViewerProvider, IInteractiveWindowInfo, IInteractiveWindowListener, IJupyterDebugger, IJupyterExecution, IJupyterVariables, INotebookEditor, INotebookEditorProvider, INotebookExporter, INotebookImporter, INotebookServerOptions, IStatusProvider, IThemeFinder } from '../types';

const nativeEditorDir = path.join(EXTENSION_ROOT_DIR, 'out', 'datascience-ui', 'native-editor');
enum AskForSaveResult {
Expand Down Expand Up @@ -72,6 +73,7 @@ export class NativeEditor extends InteractiveBase implements INotebookEditor {
@inject(IJupyterVariables) jupyterVariables: IJupyterVariables,
@inject(IJupyterDebugger) jupyterDebugger: IJupyterDebugger,
@inject(INotebookImporter) private importer: INotebookImporter,
@inject(IDataScience) dataScience: DataScience,
@inject(IDataScienceErrorHandler) errorHandler: IDataScienceErrorHandler,
@inject(IMemento) @named(GLOBAL_MEMENTO) private globalStorage: Memento,
@inject(IMemento) @named(WORKSPACE_MEMENTO) private localStorage: Memento
Expand All @@ -96,6 +98,7 @@ export class NativeEditor extends InteractiveBase implements INotebookEditor {
jupyterVariables,
jupyterDebugger,
editorProvider,
dataScience,
errorHandler,
nativeEditorDir,
[path.join(nativeEditorDir, 'index_bundle.js')],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ export class NativeEditorProvider implements INotebookEditorProvider, IAsyncDisp
const useDefaultConfig: boolean | undefined = settings.datascience.useDefaultConfigForJupyter;

// For the local case pass in our URI as undefined, that way connect doesn't have to check the setting
if (serverURI === Settings.JupyterServerLocalLaunch) {
if (serverURI.toLowerCase() === Settings.JupyterServerLocalLaunch) {
serverURI = undefined;
}

Expand Down
35 changes: 6 additions & 29 deletions src/client/datascience/interactive-window/interactiveWindow.ts
Original file line number Diff line number Diff line change
@@ -1,48 +1,23 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
'use strict';
import '../../common/extensions';

import { inject, injectable, multiInject } from 'inversify';
import * as path from 'path';
import { Event, EventEmitter, TextEditor, Uri, ViewColumn } from 'vscode';

import {
IApplicationShell,
ICommandManager,
IDocumentManager,
ILiveShareApi,
IWebPanelProvider,
IWorkspaceService
} from '../../common/application/types';
import { IApplicationShell, ICommandManager, IDocumentManager, ILiveShareApi, IWebPanelProvider, IWorkspaceService } from '../../common/application/types';
import { ContextKey } from '../../common/contextKey';
import '../../common/extensions';
import { IFileSystem } from '../../common/platform/types';
import { IConfigurationService, IDisposableRegistry, IPersistentStateFactory } from '../../common/types';
import * as localize from '../../common/utils/localize';
import { EXTENSION_ROOT_DIR } from '../../constants';
import { IInterpreterService } from '../../interpreter/contracts';
import { captureTelemetry } from '../../telemetry';
import { EditorContexts, Identifiers, Telemetry } from '../constants';
import { DataScience } from '../datascience';
import { InteractiveBase } from '../interactive-common/interactiveBase';
import { InteractiveWindowMessages, ISubmitNewCell } from '../interactive-common/interactiveWindowTypes';
import {
ICell,
ICodeCssGenerator,
IDataScienceErrorHandler,
IDataViewerProvider,
IInteractiveWindow,
IInteractiveWindowInfo,
IInteractiveWindowListener,
IInteractiveWindowProvider,
IJupyterDebugger,
IJupyterExecution,
IJupyterVariables,
INotebookEditorProvider,
INotebookExporter,
INotebookServerOptions,
IStatusProvider,
IThemeFinder
} from '../types';
import { ICell, ICodeCssGenerator, IDataScience, IDataScienceErrorHandler, IDataViewerProvider, IInteractiveWindow, IInteractiveWindowInfo, IInteractiveWindowListener, IInteractiveWindowProvider, IJupyterDebugger, IJupyterExecution, IJupyterVariables, INotebookEditorProvider, INotebookExporter, INotebookServerOptions, IStatusProvider, IThemeFinder } from '../types';

const historyReactDir = path.join(EXTENSION_ROOT_DIR, 'out', 'datascience-ui', 'history-react');

Expand Down Expand Up @@ -75,6 +50,7 @@ export class InteractiveWindow extends InteractiveBase implements IInteractiveWi
@inject(IJupyterVariables) jupyterVariables: IJupyterVariables,
@inject(IJupyterDebugger) jupyterDebugger: IJupyterDebugger,
@inject(INotebookEditorProvider) editorProvider: INotebookEditorProvider,
@inject(IDataScience) dataScience: DataScience,
@inject(IDataScienceErrorHandler) errorHandler: IDataScienceErrorHandler,
@inject(IPersistentStateFactory) private readonly stateFactory: IPersistentStateFactory
) {
Expand All @@ -98,6 +74,7 @@ export class InteractiveWindow extends InteractiveBase implements IInteractiveWi
jupyterVariables,
jupyterDebugger,
editorProvider,
dataScience,
errorHandler,
historyReactDir,
[path.join(historyReactDir, 'index_bundle.js')],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export class InteractiveWindowProvider implements IInteractiveWindowProvider, IA
const useDefaultConfig: boolean | undefined = settings.datascience.useDefaultConfigForJupyter;

// For the local case pass in our URI as undefined, that way connect doesn't have to check the setting
if (serverURI === Settings.JupyterServerLocalLaunch) {
if (serverURI.toLowerCase() === Settings.JupyterServerLocalLaunch) {
serverURI = undefined;
}

Expand Down
Loading