Skip to content

Support jupyter output in the remote scenario too #10241

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

Merged
merged 2 commits into from
Feb 21, 2020
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/2 Fixes/9177.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Jupyter output tab was not showing anything when connecting to a remote server.
5 changes: 4 additions & 1 deletion package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -442,5 +442,8 @@
"DataScience.gettingListOfKernelSpecs": "Fetching Kernel specs",
"DataScience.startingJupyterNotebook": "Starting Jupyter Notebook",
"DataScience.registeringKernel": "Registering Kernel",
"DataScience.trimmedOutput": "Output was trimmed for performance reasons.\nTo see the full output set the setting \"python.dataScience.textOutputLimit\" to 0."
"DataScience.trimmedOutput": "Output was trimmed for performance reasons.\nTo see the full output set the setting \"python.dataScience.textOutputLimit\" to 0.",
"DataScience.connectingToJupyterUri" : "Connecting to Jupyter server at {0}",
"DataScience.createdNewNotebook" : "{0}: Creating new notebook ",
"DataScience.createdNewKernel" : "{0}: Kernel started: {1}"
}
8 changes: 8 additions & 0 deletions src/client/common/utils/localize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -790,6 +790,14 @@ export namespace DataScience {
'DataScience.jupyterCommandLinePrompt',
'Enter your custom command line for Jupyter'
);

export const connectingToJupyterUri = localize(
'DataScience.connectingToJupyterUri',
'Connecting to Jupyter server at {0}'
);
export const createdNewNotebook = localize('DataScience.createdNewNotebook', '{0}: Creating new notebook ');

export const createdNewKernel = localize('DataScience.createdNewKernel', '{0}: Kernel started: {1}');
}

export namespace DebugConfigStrings {
Expand Down
26 changes: 23 additions & 3 deletions src/client/datascience/jupyter/jupyterServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@ import { CancellationToken } from 'vscode-jsonrpc';
import { ILiveShareApi } from '../../common/application/types';
import '../../common/extensions';
import { traceError, traceInfo } from '../../common/logger';
import { IAsyncDisposableRegistry, IConfigurationService, IDisposableRegistry, Resource } from '../../common/types';
import {
IAsyncDisposableRegistry,
IConfigurationService,
IDisposableRegistry,
IOutputChannel,
Resource
} from '../../common/types';
import { createDeferred, Deferred } from '../../common/utils/async';
import * as localize from '../../common/utils/localize';
import { noop } from '../../common/utils/misc';
Expand Down Expand Up @@ -42,7 +48,8 @@ export class JupyterServerBase implements INotebookServer {
private disposableRegistry: IDisposableRegistry,
protected readonly configService: IConfigurationService,
private sessionManagerFactory: IJupyterSessionManagerFactory,
private loggers: INotebookExecutionLogger[]
private loggers: INotebookExecutionLogger[],
private jupyterOutputChannel: IOutputChannel
) {
this.asyncRegistry.push(this);
}
Expand All @@ -67,6 +74,9 @@ export class JupyterServerBase implements INotebookServer {
});
}

// Indicate we have a new session on the output channel
this.logRemoteOutput(localize.DataScience.connectingToJupyterUri().format(launchInfo.connectionInfo.baseUrl));

// Create our session manager
this.sessionManager = await this.sessionManagerFactory.create(launchInfo.connectionInfo);
// Try creating a session just to ensure we're connected. Callers of this function check to make sure jupyter
Expand Down Expand Up @@ -104,7 +114,11 @@ export class JupyterServerBase implements INotebookServer {
this.loggers,
notebookMetadata,
cancelToken
);
).then(r => {
const baseUrl = this.launchInfo?.connectionInfo.baseUrl || '';
this.logRemoteOutput(localize.DataScience.createdNewNotebook().format(baseUrl));
return r;
});
}

public async shutdown(): Promise<void> {
Expand Down Expand Up @@ -217,4 +231,10 @@ export class JupyterServerBase implements INotebookServer {
this.launchInfo.kernelSpec = undefined;
}
}

private logRemoteOutput(output: string) {
if (this.launchInfo && !this.launchInfo.connectionInfo.localLaunch) {
this.jupyterOutputChannel.appendLine(output);
}
}
}
20 changes: 15 additions & 5 deletions src/client/datascience/jupyter/jupyterServerWrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,23 @@
// Licensed under the MIT License.
'use strict';
import { nbformat } from '@jupyterlab/coreutils';
import { inject, injectable, multiInject, optional } from 'inversify';
import { inject, injectable, multiInject, named, optional } from 'inversify';
import * as uuid from 'uuid/v4';
import { Uri } from 'vscode';
import { CancellationToken } from 'vscode-jsonrpc';
import * as vsls from 'vsls/vscode';
import { IApplicationShell, ILiveShareApi, IWorkspaceService } from '../../common/application/types';
import '../../common/extensions';
import { IFileSystem } from '../../common/platform/types';
import { IAsyncDisposableRegistry, IConfigurationService, IDisposableRegistry, Resource } from '../../common/types';
import {
IAsyncDisposableRegistry,
IConfigurationService,
IDisposableRegistry,
IOutputChannel,
Resource
} from '../../common/types';
import { IInterpreterService } from '../../interpreter/contracts';
import { JUPYTER_OUTPUT_CHANNEL } from '../constants';
import {
IConnection,
IDataScience,
Expand Down Expand Up @@ -43,7 +50,8 @@ type JupyterServerClassType = {
appShell: IApplicationShell,
fs: IFileSystem,
kernelSelector: KernelSelector,
interpreterService: IInterpreterService
interpreterService: IInterpreterService,
outputChannel: IOutputChannel
): IJupyterServerInterface;
};
// tslint:enable:callable-types
Expand All @@ -69,7 +77,8 @@ export class JupyterServerWrapper implements INotebookServer, ILiveShareHasRole
@inject(IApplicationShell) appShell: IApplicationShell,
@inject(IFileSystem) fs: IFileSystem,
@inject(IInterpreterService) interpreterService: IInterpreterService,
@inject(KernelSelector) kernelSelector: KernelSelector
@inject(KernelSelector) kernelSelector: KernelSelector,
@inject(IOutputChannel) @named(JUPYTER_OUTPUT_CHANNEL) jupyterOutput: IOutputChannel
) {
// The server factory will create the appropriate HostJupyterServer or GuestJupyterServer based on
// the liveshare state.
Expand All @@ -88,7 +97,8 @@ export class JupyterServerWrapper implements INotebookServer, ILiveShareHasRole
appShell,
fs,
kernelSelector,
interpreterService
interpreterService,
jupyterOutput
);
}

Expand Down
20 changes: 18 additions & 2 deletions src/client/datascience/jupyter/jupyterSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { ServerStatus } from '../../../datascience-ui/interactive-common/mainSta
import { Cancellation } from '../../common/cancellation';
import { isTestExecution } from '../../common/constants';
import { traceInfo, traceWarning } from '../../common/logger';
import { IOutputChannel } from '../../common/types';
import { sleep, waitForPromise } from '../../common/utils/async';
import * as localize from '../../common/utils/localize';
import { noop } from '../../common/utils/misc';
Expand Down Expand Up @@ -69,7 +70,8 @@ export class JupyterSession implements IJupyterSession {
private kernelSpec: IJupyterKernelSpec | LiveKernelModel | undefined,
private sessionManager: SessionManager,
private contentsManager: ContentsManager,
private readonly kernelSelector: KernelSelector
private readonly kernelSelector: KernelSelector,
private readonly outputChannel: IOutputChannel
) {
this.statusHandler = this.onStatusChanged.bind(this);
}
Expand Down Expand Up @@ -386,11 +388,25 @@ export class JupyterSession implements IJupyterSession {
};

return Cancellation.race(
() => this.sessionManager!.startNew(options).catch(ex => Promise.reject(new JupyterSessionStartError(ex))),
() =>
this.sessionManager!.startNew(options)
.then(s => {
this.logRemoteOutput(
localize.DataScience.createdNewKernel().format(this.connInfo.baseUrl, s.kernel.id)

Choose a reason for hiding this comment

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

Isn't this incorrect, we're starting a new session here, not creating a new kernel!

Copy link
Author

Choose a reason for hiding this comment

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

Those are the same as far as the output is concerned. That's the creation of a kernel in the output from jupyter

);
return s;
})
.catch(ex => Promise.reject(new JupyterSessionStartError(ex))),
cancelToken
);
}

private logRemoteOutput(output: string) {
if (this.connInfo && !this.connInfo.localLaunch) {
this.outputChannel.appendLine(output);
}
}

private async waitForKernelPromise(
kernelPromise: Promise<void>,
timeout: number,
Expand Down
8 changes: 5 additions & 3 deletions src/client/datascience/jupyter/jupyterSessionManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Agent as HttpsAgent } from 'https';
import { CancellationToken } from 'vscode-jsonrpc';

import { traceInfo } from '../../common/logger';
import { IConfigurationService } from '../../common/types';
import { IConfigurationService, IOutputChannel } from '../../common/types';
import * as localize from '../../common/utils/localize';
import {
IConnection,
Expand All @@ -33,7 +33,8 @@ export class JupyterSessionManager implements IJupyterSessionManager {
private jupyterPasswordConnect: IJupyterPasswordConnect,
private config: IConfigurationService,
private failOnPassword: boolean | undefined,
private kernelSelector: KernelSelector
private kernelSelector: KernelSelector,
private outputChannel: IOutputChannel
) {}

public async dispose() {
Expand Down Expand Up @@ -115,7 +116,8 @@ export class JupyterSessionManager implements IJupyterSessionManager {
kernelSpec,
this.sessionManager,
this.contentsManager,
this.kernelSelector
this.kernelSelector,
this.outputChannel
);
try {
await session.connect(cancelToken);
Expand Down
11 changes: 7 additions & 4 deletions src/client/datascience/jupyter/jupyterSessionManagerFactory.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
'use strict';
import { inject, injectable } from 'inversify';
import { inject, injectable, named } from 'inversify';

import { IConfigurationService } from '../../common/types';
import { IConfigurationService, IOutputChannel } from '../../common/types';
import { JUPYTER_OUTPUT_CHANNEL } from '../constants';
import { IConnection, IJupyterPasswordConnect, IJupyterSessionManager, IJupyterSessionManagerFactory } from '../types';
import { JupyterSessionManager } from './jupyterSessionManager';
import { KernelSelector } from './kernels/kernelSelector';
Expand All @@ -13,7 +14,8 @@ export class JupyterSessionManagerFactory implements IJupyterSessionManagerFacto
constructor(
@inject(IJupyterPasswordConnect) private jupyterPasswordConnect: IJupyterPasswordConnect,
@inject(IConfigurationService) private config: IConfigurationService,
@inject(KernelSelector) private kernelSelector: KernelSelector
@inject(KernelSelector) private kernelSelector: KernelSelector,
@inject(IOutputChannel) @named(JUPYTER_OUTPUT_CHANNEL) private jupyterOutput: IOutputChannel
) {}

/**
Expand All @@ -26,7 +28,8 @@ export class JupyterSessionManagerFactory implements IJupyterSessionManagerFacto
this.jupyterPasswordConnect,
this.config,
failOnPassword,
this.kernelSelector
this.kernelSelector,
this.jupyterOutput
);
await result.initialize(connInfo);
return result;
Expand Down
13 changes: 10 additions & 3 deletions src/client/datascience/jupyter/liveshare/hostJupyterServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,13 @@ import { nbformat } from '@jupyterlab/coreutils';
import { IApplicationShell, ILiveShareApi, IWorkspaceService } from '../../../common/application/types';
import { traceInfo } from '../../../common/logger';
import { IFileSystem } from '../../../common/platform/types';
import { IAsyncDisposableRegistry, IConfigurationService, IDisposableRegistry, Resource } from '../../../common/types';
import {
IAsyncDisposableRegistry,
IConfigurationService,
IDisposableRegistry,
IOutputChannel,
Resource
} from '../../../common/types';
import * as localize from '../../../common/utils/localize';
import { IInterpreterService } from '../../../interpreter/contracts';
import { Identifiers, LiveShare, LiveShareCommands, RegExpValues } from '../../constants';
Expand Down Expand Up @@ -52,9 +58,10 @@ export class HostJupyterServer extends LiveShareParticipantHost(JupyterServerBas
private appService: IApplicationShell,
private fs: IFileSystem,
private readonly kernelSelector: KernelSelector,
private readonly interpreterService: IInterpreterService
private readonly interpreterService: IInterpreterService,
outputChannel: IOutputChannel
) {
super(liveShare, asyncRegistry, disposableRegistry, configService, sessionManager, loggers);
super(liveShare, asyncRegistry, disposableRegistry, configService, sessionManager, loggers, outputChannel);
}

public async dispose(): Promise<void> {
Expand Down
5 changes: 4 additions & 1 deletion src/test/datascience/jupyter/jupyterSession.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { JupyterSession } from '../../../client/datascience/jupyter/jupyterSessi
import { KernelSelector } from '../../../client/datascience/jupyter/kernels/kernelSelector';
import { LiveKernelModel } from '../../../client/datascience/jupyter/kernels/types';
import { IConnection, IJupyterKernelSpec } from '../../../client/datascience/types';
import { MockOutputChannel } from '../../mockClasses';

// tslint:disable: max-func-body-length
suite('Data Science - JupyterSession', () => {
Expand Down Expand Up @@ -63,6 +64,7 @@ suite('Data Science - JupyterSession', () => {
kernelChangedSignal = mock(Signal);
when(session.statusChanged).thenReturn(instance(statusChangedSignal));
when(session.kernelChanged).thenReturn(instance(kernelChangedSignal));
const channel = new MockOutputChannel('JUPYTER');
// tslint:disable-next-line: no-any
(instance(session) as any).then = undefined;
sessionManager = mock(SessionManager);
Expand All @@ -73,7 +75,8 @@ suite('Data Science - JupyterSession', () => {
kernelSpec.object,
instance(sessionManager),
instance(contentsManager),
instance(kernelSelector)
instance(kernelSelector),
channel
);
});

Expand Down