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

Separate Jupyter session creator for raw and Jupyter #13439

Merged
merged 6 commits into from
May 2, 2023
Merged
Show file tree
Hide file tree
Changes from 5 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
14 changes: 6 additions & 8 deletions src/kernels/jupyter/finder/remoteKernelFinder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import { getKernelId } from '../../helpers';
import {
BaseKernelConnectionMetadata,
IJupyterKernelSpec,
IJupyterServerConnector,
IKernelProvider,
INotebookProvider,
INotebookProviderConnection,
IJupyterConnection,
isRemoteConnection,
LiveRemoteKernelConnectionMetadata,
RemoteKernelConnectionMetadata,
Expand Down Expand Up @@ -90,7 +90,7 @@ export class RemoteKernelFinder implements IRemoteKernelFinder, IDisposable {
readonly cacheKey: string,
private jupyterSessionManagerFactory: IJupyterSessionManagerFactory,
private extensionChecker: IPythonExtensionChecker,
private readonly notebookProvider: INotebookProvider,
private readonly jupyterServerConnector: IJupyterServerConnector,
private readonly globalState: Memento,
private readonly env: IApplicationEnvironment,
private readonly cachedRemoteKernelValidator: IJupyterRemoteCachedKernelValidator,
Expand Down Expand Up @@ -263,9 +263,9 @@ export class RemoteKernelFinder implements IRemoteKernelFinder, IDisposable {
private async getRemoteConnectionInfo(
cancelToken?: CancellationToken,
displayProgress: boolean = true
): Promise<INotebookProviderConnection | undefined> {
): Promise<IJupyterConnection | undefined> {
const ui = new DisplayOptions(!displayProgress);
return this.notebookProvider.connect({
return this.jupyterServerConnector.connect({
resource: undefined,
ui,
localJupyter: false,
Expand Down Expand Up @@ -326,9 +326,7 @@ export class RemoteKernelFinder implements IRemoteKernelFinder, IDisposable {
}

// Talk to the remote server to determine sessions
public async listKernelsFromConnection(
connInfo: INotebookProviderConnection
): Promise<RemoteKernelConnectionMetadata[]> {
public async listKernelsFromConnection(connInfo: IJupyterConnection): Promise<RemoteKernelConnectionMetadata[]> {
// Get a jupyter session manager to talk to
let sessionManager: IJupyterSessionManager | undefined;
// This should only be used when doing remote.
Expand Down
8 changes: 4 additions & 4 deletions src/kernels/jupyter/finder/remoteKernelFinder.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { JupyterSessionManagerFactory } from '../session/jupyterSessionManagerFa
import { ActiveKernelIdList } from '../connection/preferredRemoteKernelIdProvider';
import { IJupyterKernel, IJupyterRemoteCachedKernelValidator, IJupyterSessionManager } from '../types';
import { KernelFinder } from '../../kernelFinder';
import { NotebookProvider } from '../launcher/notebookProvider';
import { JupyterServerConnector } from '../launcher/jupyterServerConnector';
import { PythonExtensionChecker } from '../../../platform/api/pythonApi';
import { IFileSystemNode } from '../../../platform/common/platform/types.node';
import { JupyterServerUriStorage } from '../connection/serverUriStorage';
Expand Down Expand Up @@ -124,8 +124,8 @@ suite(`Remote Kernel Finder`, () => {
when(jupyterSessionManagerFactory.create(anything())).thenResolve(instance(jupyterSessionManager));
const extensionChecker = mock(PythonExtensionChecker);
when(extensionChecker.isPythonExtensionInstalled).thenReturn(true);
const notebookProvider = mock(NotebookProvider);
when(notebookProvider.connect(anything())).thenResolve(connInfo);
const serverConnector = mock(JupyterServerConnector);
when(serverConnector.connect(anything())).thenResolve(connInfo);
fs = mock(FileSystem);
when(fs.delete(anything())).thenResolve();
when(fs.exists(anything())).thenResolve(true);
Expand Down Expand Up @@ -158,7 +158,7 @@ suite(`Remote Kernel Finder`, () => {
RemoteKernelSpecsCacheKey,
instance(jupyterSessionManagerFactory),
instance(extensionChecker),
instance(notebookProvider),
instance(serverConnector),
instance(memento),
instance(env),
instance(cachedRemoteKernelValidator),
Expand Down
10 changes: 5 additions & 5 deletions src/kernels/jupyter/finder/remoteKernelFinderController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import { injectable, inject, named } from 'inversify';
import { Disposable, Memento } from 'vscode';
import { IKernelFinder, IKernelProvider, INotebookProvider } from '../../types';
import { IKernelFinder, IKernelProvider, IJupyterServerConnector } from '../../types';
import { GLOBAL_MEMENTO, IDisposableRegistry, IExtensions, IMemento } from '../../../platform/common/types';
import {
IJupyterSessionManagerFactory,
Expand Down Expand Up @@ -34,7 +34,7 @@ class MultiServerStrategy implements IRemoteKernelFinderRegistrationStrategy {
constructor(
private jupyterSessionManagerFactory: IJupyterSessionManagerFactory,
private extensionChecker: IPythonExtensionChecker,
private readonly notebookProvider: INotebookProvider,
private readonly jupyterServerConnector: IJupyterServerConnector,
private readonly serverUriStorage: IJupyterServerUriStorage,
private readonly globalState: Memento,
private readonly env: IApplicationEnvironment,
Expand Down Expand Up @@ -75,7 +75,7 @@ class MultiServerStrategy implements IRemoteKernelFinderRegistrationStrategy {
`${RemoteKernelSpecsCacheKey}-${serverUri.serverId}`,
this.jupyterSessionManagerFactory,
this.extensionChecker,
this.notebookProvider,
this.jupyterServerConnector,
this.globalState,
this.env,
this.cachedRemoteKernelValidator,
Expand Down Expand Up @@ -116,7 +116,7 @@ export class RemoteKernelFinderController implements IExtensionSyncActivationSer
@inject(IJupyterSessionManagerFactory)
private readonly jupyterSessionManagerFactory: IJupyterSessionManagerFactory,
@inject(IPythonExtensionChecker) private readonly extensionChecker: IPythonExtensionChecker,
@inject(INotebookProvider) private readonly notebookProvider: INotebookProvider,
@inject(IJupyterServerConnector) private readonly jupyterServerConnector: IJupyterServerConnector,
@inject(IJupyterServerUriStorage) private readonly serverUriStorage: IJupyterServerUriStorage,
@inject(IMemento) @named(GLOBAL_MEMENTO) private readonly globalState: Memento,
@inject(IApplicationEnvironment) private readonly env: IApplicationEnvironment,
Expand All @@ -129,7 +129,7 @@ export class RemoteKernelFinderController implements IExtensionSyncActivationSer
this._strategy = new MultiServerStrategy(
this.jupyterSessionManagerFactory,
this.extensionChecker,
this.notebookProvider,
this.jupyterServerConnector,
this.serverUriStorage,
this.globalState,
this.env,
Expand Down
47 changes: 47 additions & 0 deletions src/kernels/jupyter/launcher/jupyterServerConnector.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { inject, injectable, optional } from 'inversify';
import { IPythonExtensionChecker } from '../../../platform/api/types';
import { ConnectNotebookProviderOptions, IJupyterConnection, IJupyterServerConnector } from '../../types';
import { DisplayOptions } from '../../displayOptions';
import { IRawKernelConnectionSessionCreator } from '../../raw/types';
import { IJupyterNotebookProvider } from '../types';
import { PythonExtensionNotInstalledError } from '../../../platform/errors/pythonExtNotInstalledError';

@injectable()
export class JupyterServerConnector implements IJupyterServerConnector {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

These are not the final names and final classes, the primary goal is to break down larger components into smaller ones , this way re-factoring this would be simpler and its easier
Right now there's a lot of inheritance and coupling

private readonly startupUi = new DisplayOptions(true);
constructor(
@inject(IRawKernelConnectionSessionCreator)
@optional()
private readonly rawSessionCreator: IRawKernelConnectionSessionCreator | undefined,
@inject(IJupyterNotebookProvider)
private readonly jupyterNotebookProvider: IJupyterNotebookProvider,
@inject(IPythonExtensionChecker) private readonly extensionChecker: IPythonExtensionChecker
) {}

public async connect(options: ConnectNotebookProviderOptions): Promise<IJupyterConnection> {
if (!options.ui.disableUI) {
this.startupUi.disableUI = false;
}
const handler = options.ui.onDidChangeDisableUI(() => {
if (!options.ui.disableUI) {
this.startupUi.disableUI = false;
handler.dispose();
}
});
options.ui = this.startupUi;
if (this.rawSessionCreator?.isSupported && options.localJupyter) {
throw new Error('Connect method should not be invoked for local Connections when Raw is supported');
} else if (this.extensionChecker.isPythonExtensionInstalled || !options.localJupyter) {
return this.jupyterNotebookProvider.connect(options).finally(() => handler.dispose());
} else {
handler.dispose();
if (!this.startupUi.disableUI && options.localJupyter) {
await this.extensionChecker.showPythonExtensionInstallRequiredPrompt();
}
throw new PythonExtensionNotInstalledError();
}
}
}
60 changes: 60 additions & 0 deletions src/kernels/jupyter/launcher/kernelConnectionSessionCreator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { inject, injectable, optional } from 'inversify';
import {
GetServerOptions,
IKernelConnectionSession,
IKernelConnectionSessionCreator,
isLocalConnection,
NotebookCreationOptions
} from '../../types';
import { Cancellation } from '../../../platform/common/cancellation';
import { IRawKernelConnectionSessionCreator } from '../../raw/types';
import { IJupyterNotebookProvider } from '../types';

/**
* Generic class for connecting to a server. Probably could be renamed as it doesn't provide notebooks, but rather connections.
*/
@injectable()
export class KernelConnectionSessionCreator implements IKernelConnectionSessionCreator {
constructor(
@inject(IRawKernelConnectionSessionCreator)
@optional()
private readonly rawKernelSessionCreator: IRawKernelConnectionSessionCreator | undefined,
@inject(IJupyterNotebookProvider)
private readonly jupyterNotebookProvider: IJupyterNotebookProvider
) {}

public async create(options: NotebookCreationOptions): Promise<IKernelConnectionSession> {
const kernelConnection = options.kernelConnection;
const isLocal = isLocalConnection(kernelConnection);

if (this.rawKernelSessionCreator?.isSupported && isLocal) {
return this.rawKernelSessionCreator.create(
options.resource,
options.kernelConnection,
options.ui,
options.token
);
}
const serverOptions: GetServerOptions = isLocal
? {
resource: options.resource,
token: options.token,
ui: options.ui,
localJupyter: true
}
: {
resource: options.resource,
token: options.token,
ui: options.ui,
localJupyter: false,
serverId: kernelConnection.serverId
};
await this.jupyterNotebookProvider.connect(serverOptions);
Cancellation.throwIfCanceled(options.token);

return this.jupyterNotebookProvider.createNotebook(options);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,39 +6,38 @@ import { anything, instance, mock, when } from 'ts-mockito';
import * as vscode from 'vscode';
import { PythonExtensionChecker } from '../../../platform/api/pythonApi';
import { IJupyterKernelConnectionSession, KernelConnectionMetadata } from '../../types';
import { NotebookProvider } from './notebookProvider';
import { DisplayOptions } from '../../displayOptions';
import { IJupyterNotebookProvider } from '../types';
import { IRawNotebookProvider } from '../../raw/types';
import { IRawKernelConnectionSessionCreator } from '../../raw/types';
import { IDisposable } from '../../../platform/common/types';
import { disposeAllDisposables } from '../../../platform/common/helpers';
import { KernelConnectionSessionCreator } from './kernelConnectionSessionCreator';

function Uri(filename: string): vscode.Uri {
return vscode.Uri.file(filename);
}

/* eslint-disable */
suite('NotebookProvider', () => {
let notebookProvider: NotebookProvider;
let kernelConnectionSessionCreator: KernelConnectionSessionCreator;
let jupyterNotebookProvider: IJupyterNotebookProvider;
let rawNotebookProvider: IRawNotebookProvider;
let rawKernelSessionCreator: IRawKernelConnectionSessionCreator;
let cancelToken: vscode.CancellationTokenSource;
const disposables: IDisposable[] = [];
setup(() => {
jupyterNotebookProvider = mock<IJupyterNotebookProvider>();
rawNotebookProvider = mock<IRawNotebookProvider>();
rawKernelSessionCreator = mock<IRawKernelConnectionSessionCreator>();
cancelToken = new vscode.CancellationTokenSource();
disposables.push(cancelToken);
when(rawNotebookProvider.isSupported).thenReturn(false);
when(rawKernelSessionCreator.isSupported).thenReturn(false);
const extensionChecker = mock(PythonExtensionChecker);
when(extensionChecker.isPythonExtensionInstalled).thenReturn(true);
const onDidChangeEvent = new vscode.EventEmitter<void>();
disposables.push(onDidChangeEvent);

notebookProvider = new NotebookProvider(
instance(rawNotebookProvider),
instance(jupyterNotebookProvider),
instance(extensionChecker)
kernelConnectionSessionCreator = new KernelConnectionSessionCreator(
instance(rawKernelSessionCreator),
instance(jupyterNotebookProvider)
);
});
teardown(() => disposeAllDisposables(disposables));
Expand All @@ -50,7 +49,7 @@ suite('NotebookProvider', () => {
const doc = mock<vscode.NotebookDocument>();
when(doc.uri).thenReturn(Uri('C:\\\\foo.py'));

const session = await notebookProvider.create({
const session = await kernelConnectionSessionCreator.create({
resource: Uri('C:\\\\foo.py'),
kernelConnection: instance(mock<KernelConnectionMetadata>()),
ui: new DisplayOptions(false),
Expand All @@ -68,7 +67,7 @@ suite('NotebookProvider', () => {
const doc = mock<vscode.NotebookDocument>();
when(doc.uri).thenReturn(Uri('C:\\\\foo.py'));

const session = await notebookProvider.create({
const session = await kernelConnectionSessionCreator.create({
resource: Uri('C:\\\\foo.py'),
kernelConnection: instance(mock<KernelConnectionMetadata>()),
ui: new DisplayOptions(false),
Expand All @@ -77,7 +76,7 @@ suite('NotebookProvider', () => {
});
expect(session).to.not.equal(undefined, 'Server should return a notebook');

const session2 = await notebookProvider.create({
const session2 = await kernelConnectionSessionCreator.create({
resource: Uri('C:\\\\foo.py'),
kernelConnection: instance(mock<KernelConnectionMetadata>()),
ui: new DisplayOptions(false),
Expand Down
95 changes: 0 additions & 95 deletions src/kernels/jupyter/launcher/notebookProvider.ts

This file was deleted.

Loading