Split up NotebookProvider into separate providers for handling file serialization and cell execution. (#17176)

This commit is contained in:
Cory Rivera
2021-09-29 16:15:28 -07:00
committed by GitHub
parent dfc2635aa7
commit 14904bb671
51 changed files with 1426 additions and 971 deletions

View File

@@ -19,7 +19,6 @@ import { IPrompter, IQuestion, QuestionTypes } from '../prompts/question';
import { AppContext } from '../common/appContext';
import { LocalJupyterServerManager, ServerInstanceFactory } from './jupyterServerManager';
import { NotebookCompletionItemProvider } from '../intellisense/completionItemProvider';
import { JupyterNotebookProvider } from './jupyterNotebookProvider';
import { ConfigurePythonWizard } from '../dialog/configurePython/configurePythonWizard';
import CodeAdapter from '../prompts/adapter';
import { ManagePackagesDialog } from '../dialog/managePackages/managePackagesDialog';
@@ -28,6 +27,7 @@ import { LocalPipPackageManageProvider } from './localPipPackageManageProvider';
import { LocalCondaPackageManageProvider } from './localCondaPackageManageProvider';
import { ManagePackagesDialogModel, ManagePackageDialogOptions } from '../dialog/managePackages/managePackagesDialogModel';
import { PyPiClient } from './pypiClient';
import { JupyterExecuteProvider } from './jupyterExecuteProvider';
let untitledCounter = 0;
@@ -37,7 +37,7 @@ export class JupyterController {
private _packageManageProviders = new Map<string, IPackageManageProvider>();
private prompter: IPrompter;
private _notebookProvider: JupyterNotebookProvider;
private _executeProvider: JupyterExecuteProvider;
constructor(private appContext: AppContext) {
this.prompter = new CodeAdapter();
@@ -47,8 +47,8 @@ export class JupyterController {
return this.appContext && this.appContext.extensionContext;
}
public get notebookProvider(): JupyterNotebookProvider {
return this._notebookProvider;
public get executeProvider(): JupyterExecuteProvider {
return this._executeProvider;
}
// PUBLIC METHODS //////////////////////////////////////////////////////
@@ -79,21 +79,19 @@ export class JupyterController {
let supportedFileFilter: vscode.DocumentFilter[] = [
{ scheme: 'untitled', language: '*' }
];
this.registerNotebookProvider();
this.extensionContext.subscriptions.push(vscode.languages.registerCompletionItemProvider(supportedFileFilter, new NotebookCompletionItemProvider(this._notebookProvider), '.'));
this.registerDefaultPackageManageProviders();
return true;
}
private registerNotebookProvider(): void {
this._notebookProvider = new JupyterNotebookProvider((documentUri: vscode.Uri) => new LocalJupyterServerManager({
this._executeProvider = new JupyterExecuteProvider((documentUri: vscode.Uri) => new LocalJupyterServerManager({
documentPath: documentUri.fsPath,
jupyterInstallation: this._jupyterInstallation,
extensionContext: this.extensionContext,
factory: this._serverInstanceFactory
}));
azdata.nb.registerNotebookProvider(this._notebookProvider);
azdata.nb.registerExecuteProvider(this._executeProvider);
this.extensionContext.subscriptions.push(vscode.languages.registerCompletionItemProvider(supportedFileFilter, new NotebookCompletionItemProvider(this._executeProvider), '.'));
this.registerDefaultPackageManageProviders();
return true;
}
private saveProfileAndCreateNotebook(profile: azdata.IConnectionProfile): Promise<void> {

View File

@@ -10,7 +10,7 @@ import { ServerConnection, SessionManager } from '@jupyterlab/services';
import { JupyterSessionManager } from './jupyterSessionManager';
import { LocalJupyterServerManager } from './jupyterServerManager';
export class JupyterNotebookManager implements nb.NotebookManager, vscode.Disposable {
export class JupyterExecuteManager implements nb.ExecuteManager, vscode.Disposable {
protected _serverSettings: ServerConnection.ISettings;
private _sessionManager: JupyterSessionManager;
@@ -21,9 +21,6 @@ export class JupyterNotebookManager implements nb.NotebookManager, vscode.Dispos
this._sessionManager.installation = this._serverManager.instanceOptions.install;
});
}
public get contentManager(): nb.ContentManager {
return undefined;
}
public get sessionManager(): nb.SessionManager {
return this._sessionManager;

View File

@@ -11,41 +11,41 @@ const localize = nls.loadMessageBundle();
import * as constants from '../common/constants';
import * as utils from '../common/utils';
import { JupyterNotebookManager } from './jupyterNotebookManager';
import { JupyterExecuteManager } from './jupyterExecuteManager';
import { LocalJupyterServerManager } from './jupyterServerManager';
import { JupyterSessionManager } from './jupyterSessionManager';
export type ServerManagerFactory = (documentUri: vscode.Uri) => LocalJupyterServerManager;
export class JupyterNotebookProvider implements nb.NotebookProvider {
export class JupyterExecuteProvider implements nb.NotebookExecuteProvider {
readonly providerId: string = constants.jupyterNotebookProviderId;
private managerTracker = new Map<string, JupyterNotebookManager>();
private executeManagerTracker = new Map<string, JupyterExecuteManager>();
constructor(private createServerManager: ServerManagerFactory) {
}
public getNotebookManager(notebookUri: vscode.Uri): Thenable<nb.NotebookManager> {
public getExecuteManager(notebookUri: vscode.Uri): Thenable<nb.ExecuteManager> {
if (!notebookUri) {
return Promise.reject(localize('errNotebookUriMissing', "A notebook path is required"));
}
return Promise.resolve(this.doGetNotebookManager(notebookUri));
return Promise.resolve(this.doGetExecuteManager(notebookUri));
}
public get notebookManagerCount(): number {
return this.managerTracker.size;
public get executeManagerCount(): number {
return this.executeManagerTracker.size;
}
private doGetNotebookManager(notebookUri: vscode.Uri): nb.NotebookManager {
private doGetExecuteManager(notebookUri: vscode.Uri): nb.ExecuteManager {
let baseFolder = this.transformToBaseFolder(notebookUri?.fsPath?.toString());
let manager = this.managerTracker.get(baseFolder);
let manager = this.executeManagerTracker.get(baseFolder);
if (!manager) {
let baseFolderUri = vscode.Uri.file(baseFolder);
if (!baseFolderUri) {
baseFolderUri = notebookUri;
}
let serverManager = this.createServerManager(baseFolderUri);
manager = new JupyterNotebookManager(serverManager);
this.managerTracker.set(baseFolder, manager);
manager = new JupyterExecuteManager(serverManager);
this.executeManagerTracker.set(baseFolder, manager);
}
return manager;
}
@@ -56,7 +56,7 @@ export class JupyterNotebookProvider implements nb.NotebookProvider {
return;
}
let baseFolder = this.transformToBaseFolder(notebookUri.fsPath.toString());
let manager = this.managerTracker.get(baseFolder);
let manager = this.executeManagerTracker.get(baseFolder);
if (manager) {
let sessionManager = (manager.sessionManager as JupyterSessionManager);
let session = sessionManager.listRunning().find(e => e.path === notebookUri.fsPath);
@@ -70,7 +70,7 @@ export class JupyterNotebookProvider implements nb.NotebookProvider {
const timeoutInMs = timeoutInMinutes * 60 * 1000;
setTimeout(() => {
if (sessionManager.listRunning().length === 0) {
this.managerTracker.delete(baseFolder);
this.executeManagerTracker.delete(baseFolder);
manager.dispose();
}
}, timeoutInMs);
@@ -79,10 +79,6 @@ export class JupyterNotebookProvider implements nb.NotebookProvider {
}
}
public get standardKernels(): nb.IStandardKernel[] {
return [];
}
private transformToBaseFolder(notebookPath: string): string {
let parsedPath = path.parse(notebookPath);
let userHome = utils.getUserHome();

View File

@@ -58,7 +58,7 @@ const configBase = {
}
};
export class JupyterSessionManager implements nb.SessionManager {
export class JupyterSessionManager implements nb.SessionManager, vscode.Disposable {
private _ready: Deferred<void>;
private _isReady: boolean;
private _sessionManager: Session.IManager;

View File

@@ -1,41 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { nb } from 'azdata';
import * as vscode from 'vscode';
import { Contents } from '@jupyterlab/services';
export class RemoteContentManager implements nb.ContentManager {
constructor(private contents: Contents.IManager) {
}
public getNotebookContents(notebookUri: vscode.Uri): Thenable<nb.INotebookContents> {
return this.getNotebookContentsAsync(notebookUri.fsPath);
}
private async getNotebookContentsAsync(path: string): Promise<nb.INotebookContents> {
if (!path) {
return undefined;
}
// Note: intentionally letting caller handle exceptions
let contentsModel = await this.contents.get(path);
if (!contentsModel) {
return undefined;
}
return <nb.INotebookContents>contentsModel.content;
}
public async save(notebookUri: vscode.Uri, notebook: nb.INotebookContents): Promise<nb.INotebookContents> {
let path = notebookUri.fsPath;
await this.contents.save(path, {
path: path,
content: notebook,
type: 'notebook',
format: 'json'
});
return notebook;
}
}