From f44ae6ab959ac562af8440d0ac5b648b60e79b41 Mon Sep 17 00:00:00 2001 From: Kyle Kavanagh Date: Sat, 17 Aug 2019 13:28:57 -0500 Subject: [PATCH 1/7] Working kernel selection when session created --- .../datascience/jupyter/jupyterSession.ts | 72 +++++++++++++++++-- .../jupyter/jupyterSessionManager.ts | 14 ++-- 2 files changed, 75 insertions(+), 11 deletions(-) diff --git a/src/client/datascience/jupyter/jupyterSession.ts b/src/client/datascience/jupyter/jupyterSession.ts index 515739ed95df..1e264333b6fd 100644 --- a/src/client/datascience/jupyter/jupyterSession.ts +++ b/src/client/datascience/jupyter/jupyterSession.ts @@ -14,7 +14,7 @@ import { JSONObject } from '@phosphor/coreutils'; import { Slot } from '@phosphor/signaling'; import { Agent as HttpsAgent } from 'https'; import * as uuid from 'uuid/v4'; -import { Event, EventEmitter } from 'vscode'; +import { Event, EventEmitter, QuickPickItem } from 'vscode'; import { CancellationToken } from 'vscode-jsonrpc'; import { Cancellation } from '../../common/cancellation'; @@ -33,6 +33,11 @@ import { import { JupyterKernelPromiseFailedError } from './jupyterKernelPromiseFailedError'; import { JupyterWaitForIdleError } from './jupyterWaitForIdleError'; import { createJupyterWebSocket } from './jupyterWebSocket'; +import { IApplicationShell } from '../../common/application/types'; + +interface KernelQuickPickItem extends QuickPickItem { + kernelId: string; +} export class JupyterSession implements IJupyterSession { private connInfo: IConnection | undefined; @@ -47,12 +52,17 @@ export class JupyterSession implements IJupyterSession { private connected: boolean = false; private jupyterPasswordConnect: IJupyterPasswordConnect; private oldSessions: Session.ISession[] = []; + private readonly appShell: IApplicationShell; + private allowShutdown: boolean = true; constructor( + appShell: IApplicationShell, connInfo: IConnection, kernelSpec: IJupyterKernelSpec | undefined, jupyterPasswordConnect: IJupyterPasswordConnect ) { + console.trace() + this.appShell = appShell; this.connInfo = connInfo; this.kernelSpec = kernelSpec; this.jupyterPasswordConnect = jupyterPasswordConnect; @@ -154,6 +164,7 @@ export class JupyterSession implements IJupyterSession { this.sessionManager = new SessionManager({ serverSettings: serverSettings }); this.contentsManager = new ContentsManager({ serverSettings: serverSettings }); + // Start a new session this.session = await this.createSession(serverSettings, this.contentsManager, cancelToken); @@ -217,12 +228,45 @@ export class JupyterSession implements IJupyterSession { throw exception; } + private async createSession(serverSettings: ServerConnection.ISettings, contentsManager: ContentsManager, cancelToken?: CancellationToken): Promise { // Create a temporary notebook for this session. this.notebookFiles.push(await contentsManager.newUntitled({ type: 'notebook' })); - // Create our session options using this temporary notebook and our connection info + const runningKernels: Kernel.IModel[] = await Kernel.listRunning(serverSettings); + const arr: KernelQuickPickItem[] = runningKernels.map(runningKernel => { + traceInfo(`Found running kernel ${runningKernel.id}, running since ${runningKernel.last_activity}`); + const localLastActivity = runningKernel.last_activity ? new Date(runningKernel.last_activity.toString()).toLocaleString() : '?'; + return { + label: `Kernel ${runningKernel.name} - ${runningKernel.id}`, + detail: `Running since ${localLastActivity}, ${runningKernel.connections} existing connections`, + kernelId: runningKernel.id + }; + }); + const startNewKernel = { + label: 'Start new kernel on Jupyter server', + picked: true, + kernelId: 'none' + }; + arr.unshift(startNewKernel); + + const kernelSelection = await this.appShell.showQuickPick(arr, { + ignoreFocusOut: true, + placeHolder: 'Select Jupyer Kernel' + }); + + const autoShutdown = { + label: 'Automatically shutdown Kernel when closed', + picked: true + }; + const leaveRunning = { + label: 'Leave Kernel running when closed', + picked: true + }; + const shutdownOptions = [autoShutdown, leaveRunning]; + const shutdownSelection = await this.appShell.showQuickPick(shutdownOptions, { ignoreFocusOut: true }); + const options: Session.IOptions = { path: this.notebookFiles[this.notebookFiles.length - 1].path, kernelName: this.kernelSpec ? this.kernelSpec.name : '', @@ -230,6 +274,20 @@ export class JupyterSession implements IJupyterSession { serverSettings: serverSettings }; + if (kernelSelection && kernelSelection !== startNewKernel) { + options.kernelId = kernelSelection.kernelId + traceInfo(`Connecting to existing kernel ${kernelSelection.kernelId}`); + } else { + traceInfo('Creating new kernel for connection'); + } + + if (shutdownSelection === leaveRunning) { + this.allowShutdown = false; + traceInfo('Session will not be shutdown on close'); + } + + // Create our session options using this temporary notebook and our connection info + return Cancellation.race(() => this.sessionManager!.startNew(options), cancelToken); } @@ -347,10 +405,14 @@ export class JupyterSession implements IJupyterSession { }); } } - await waitForPromise(session.shutdown(), 1000); + if (this.allowShutdown) { + await waitForPromise(session.shutdown(), 1000); + } } else { - // Shutdown may fail if the process has been killed - await waitForPromise(session.shutdown(), 1000); + if (this.allowShutdown) { + // Shutdown may fail if the process has been killed + await waitForPromise(session.shutdown(), 1000); + } } } catch { noop(); diff --git a/src/client/datascience/jupyter/jupyterSessionManager.ts b/src/client/datascience/jupyter/jupyterSessionManager.ts index b36053bb1418..025e345cc33c 100644 --- a/src/client/datascience/jupyter/jupyterSessionManager.ts +++ b/src/client/datascience/jupyter/jupyterSessionManager.ts @@ -6,18 +6,20 @@ import { inject, injectable } from 'inversify'; import { CancellationToken } from 'vscode-jsonrpc'; import { IConnection, IJupyterKernelSpec, IJupyterPasswordConnect, IJupyterSession, IJupyterSessionManager } from '../types'; +import { IApplicationShell } from '../../common/application/types'; import { JupyterKernelSpec } from './jupyterKernelSpec'; import { JupyterSession } from './jupyterSession'; @injectable() export class JupyterSessionManager implements IJupyterSessionManager { constructor( - @inject(IJupyterPasswordConnect) private jupyterPasswordConnect: IJupyterPasswordConnect - ) {} + @inject(IJupyterPasswordConnect) private jupyterPasswordConnect: IJupyterPasswordConnect, + @inject(IApplicationShell) private appShell: IApplicationShell + ) { } - public async startNew(connInfo: IConnection, kernelSpec: IJupyterKernelSpec | undefined, cancelToken?: CancellationToken) : Promise { + public async startNew(connInfo: IConnection, kernelSpec: IJupyterKernelSpec | undefined, cancelToken?: CancellationToken): Promise { // Create a new session and attempt to connect to it - const session = new JupyterSession(connInfo, kernelSpec, this.jupyterPasswordConnect); + const session = new JupyterSession(this.appShell, connInfo, kernelSpec, this.jupyterPasswordConnect); try { await session.connect(cancelToken); } finally { @@ -28,8 +30,8 @@ export class JupyterSessionManager implements IJupyterSessionManager { return session; } - public async getActiveKernelSpecs(connection: IConnection) : Promise { - let sessionManager: SessionManager | undefined ; + public async getActiveKernelSpecs(connection: IConnection): Promise { + let sessionManager: SessionManager | undefined; try { // Use our connection to create a session manager const serverSettings = ServerConnection.makeSettings( From 509e50bf41837f7f15affe6fe8d5b0ced822508b Mon Sep 17 00:00:00 2001 From: Kyle Kavanagh Date: Sat, 17 Aug 2019 15:12:22 -0500 Subject: [PATCH 2/7] Select jupyter kernel once up front --- package.json | 14 ++++ src/client/common/types.ts | 2 + src/client/datascience/constants.ts | 2 + src/client/datascience/datascience.ts | 66 +++++++++++++++++-- .../datascience/jupyter/jupyterExecution.ts | 6 +- .../datascience/jupyter/jupyterSession.ts | 64 ++++-------------- .../jupyter/jupyterSessionManager.ts | 38 +++++++---- .../liveshare/guestJupyterSessionManager.ts | 12 +++- src/client/datascience/types.ts | 1 + src/client/telemetry/index.ts | 2 + .../react-common/settingsReactSide.ts | 2 + src/test/datascience/color.test.ts | 2 + .../datascience/dataScienceIocContainer.ts | 2 + .../codewatcher.unit.test.ts | 2 + src/test/datascience/execution.unit.test.ts | 2 + ...eractiveWindowCommandListener.unit.test.ts | 2 + .../interactiveWindowTestHelpers.tsx | 2 + src/test/datascience/mockJupyterManager.ts | 5 ++ src/test/datascience/reactHelpers.ts | 2 + 19 files changed, 152 insertions(+), 76 deletions(-) diff --git a/package.json b/package.json index c022da8be5d3..b74aa90d38c0 100644 --- a/package.json +++ b/package.json @@ -72,6 +72,8 @@ "onCommand:python.datascience.showhistorypane", "onCommand:python.datascience.importnotebook", "onCommand:python.datascience.selectjupyteruri", + "onCommand:python.dataScience.jupyterserverkernelid", + "onCommand:python.dataScience.jupyterserverallowkernelshutdown", "onCommand:python.datascience.exportfileasnotebook", "onCommand:python.datascience.exportfileandoutputasnotebook", "onCommand:python.enableSourceMapSupport" @@ -1365,6 +1367,18 @@ "description": "Select the Jupyter server URI to connect to. Select 'local' to launch a new Juypter server on the local machine.", "scope": "resource" }, + "python.dataScience.jupyterServerKernelId": { + "type": "string", + "default": "", + "description": "Select the Jupyter server Kernel UUID to connect to. Leave blank to start a new kernel", + "scope": "resource" + }, + "python.dataScience.jupyterServerAllowKernelShutdown": { + "type": "boolean", + "default": true, + "description": "Shutdown the Jupyter kernel when finishede", + "scope": "resource" + }, "python.dataScience.notebookFileRoot": { "type": "string", "default": "${workspaceFolder}", diff --git a/src/client/common/types.ts b/src/client/common/types.ts index bf2354d29f9f..0e223ca96efc 100644 --- a/src/client/common/types.ts +++ b/src/client/common/types.ts @@ -303,6 +303,8 @@ export interface IDataScienceSettings { jupyterInterruptTimeout: number; jupyterLaunchTimeout: number; jupyterLaunchRetries: number; + jupyterServerAllowKernelShutdown: boolean, + jupyterServerKernelId: string, jupyterServerURI: string; notebookFileRoot: string; changeDirOnImportExport: boolean; diff --git a/src/client/datascience/constants.ts b/src/client/datascience/constants.ts index 216f37fea021..c9bc41936473 100644 --- a/src/client/datascience/constants.ts +++ b/src/client/datascience/constants.ts @@ -112,6 +112,8 @@ export enum Telemetry { ExpandAll = 'DATASCIENCE.EXPAND_ALL', CollapseAll = 'DATASCIENCE.COLLAPSE_ALL', SelectJupyterURI = 'DATASCIENCE.SELECT_JUPYTER_URI', + JupyterKernelSpecified = 'DATASCIENCE.JUPYTER_KERNEL_SPECIFIED', + JupyterKernelAutoShutdown = 'DATASCIENCE.JUPYTER_AUTO_SHUTDOWN', SetJupyterURIToLocal = 'DATASCIENCE.SET_JUPYTER_URI_LOCAL', SetJupyterURIToUserSpecified = 'DATASCIENCE.SET_JUPYTER_URI_USER_SPECIFIED', Interrupt = 'DATASCIENCE.INTERRUPT', diff --git a/src/client/datascience/datascience.ts b/src/client/datascience/datascience.ts index 55e5579ad43a..e6e93001674b 100644 --- a/src/client/datascience/datascience.ts +++ b/src/client/datascience/datascience.ts @@ -2,7 +2,7 @@ // Licensed under the MIT License. 'use strict'; import '../common/extensions'; - +import { Kernel } from '@jupyterlab/services'; import { JSONObject } from '@phosphor/coreutils'; import { inject, injectable } from 'inversify'; import { URL } from 'url'; @@ -11,7 +11,7 @@ import * as vscode from 'vscode'; import { IApplicationShell, ICommandManager, IDebugService, IDocumentManager, IWorkspaceService } from '../common/application/types'; import { PYTHON_ALLFILES, PYTHON_LANGUAGE } from '../common/constants'; import { ContextKey } from '../common/contextKey'; -import { traceError } from '../common/logger'; +import { traceInfo, traceError } from '../common/logger'; import { BANNER_NAME_DS_SURVEY, IConfigurationService, @@ -26,7 +26,12 @@ import { IServiceContainer } from '../ioc/types'; import { captureTelemetry, sendTelemetryEvent } from '../telemetry'; import { hasCells } from './cellFactory'; import { Commands, EditorContexts, Settings, Telemetry } from './constants'; -import { ICodeWatcher, IDataScience, IDataScienceCodeLensProvider, IDataScienceCommandListener } from './types'; +import { JupyterExecutionBase } from './jupyter/jupyterExecution'; +import { ICodeWatcher, IDataScience, IDataScienceCodeLensProvider, IDataScienceCommandListener, IJupyterSessionManager } from './types'; + +interface IKernelQuickPickItem extends vscode.QuickPickItem { + kernelId: string; +} @injectable() export class DataScience implements IDataScience { @@ -44,7 +49,8 @@ export class DataScience implements IDataScience { @inject(IDocumentManager) private documentManager: IDocumentManager, @inject(IApplicationShell) private appShell: IApplicationShell, @inject(IDebugService) private debugService: IDebugService, - @inject(IWorkspaceService) private workspace: IWorkspaceService + @inject(IWorkspaceService) private workspace: IWorkspaceService, + @inject(IJupyterSessionManager) private sessionManager: IJupyterSessionManager ) { this.commandListeners = this.serviceContainer.getAll(IDataScienceCommandListener); this.dataScienceSurveyBanner = this.serviceContainer.get(IPythonExtensionBanner, BANNER_NAME_DS_SURVEY); @@ -289,6 +295,58 @@ export class DataScience implements IDataScience { if (userURI) { await this.configuration.updateSetting('dataScience.jupyterServerURI', userURI, undefined, vscode.ConfigurationTarget.Workspace); + + const connInfo = JupyterExecutionBase.createRemoteConnectionInfo(userURI, this.configuration); + + const runningKernels: Kernel.IModel[] = await this.sessionManager.getActiveKernels(connInfo); + const arr: IKernelQuickPickItem[] = runningKernels.map(runningKernel => { + traceInfo(`Found running kernel ${runningKernel.id}, running since ${runningKernel.last_activity}`); + const localLastActivity = runningKernel.last_activity ? new Date(runningKernel.last_activity.toString()).toLocaleString() : '?'; + return { + label: `Kernel ${runningKernel.name} - ${runningKernel.id}`, + detail: `Running since ${localLastActivity}, ${runningKernel.connections} existing connections`, + kernelId: runningKernel.id + }; + }); + const startNewKernel = { + label: 'Start new kernel on Jupyter server', + picked: true, + kernelId: 'none' + }; + arr.unshift(startNewKernel); + + const kernelSelection = await this.appShell.showQuickPick(arr, { + ignoreFocusOut: true, + placeHolder: 'Select Jupyer Kernel' + }); + + const autoShutdown = { + label: 'Automatically shutdown Kernel when closed', + picked: true + }; + const leaveRunning = { + label: 'Leave Kernel running when closed', + picked: true + }; + const shutdownOptions = [autoShutdown, leaveRunning]; + const shutdownSelection = await this.appShell.showQuickPick(shutdownOptions, { ignoreFocusOut: true }); + + if (kernelSelection && kernelSelection !== startNewKernel) { + traceInfo(`Connecting to existing kernel ${kernelSelection.kernelId}`); + sendTelemetryEvent(Telemetry.JupyterKernelSpecified); + await this.configuration.updateSetting('dataScience.jupyterServerKernelId', kernelSelection.kernelId, undefined, vscode.ConfigurationTarget.Workspace); + } else { + traceInfo('Creating new kernel for connection'); + } + + let allowShutdown = true; + if (shutdownSelection === leaveRunning) { + traceInfo('Session will not be shutdown on close'); + allowShutdown = false; + } + sendTelemetryEvent(Telemetry.JupyterKernelAutoShutdown, undefined, { autoShutdownEnabled: allowShutdown }); + await this.configuration.updateSetting('dataScience.jupyterServerAllowKernelShutdown', allowShutdown, undefined, vscode.ConfigurationTarget.Workspace); + } } diff --git a/src/client/datascience/jupyter/jupyterExecution.ts b/src/client/datascience/jupyter/jupyterExecution.ts index 4bf699a9167a..6d4e308f1061 100644 --- a/src/client/datascience/jupyter/jupyterExecution.ts +++ b/src/client/datascience/jupyter/jupyterExecution.ts @@ -291,7 +291,7 @@ export class JupyterExecutionBase implements IJupyterExecution { } } else { // If we have a URI spec up a connection info for it - connection = this.createRemoteConnectionInfo(options.uri); + connection = JupyterExecutionBase.createRemoteConnectionInfo(options.uri, this.configuration); kernelSpec = undefined; } @@ -310,7 +310,7 @@ export class JupyterExecutionBase implements IJupyterExecution { return { connection, kernelSpec }; } - private createRemoteConnectionInfo = (uri: string): IConnection => { + public static createRemoteConnectionInfo = (uri: string, configuration: IConfigurationService): IConnection => { let url: URL; try { url = new URL(uri); @@ -318,7 +318,7 @@ export class JupyterExecutionBase implements IJupyterExecution { // This should already have been parsed when set, so just throw if it's not right here throw err; } - const settings = this.configuration.getSettings(); + const settings = configuration.getSettings(); const allowUnauthorized = settings.datascience.allowUnauthorizedRemoteConnection ? settings.datascience.allowUnauthorizedRemoteConnection : false; return { diff --git a/src/client/datascience/jupyter/jupyterSession.ts b/src/client/datascience/jupyter/jupyterSession.ts index 1e264333b6fd..395d19115450 100644 --- a/src/client/datascience/jupyter/jupyterSession.ts +++ b/src/client/datascience/jupyter/jupyterSession.ts @@ -14,7 +14,7 @@ import { JSONObject } from '@phosphor/coreutils'; import { Slot } from '@phosphor/signaling'; import { Agent as HttpsAgent } from 'https'; import * as uuid from 'uuid/v4'; -import { Event, EventEmitter, QuickPickItem } from 'vscode'; +import { Event, EventEmitter } from 'vscode'; import { CancellationToken } from 'vscode-jsonrpc'; import { Cancellation } from '../../common/cancellation'; @@ -33,11 +33,6 @@ import { import { JupyterKernelPromiseFailedError } from './jupyterKernelPromiseFailedError'; import { JupyterWaitForIdleError } from './jupyterWaitForIdleError'; import { createJupyterWebSocket } from './jupyterWebSocket'; -import { IApplicationShell } from '../../common/application/types'; - -interface KernelQuickPickItem extends QuickPickItem { - kernelId: string; -} export class JupyterSession implements IJupyterSession { private connInfo: IConnection | undefined; @@ -52,20 +47,21 @@ export class JupyterSession implements IJupyterSession { private connected: boolean = false; private jupyterPasswordConnect: IJupyterPasswordConnect; private oldSessions: Session.ISession[] = []; - private readonly appShell: IApplicationShell; - private allowShutdown: boolean = true; + private allowShutdown: boolean; + private desiredKernelId: string | undefined; constructor( - appShell: IApplicationShell, connInfo: IConnection, kernelSpec: IJupyterKernelSpec | undefined, - jupyterPasswordConnect: IJupyterPasswordConnect + jupyterPasswordConnect: IJupyterPasswordConnect, + desiredKernelId: string | undefined, + allowShutdown: boolean ) { - console.trace() - this.appShell = appShell; this.connInfo = connInfo; this.kernelSpec = kernelSpec; this.jupyterPasswordConnect = jupyterPasswordConnect; + this.allowShutdown = allowShutdown; + this.desiredKernelId = desiredKernelId; } public dispose(): Promise { @@ -234,39 +230,6 @@ export class JupyterSession implements IJupyterSession { // Create a temporary notebook for this session. this.notebookFiles.push(await contentsManager.newUntitled({ type: 'notebook' })); - const runningKernels: Kernel.IModel[] = await Kernel.listRunning(serverSettings); - const arr: KernelQuickPickItem[] = runningKernels.map(runningKernel => { - traceInfo(`Found running kernel ${runningKernel.id}, running since ${runningKernel.last_activity}`); - const localLastActivity = runningKernel.last_activity ? new Date(runningKernel.last_activity.toString()).toLocaleString() : '?'; - return { - label: `Kernel ${runningKernel.name} - ${runningKernel.id}`, - detail: `Running since ${localLastActivity}, ${runningKernel.connections} existing connections`, - kernelId: runningKernel.id - }; - }); - const startNewKernel = { - label: 'Start new kernel on Jupyter server', - picked: true, - kernelId: 'none' - }; - arr.unshift(startNewKernel); - - const kernelSelection = await this.appShell.showQuickPick(arr, { - ignoreFocusOut: true, - placeHolder: 'Select Jupyer Kernel' - }); - - const autoShutdown = { - label: 'Automatically shutdown Kernel when closed', - picked: true - }; - const leaveRunning = { - label: 'Leave Kernel running when closed', - picked: true - }; - const shutdownOptions = [autoShutdown, leaveRunning]; - const shutdownSelection = await this.appShell.showQuickPick(shutdownOptions, { ignoreFocusOut: true }); - const options: Session.IOptions = { path: this.notebookFiles[this.notebookFiles.length - 1].path, kernelName: this.kernelSpec ? this.kernelSpec.name : '', @@ -274,18 +237,13 @@ export class JupyterSession implements IJupyterSession { serverSettings: serverSettings }; - if (kernelSelection && kernelSelection !== startNewKernel) { - options.kernelId = kernelSelection.kernelId - traceInfo(`Connecting to existing kernel ${kernelSelection.kernelId}`); + if (this.desiredKernelId) { + options.kernelId = this.desiredKernelId; + traceInfo(`Connecting to existing kernel ${this.desiredKernelId}`); } else { traceInfo('Creating new kernel for connection'); } - if (shutdownSelection === leaveRunning) { - this.allowShutdown = false; - traceInfo('Session will not be shutdown on close'); - } - // Create our session options using this temporary notebook and our connection info return Cancellation.race(() => this.sessionManager!.startNew(options), cancelToken); diff --git a/src/client/datascience/jupyter/jupyterSessionManager.ts b/src/client/datascience/jupyter/jupyterSessionManager.ts index 025e345cc33c..719860d238d7 100644 --- a/src/client/datascience/jupyter/jupyterSessionManager.ts +++ b/src/client/datascience/jupyter/jupyterSessionManager.ts @@ -1,12 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. 'use strict'; -import { ServerConnection, SessionManager } from '@jupyterlab/services'; +import { ServerConnection, SessionManager, Kernel } from '@jupyterlab/services'; import { inject, injectable } from 'inversify'; import { CancellationToken } from 'vscode-jsonrpc'; import { IConnection, IJupyterKernelSpec, IJupyterPasswordConnect, IJupyterSession, IJupyterSessionManager } from '../types'; -import { IApplicationShell } from '../../common/application/types'; +import { IConfigurationService } from '../../common/types'; import { JupyterKernelSpec } from './jupyterKernelSpec'; import { JupyterSession } from './jupyterSession'; @@ -14,12 +14,15 @@ import { JupyterSession } from './jupyterSession'; export class JupyterSessionManager implements IJupyterSessionManager { constructor( @inject(IJupyterPasswordConnect) private jupyterPasswordConnect: IJupyterPasswordConnect, - @inject(IApplicationShell) private appShell: IApplicationShell + @inject(IConfigurationService) private readonly configurationService: IConfigurationService ) { } public async startNew(connInfo: IConnection, kernelSpec: IJupyterKernelSpec | undefined, cancelToken?: CancellationToken): Promise { // Create a new session and attempt to connect to it - const session = new JupyterSession(this.appShell, connInfo, kernelSpec, this.jupyterPasswordConnect); + const settings = this.configurationService.getSettings(); + const allowShutdown = settings.datascience.jupyterServerAllowKernelShutdown; + const kernelId = settings.datascience.jupyterServerKernelId; + const session = new JupyterSession(connInfo, kernelSpec, this.jupyterPasswordConnect, kernelId, allowShutdown); try { await session.connect(cancelToken); } finally { @@ -30,19 +33,15 @@ export class JupyterSessionManager implements IJupyterSessionManager { return session; } + public getActiveKernels(connection: IConnection): Promise { + return Kernel.listRunning(this.makeServerSettings(connection)); + } + public async getActiveKernelSpecs(connection: IConnection): Promise { let sessionManager: SessionManager | undefined; try { // Use our connection to create a session manager - const serverSettings = ServerConnection.makeSettings( - { - baseUrl: connection.baseUrl, - token: connection.token, - pageUrl: '', - // A web socket is required to allow token authentication (what if there is no token authentication?) - wsUrl: connection.baseUrl.replace('http', 'ws'), - init: { cache: 'no-store', credentials: 'same-origin' } - }); + const serverSettings = this.makeServerSettings(connection); sessionManager = new SessionManager({ serverSettings: serverSettings }); // Ask the session manager to refresh its list of kernel specs. @@ -67,4 +66,17 @@ export class JupyterSessionManager implements IJupyterSessionManager { } + + private makeServerSettings(connection: IConnection): ServerConnection.ISettings { + return ServerConnection.makeSettings( + { + baseUrl: connection.baseUrl, + token: connection.token, + pageUrl: '', + // A web socket is required to allow token authentication (what if there is no token authentication?) + wsUrl: connection.baseUrl.replace('http', 'ws'), + init: { cache: 'no-store', credentials: 'same-origin' } + }); + } + } diff --git a/src/client/datascience/jupyter/liveshare/guestJupyterSessionManager.ts b/src/client/datascience/jupyter/liveshare/guestJupyterSessionManager.ts index 517eaa655569..9f2361142150 100644 --- a/src/client/datascience/jupyter/liveshare/guestJupyterSessionManager.ts +++ b/src/client/datascience/jupyter/liveshare/guestJupyterSessionManager.ts @@ -3,20 +3,26 @@ 'use strict'; import { CancellationToken } from 'vscode-jsonrpc'; +import { Kernel } from '@jupyterlab/services'; import { noop } from '../../../../test/core'; import { IConnection, IJupyterKernelSpec, IJupyterSession, IJupyterSessionManager } from '../../types'; export class GuestJupyterSessionManager implements IJupyterSessionManager { - public constructor(private realSessionManager : IJupyterSessionManager) { + public constructor(private realSessionManager: IJupyterSessionManager) { noop(); } - public startNew(connInfo: IConnection, kernelSpec: IJupyterKernelSpec | undefined, cancelToken?: CancellationToken) : Promise { + public startNew(connInfo: IConnection, kernelSpec: IJupyterKernelSpec | undefined, cancelToken?: CancellationToken): Promise { return this.realSessionManager.startNew(connInfo, kernelSpec, cancelToken); } - public async getActiveKernelSpecs(_connection: IConnection) : Promise { + public async getActiveKernels(_connection: IConnection): Promise { + // Don't return any kernels in guest mode. They're only needed for the host side + return Promise.resolve([]); + } + + public async getActiveKernelSpecs(_connection: IConnection): Promise { // Don't return any kernel specs in guest mode. They're only needed for the host side return Promise.resolve([]); } diff --git a/src/client/datascience/types.ts b/src/client/datascience/types.ts index 14591afabafe..93207aa513b6 100644 --- a/src/client/datascience/types.ts +++ b/src/client/datascience/types.ts @@ -148,6 +148,7 @@ export const IJupyterSessionManager = Symbol('IJupyterSessionManager'); export interface IJupyterSessionManager { startNew(connInfo: IConnection, kernelSpec: IJupyterKernelSpec | undefined, cancelToken?: CancellationToken): Promise; getActiveKernelSpecs(connInfo: IConnection): Promise; + getActiveKernels(connInfo: IConnection): Promise; } export interface IJupyterKernelSpec extends IAsyncDisposable { diff --git a/src/client/telemetry/index.ts b/src/client/telemetry/index.ts index 9e70f61d7c9d..f3ca42733a03 100644 --- a/src/client/telemetry/index.ts +++ b/src/client/telemetry/index.ts @@ -1272,6 +1272,8 @@ export interface IEventNamePropertyMapping { [Telemetry.SelfCertsMessageClose]: never | undefined; [Telemetry.SelfCertsMessageEnabled]: never | undefined; [Telemetry.SelectJupyterURI]: never | undefined; + [Telemetry.JupyterKernelSpecified]: never | undefined; + [Telemetry.JupyterKernelAutoShutdown]: { autoShutdownEnabled: boolean }; [Telemetry.SetJupyterURIToLocal]: never | undefined; [Telemetry.SetJupyterURIToUserSpecified]: never | undefined; [Telemetry.ShiftEnterBannerShown]: never | undefined; diff --git a/src/datascience-ui/react-common/settingsReactSide.ts b/src/datascience-ui/react-common/settingsReactSide.ts index e7c81bff10c6..35f269cd73fa 100644 --- a/src/datascience-ui/react-common/settingsReactSide.ts +++ b/src/datascience-ui/react-common/settingsReactSide.ts @@ -36,6 +36,8 @@ function load() { jupyterLaunchTimeout: 10, jupyterLaunchRetries: 3, enabled: true, + jupyterServerAllowKernelShutdown: true, + jupyterServerKernelId: '', jupyterServerURI: 'local', notebookFileRoot: 'WORKSPACE', changeDirOnImportExport: true, diff --git a/src/test/datascience/color.test.ts b/src/test/datascience/color.test.ts index 1088dd868f46..6638a62d5616 100644 --- a/src/test/datascience/color.test.ts +++ b/src/test/datascience/color.test.ts @@ -53,6 +53,8 @@ suite('Theme colors', () => { jupyterLaunchTimeout: 20000, jupyterLaunchRetries: 3, enabled: true, + jupyterServerAllowKernelShutdown: true, + jupyterServerKernelId: '', jupyterServerURI: 'local', notebookFileRoot: 'WORKSPACE', changeDirOnImportExport: true, diff --git a/src/test/datascience/dataScienceIocContainer.ts b/src/test/datascience/dataScienceIocContainer.ts index 4aec10054698..02da59ba6710 100644 --- a/src/test/datascience/dataScienceIocContainer.ts +++ b/src/test/datascience/dataScienceIocContainer.ts @@ -407,6 +407,8 @@ export class DataScienceIocContainer extends UnitTestIocContainer { jupyterLaunchTimeout: 20000, jupyterLaunchRetries: 3, enabled: true, + jupyterServerAllowKernelShutdown: true, + jupyterServerKernelId: '', jupyterServerURI: 'local', notebookFileRoot: 'WORKSPACE', changeDirOnImportExport: true, diff --git a/src/test/datascience/editor-integration/codewatcher.unit.test.ts b/src/test/datascience/editor-integration/codewatcher.unit.test.ts index 716246c00b1c..c9efadb5f096 100644 --- a/src/test/datascience/editor-integration/codewatcher.unit.test.ts +++ b/src/test/datascience/editor-integration/codewatcher.unit.test.ts @@ -74,6 +74,8 @@ suite('DataScience Code Watcher Unit Tests', () => { jupyterLaunchTimeout: 20000, jupyterLaunchRetries: 3, enabled: true, + jupyterServerAllowKernelShutdown: true, + jupyterServerKernelId: '', jupyterServerURI: 'local', notebookFileRoot: 'WORKSPACE', changeDirOnImportExport: true, diff --git a/src/test/datascience/execution.unit.test.ts b/src/test/datascience/execution.unit.test.ts index c4c3d60738c3..b8e3ad409208 100644 --- a/src/test/datascience/execution.unit.test.ts +++ b/src/test/datascience/execution.unit.test.ts @@ -540,6 +540,8 @@ suite('Jupyter Execution', async () => { jupyterLaunchTimeout: 10, jupyterLaunchRetries: 3, enabled: true, + jupyterServerAllowKernelShutdown: true, + jupyterServerKernelId: '', jupyterServerURI: 'local', notebookFileRoot: 'WORKSPACE', changeDirOnImportExport: true, diff --git a/src/test/datascience/interactiveWindowCommandListener.unit.test.ts b/src/test/datascience/interactiveWindowCommandListener.unit.test.ts index 76653d3b7e34..9caa0a36faae 100644 --- a/src/test/datascience/interactiveWindowCommandListener.unit.test.ts +++ b/src/test/datascience/interactiveWindowCommandListener.unit.test.ts @@ -133,6 +133,8 @@ suite('Interactive window command listener', async () => { jupyterLaunchTimeout: 10, jupyterLaunchRetries: 3, enabled: true, + jupyterServerAllowKernelShutdown: true, + jupyterServerKernelId: '', jupyterServerURI: '', changeDirOnImportExport: true, notebookFileRoot: 'WORKSPACE', diff --git a/src/test/datascience/interactiveWindowTestHelpers.tsx b/src/test/datascience/interactiveWindowTestHelpers.tsx index c018277e6091..b95fa55c5e17 100644 --- a/src/test/datascience/interactiveWindowTestHelpers.tsx +++ b/src/test/datascience/interactiveWindowTestHelpers.tsx @@ -307,6 +307,8 @@ export function defaultDataScienceSettings(): IDataScienceSettings { jupyterLaunchTimeout: 10, jupyterLaunchRetries: 3, enabled: true, + jupyterServerAllowKernelShutdown: true, + jupyterServerKernelId: '', jupyterServerURI: 'local', notebookFileRoot: 'WORKSPACE', changeDirOnImportExport: true, diff --git a/src/test/datascience/mockJupyterManager.ts b/src/test/datascience/mockJupyterManager.ts index a8b967665899..c43a832dc575 100644 --- a/src/test/datascience/mockJupyterManager.ts +++ b/src/test/datascience/mockJupyterManager.ts @@ -33,6 +33,7 @@ import { noop, sleep } from '../core'; import { MockJupyterSession } from './mockJupyterSession'; import { MockProcessService } from './mockProcessService'; import { MockPythonService } from './mockPythonService'; +import { Kernel } from '@jupyterlab/services'; // tslint:disable:no-any no-http-string no-multiline-string max-func-body-length @@ -236,6 +237,10 @@ export class MockJupyterManager implements IJupyterSessionManager { } } + public getActiveKernels(_connection: IConnection): Promise { + return Promise.resolve([]); + } + public getActiveKernelSpecs(_connection: IConnection): Promise { return Promise.resolve([]); } diff --git a/src/test/datascience/reactHelpers.ts b/src/test/datascience/reactHelpers.ts index c4152c58dc6d..5d6bc7b4ef2b 100644 --- a/src/test/datascience/reactHelpers.ts +++ b/src/test/datascience/reactHelpers.ts @@ -349,6 +349,8 @@ export function setUpDomEnvironment() { jupyterLaunchTimeout: 10, jupyterLaunchRetries: 3, enabled: true, + jupyterServerAllowKernelShutdown: true, + jupyterServerKernelId: '', jupyterServerURI: 'local', notebookFileRoot: 'WORKSPACE', changeDirOnImportExport: true, From f915eb5e25d4847bdb37639995e3111ff2d8588b Mon Sep 17 00:00:00 2001 From: Kyle Kavanagh Date: Sat, 17 Aug 2019 21:23:43 -0500 Subject: [PATCH 3/7] Rename temp file created when initially connecting to jupyter to avoid nasty jupyter session behavior --- src/client/datascience/datascience.ts | 9 ++++++--- src/client/datascience/jupyter/jupyterSession.ts | 10 +++++++--- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/client/datascience/datascience.ts b/src/client/datascience/datascience.ts index e6e93001674b..dc630fb1957c 100644 --- a/src/client/datascience/datascience.ts +++ b/src/client/datascience/datascience.ts @@ -331,13 +331,16 @@ export class DataScience implements IDataScience { const shutdownOptions = [autoShutdown, leaveRunning]; const shutdownSelection = await this.appShell.showQuickPick(shutdownOptions, { ignoreFocusOut: true }); + let kernelUUID: string = ''; if (kernelSelection && kernelSelection !== startNewKernel) { - traceInfo(`Connecting to existing kernel ${kernelSelection.kernelId}`); + traceInfo(`Will connect to existing kernel ${kernelSelection.kernelId}`); + kernelUUID = kernelSelection.kernelId; sendTelemetryEvent(Telemetry.JupyterKernelSpecified); - await this.configuration.updateSetting('dataScience.jupyterServerKernelId', kernelSelection.kernelId, undefined, vscode.ConfigurationTarget.Workspace); + } else { - traceInfo('Creating new kernel for connection'); + traceInfo('Will create a new kernel for connection'); } + await this.configuration.updateSetting('dataScience.jupyterServerKernelId', kernelUUID, undefined, vscode.ConfigurationTarget.Workspace); let allowShutdown = true; if (shutdownSelection === leaveRunning) { diff --git a/src/client/datascience/jupyter/jupyterSession.ts b/src/client/datascience/jupyter/jupyterSession.ts index 395d19115450..bfaf2993bbc0 100644 --- a/src/client/datascience/jupyter/jupyterSession.ts +++ b/src/client/datascience/jupyter/jupyterSession.ts @@ -227,13 +227,17 @@ export class JupyterSession implements IJupyterSession { private async createSession(serverSettings: ServerConnection.ISettings, contentsManager: ContentsManager, cancelToken?: CancellationToken): Promise { - // Create a temporary notebook for this session. - this.notebookFiles.push(await contentsManager.newUntitled({ type: 'notebook' })); + // Create a temporary notebook for this session. Give it a unique name, so there is no possiblity of us reusing a session lingering the jupyter server + // (sessions in jupyter are indexed by path, regardless if the file exists of not and regardless of the session name, so deleting the file later doesn't save us) + // See https://github.com/jupyter/notebook/blob/5.7.x/notebook/services/sessions/handlers.py#L65 + const sessionUUID = uuid(); + const nbFile = await contentsManager.newUntitled({ type: 'notebook' }); + this.notebookFiles.push(await contentsManager.rename(nbFile.path, `.vscode-jupyter-session-${sessionUUID}.ipynb`)); const options: Session.IOptions = { path: this.notebookFiles[this.notebookFiles.length - 1].path, kernelName: this.kernelSpec ? this.kernelSpec.name : '', - name: uuid(), // This is crucial to distinguish this session from any other. + name: sessionUUID, // This is crucial to distinguish this session from any other. serverSettings: serverSettings }; From bad21401508880fa94700ec1dd0beafdad6f4aba Mon Sep 17 00:00:00 2001 From: "Kyle D. Kavanagh" Date: Sun, 18 Aug 2019 11:31:27 -0500 Subject: [PATCH 4/7] update news --- news/1 Enhancements/7014.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 news/1 Enhancements/7014.md diff --git a/news/1 Enhancements/7014.md b/news/1 Enhancements/7014.md new file mode 100644 index 000000000000..e0b01c98da37 --- /dev/null +++ b/news/1 Enhancements/7014.md @@ -0,0 +1 @@ +Add ability to reconnect to existing Jupyter kernel on remote jupyter hosts - @kdkavanagh From 17f8f619c9b0681d2b04babe6c919fe39e0a96a2 Mon Sep 17 00:00:00 2001 From: "Kyle D. Kavanagh" Date: Sun, 18 Aug 2019 11:32:53 -0500 Subject: [PATCH 5/7] fix typo --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b74aa90d38c0..526f8a0ac77a 100644 --- a/package.json +++ b/package.json @@ -1376,7 +1376,7 @@ "python.dataScience.jupyterServerAllowKernelShutdown": { "type": "boolean", "default": true, - "description": "Shutdown the Jupyter kernel when finishede", + "description": "Shutdown the Jupyter kernel when finished", "scope": "resource" }, "python.dataScience.notebookFileRoot": { From ea2ec275eb360371490b50b3989a811acd18b2a9 Mon Sep 17 00:00:00 2001 From: Kyle Kavanagh Date: Sun, 18 Aug 2019 11:41:07 -0500 Subject: [PATCH 6/7] Add localization --- package.nls.json | 4 ++++ src/client/common/utils/localize.ts | 4 ++++ src/client/datascience/datascience.ts | 8 ++++---- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/package.nls.json b/package.nls.json index 1d794158e855..a92fd9f2b97a 100644 --- a/package.nls.json +++ b/package.nls.json @@ -174,6 +174,10 @@ "DataScience.jupyterSelectURISpecifyURI": "Type in the URI to connect to a running Jupyter server", "DataScience.jupyterSelectURIPrompt": "Enter the URI of a Jupyter server", "DataScience.jupyterSelectURIInvalidURI": "Invalid URI specified", + "DataScience.jupyterServerReconnectKernelLocal": "Select Jupyer Kernel", + "DataScience.jupyterServerReconnectKernelStartNewLocal": "Start new kernel on Jupyter server", + "DataScience.jupyterServerKernelAutoShutdownLocal": "Automatically shutdown Kernel when closed", + "DataScience.jupyterServerKernelLeaveRunningLocal": "Leave Kernel running when closed", "DataScience.jupyterSelectPasswordPrompt": "Enter your notebook password", "DataScience.jupyterNotebookFailure": "Jupyter notebook failed to launch. \r\n{0}", "DataScience.jupyterNotebookConnectFailed": "Failed to connect to Jupyter notebook. \r\n{0}\r\n{1}", diff --git a/src/client/common/utils/localize.ts b/src/client/common/utils/localize.ts index cf28e8d0244f..8d6f8958d03d 100644 --- a/src/client/common/utils/localize.ts +++ b/src/client/common/utils/localize.ts @@ -176,6 +176,10 @@ export namespace DataScience { export const jupyterSelectURISpecifyURI = localize('DataScience.jupyterSelectURISpecifyURI', 'Type in the URI for the Jupyter server'); export const jupyterSelectURIPrompt = localize('DataScience.jupyterSelectURIPrompt', 'Enter the URI of a Jupyter server'); export const jupyterSelectURIInvalidURI = localize('DataScience.jupyterSelectURIInvalidURI', 'Invalid URI specified'); + export const jupyterServerReconnectKernelLocal = localize('DataScience.jupyterServerReconnectKernelLocal', 'Select Jupyer Kernel'); + export const jupyterServerReconnectKernelStartNewLocal = localize('DataScience.jupyterServerReconnectKernelStartNewLocal', 'Start new kernel on Jupyter server'); + export const jupyterServerKernelAutoShutdownLocal = localize('DataScience.jupyterServerKernelAutoShutdownLocal', 'Automatically shutdown Kernel when closed'); + export const jupyterServerKernelLeaveRunningLocal = localize('DataScience.jupyterServerKernelLeaveRunningLocal', 'Leave Kernel running when closed'); export const jupyterSelectPasswordPrompt = localize('DataScience.jupyterSelectPasswordPrompt', 'Enter your notebook password'); export const jupyterNotebookFailure = localize('DataScience.jupyterNotebookFailure', 'Jupyter notebook failed to launch. \r\n{0}'); export const jupyterNotebookConnectFailed = localize('DataScience.jupyterNotebookConnectFailed', 'Failed to connect to Jupyter notebook. \r\n{0}\r\n{1}'); diff --git a/src/client/datascience/datascience.ts b/src/client/datascience/datascience.ts index dc630fb1957c..1b941777a15c 100644 --- a/src/client/datascience/datascience.ts +++ b/src/client/datascience/datascience.ts @@ -309,7 +309,7 @@ export class DataScience implements IDataScience { }; }); const startNewKernel = { - label: 'Start new kernel on Jupyter server', + label: localize.DataScience.jupyterServerReconnectKernelStartNewLocal(), picked: true, kernelId: 'none' }; @@ -317,15 +317,15 @@ export class DataScience implements IDataScience { const kernelSelection = await this.appShell.showQuickPick(arr, { ignoreFocusOut: true, - placeHolder: 'Select Jupyer Kernel' + placeHolder: localize.DataScience.jupyterServerReconnectKernelLocal() }); const autoShutdown = { - label: 'Automatically shutdown Kernel when closed', + label: localize.DataScience.jupyterServerKernelAutoShutdownLocal(), picked: true }; const leaveRunning = { - label: 'Leave Kernel running when closed', + label: localize.DataScience.jupyterServerKernelLeaveRunningLocal(), picked: true }; const shutdownOptions = [autoShutdown, leaveRunning]; From 8059106c2bdc08512f7b450db3f75a163bb0e347 Mon Sep 17 00:00:00 2001 From: Kyle Kavanagh Date: Sun, 18 Aug 2019 15:45:14 -0500 Subject: [PATCH 7/7] Linting --- src/client/common/types.ts | 4 +- src/client/datascience/datascience.ts | 3 +- .../datascience/jupyter/jupyterExecution.ts | 50 +++++++++---------- .../datascience/jupyter/jupyterSession.ts | 2 - .../jupyter/jupyterSessionManager.ts | 5 +- src/test/datascience/mockJupyterManager.ts | 2 +- 6 files changed, 32 insertions(+), 34 deletions(-) diff --git a/src/client/common/types.ts b/src/client/common/types.ts index 0e223ca96efc..fa251867c7d0 100644 --- a/src/client/common/types.ts +++ b/src/client/common/types.ts @@ -303,8 +303,8 @@ export interface IDataScienceSettings { jupyterInterruptTimeout: number; jupyterLaunchTimeout: number; jupyterLaunchRetries: number; - jupyterServerAllowKernelShutdown: boolean, - jupyterServerKernelId: string, + jupyterServerAllowKernelShutdown: boolean; + jupyterServerKernelId: string; jupyterServerURI: string; notebookFileRoot: string; changeDirOnImportExport: boolean; diff --git a/src/client/datascience/datascience.ts b/src/client/datascience/datascience.ts index 1b941777a15c..feb42371b513 100644 --- a/src/client/datascience/datascience.ts +++ b/src/client/datascience/datascience.ts @@ -2,6 +2,7 @@ // Licensed under the MIT License. 'use strict'; import '../common/extensions'; + import { Kernel } from '@jupyterlab/services'; import { JSONObject } from '@phosphor/coreutils'; import { inject, injectable } from 'inversify'; @@ -11,7 +12,7 @@ import * as vscode from 'vscode'; import { IApplicationShell, ICommandManager, IDebugService, IDocumentManager, IWorkspaceService } from '../common/application/types'; import { PYTHON_ALLFILES, PYTHON_LANGUAGE } from '../common/constants'; import { ContextKey } from '../common/contextKey'; -import { traceInfo, traceError } from '../common/logger'; +import { traceError, traceInfo } from '../common/logger'; import { BANNER_NAME_DS_SURVEY, IConfigurationService, diff --git a/src/client/datascience/jupyter/jupyterExecution.ts b/src/client/datascience/jupyter/jupyterExecution.ts index 6d4e308f1061..a75de37758d0 100644 --- a/src/client/datascience/jupyter/jupyterExecution.ts +++ b/src/client/datascience/jupyter/jupyterExecution.ts @@ -49,6 +49,10 @@ enum ModuleExistsResult { export class JupyterExecutionBase implements IJupyterExecution { + public get sessionChanged(): Event { + return this.eventEmitter.event; + } + private processServicePromise: Promise; private commands: Record = {}; private jupyterPath: string | undefined; @@ -86,8 +90,27 @@ export class JupyterExecutionBase implements IJupyterExecution { } } - public get sessionChanged(): Event { - return this.eventEmitter.event; + public static createRemoteConnectionInfo = (uri: string, configuration: IConfigurationService): IConnection => { + let url: URL; + try { + url = new URL(uri); + } catch (err) { + // This should already have been parsed when set, so just throw if it's not right here + throw err; + } + const settings = configuration.getSettings(); + const allowUnauthorized = settings.datascience.allowUnauthorizedRemoteConnection ? settings.datascience.allowUnauthorizedRemoteConnection : false; + + return { + allowUnauthorized, + baseUrl: `${url.protocol}//${url.host}${url.pathname}`, + token: `${url.searchParams.get('token')}`, + hostName: url.hostname, + localLaunch: false, + localProcExitCode: undefined, + disconnected: (_l) => { return { dispose: noop }; }, + dispose: noop + }; } public dispose(): Promise { @@ -310,29 +333,6 @@ export class JupyterExecutionBase implements IJupyterExecution { return { connection, kernelSpec }; } - public static createRemoteConnectionInfo = (uri: string, configuration: IConfigurationService): IConnection => { - let url: URL; - try { - url = new URL(uri); - } catch (err) { - // This should already have been parsed when set, so just throw if it's not right here - throw err; - } - const settings = configuration.getSettings(); - const allowUnauthorized = settings.datascience.allowUnauthorizedRemoteConnection ? settings.datascience.allowUnauthorizedRemoteConnection : false; - - return { - allowUnauthorized, - baseUrl: `${url.protocol}//${url.host}${url.pathname}`, - token: `${url.searchParams.get('token')}`, - hostName: url.hostname, - localLaunch: false, - localProcExitCode: undefined, - disconnected: (_l) => { return { dispose: noop }; }, - dispose: noop - }; - } - // tslint:disable-next-line: max-func-body-length @captureTelemetry(Telemetry.StartJupyter) private async startNotebookServer(useDefaultConfig: boolean, cancelToken?: CancellationToken): Promise<{ connection: IConnection; kernelSpec: IJupyterKernelSpec | undefined }> { diff --git a/src/client/datascience/jupyter/jupyterSession.ts b/src/client/datascience/jupyter/jupyterSession.ts index bfaf2993bbc0..d1f65590aa4a 100644 --- a/src/client/datascience/jupyter/jupyterSession.ts +++ b/src/client/datascience/jupyter/jupyterSession.ts @@ -160,7 +160,6 @@ export class JupyterSession implements IJupyterSession { this.sessionManager = new SessionManager({ serverSettings: serverSettings }); this.contentsManager = new ContentsManager({ serverSettings: serverSettings }); - // Start a new session this.session = await this.createSession(serverSettings, this.contentsManager, cancelToken); @@ -224,7 +223,6 @@ export class JupyterSession implements IJupyterSession { throw exception; } - private async createSession(serverSettings: ServerConnection.ISettings, contentsManager: ContentsManager, cancelToken?: CancellationToken): Promise { // Create a temporary notebook for this session. Give it a unique name, so there is no possiblity of us reusing a session lingering the jupyter server diff --git a/src/client/datascience/jupyter/jupyterSessionManager.ts b/src/client/datascience/jupyter/jupyterSessionManager.ts index 719860d238d7..089a2b19935b 100644 --- a/src/client/datascience/jupyter/jupyterSessionManager.ts +++ b/src/client/datascience/jupyter/jupyterSessionManager.ts @@ -1,12 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. 'use strict'; -import { ServerConnection, SessionManager, Kernel } from '@jupyterlab/services'; +import { Kernel, ServerConnection, SessionManager } from '@jupyterlab/services'; import { inject, injectable } from 'inversify'; import { CancellationToken } from 'vscode-jsonrpc'; -import { IConnection, IJupyterKernelSpec, IJupyterPasswordConnect, IJupyterSession, IJupyterSessionManager } from '../types'; import { IConfigurationService } from '../../common/types'; +import { IConnection, IJupyterKernelSpec, IJupyterPasswordConnect, IJupyterSession, IJupyterSessionManager } from '../types'; import { JupyterKernelSpec } from './jupyterKernelSpec'; import { JupyterSession } from './jupyterSession'; @@ -66,7 +66,6 @@ export class JupyterSessionManager implements IJupyterSessionManager { } - private makeServerSettings(connection: IConnection): ServerConnection.ISettings { return ServerConnection.makeSettings( { diff --git a/src/test/datascience/mockJupyterManager.ts b/src/test/datascience/mockJupyterManager.ts index c43a832dc575..bf45dc4cd8ee 100644 --- a/src/test/datascience/mockJupyterManager.ts +++ b/src/test/datascience/mockJupyterManager.ts @@ -12,6 +12,7 @@ import * as uuid from 'uuid/v4'; import { EventEmitter } from 'vscode'; import { CancellationToken } from 'vscode-jsonrpc'; +import { Kernel } from '@jupyterlab/services'; import { Cancellation } from '../../client/common/cancellation'; import { ExecutionResult, IProcessServiceFactory, IPythonExecutionFactory, Output } from '../../client/common/process/types'; import { IAsyncDisposableRegistry, IConfigurationService } from '../../client/common/types'; @@ -33,7 +34,6 @@ import { noop, sleep } from '../core'; import { MockJupyterSession } from './mockJupyterSession'; import { MockProcessService } from './mockProcessService'; import { MockPythonService } from './mockPythonService'; -import { Kernel } from '@jupyterlab/services'; // tslint:disable:no-any no-http-string no-multiline-string max-func-body-length