Disable python downloads when running notebooks on a SAW. (#11186)

This commit is contained in:
Cory Rivera
2020-07-07 11:32:05 -07:00
committed by GitHub
parent 9f0584f88f
commit f409abfc01
8 changed files with 48 additions and 39 deletions

View File

@@ -302,6 +302,14 @@
"command": "jupyter.task.openNotebook",
"when": "false"
},
{
"command": "jupyter.cmd.configurePython",
"when": "!notebook:runningOnSAW"
},
{
"command": "jupyter.reinstallDependencies",
"when": "!notebook:runningOnSAW"
},
{
"command": "jupyter.cmd.managePackages",
"when": "false"
@@ -418,7 +426,7 @@
"notebook/toolbar": [
{
"command": "jupyter.cmd.managePackages",
"when": "providerId == jupyter && notebook:pythonInstalled"
"when": "providerId == jupyter && notebook:pythonInstalled && !notebook:runningOnSAW"
}
]
},

View File

@@ -0,0 +1,2 @@
import notebook.notebookapp
notebook.notebookapp.main()

View File

@@ -5,7 +5,6 @@
import * as vscode from 'vscode';
import * as azdata from 'azdata';
import { CommandContext, BuiltInCommands } from './constants';
/**
* Wrapper class to act as a facade over VSCode and Data APIs and allow us to test / mock callbacks into
@@ -61,10 +60,6 @@ export class ApiWrapper {
azdata.tasks.startBackgroundOperation(operationInfo);
}
public setCommandContext(key: CommandContext | string, value: any): Thenable<any> {
return vscode.commands.executeCommand(BuiltInCommands.SetContext, key, value);
}
public getNotebookDocuments() {
return azdata.nb.notebookDocuments;
}

View File

@@ -3,6 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import * as fs from 'fs-extra';
import * as path from 'path';
import * as nls from 'vscode-nls';
@@ -15,7 +16,6 @@ import * as tar from 'tar';
import { ApiWrapper } from '../common/apiWrapper';
import * as constants from '../common/constants';
import * as utils from '../common/utils';
import { OutputChannel, ConfigurationTarget, window } from 'vscode';
import { Deferred } from '../common/promise';
import { ConfigurePythonWizard } from '../dialog/configurePython/configurePythonWizard';
import { IPrompter, IQuestion, confirm } from '../prompts/question';
@@ -59,13 +59,13 @@ export interface IJupyterServerInstallation {
uninstallPipPackages(packages: PythonPkgDetails[]): Promise<void>;
pythonExecutable: string;
pythonInstallationPath: string;
installPythonPackage(backgroundOperation: azdata.BackgroundOperation, usingExistingPython: boolean, pythonInstallationPath: string, outputChannel: OutputChannel): Promise<void>;
installPythonPackage(backgroundOperation: azdata.BackgroundOperation, usingExistingPython: boolean, pythonInstallationPath: string, outputChannel: vscode.OutputChannel): Promise<void>;
}
export class JupyterServerInstallation implements IJupyterServerInstallation {
public apiWrapper: ApiWrapper;
public extensionPath: string;
public pythonBinPath: string;
public outputChannel: OutputChannel;
public outputChannel: vscode.OutputChannel;
public pythonEnvVarPath: string;
public execOptions: ExecOptions;
@@ -112,14 +112,25 @@ export class JupyterServerInstallation implements IJupyterServerInstallation {
private readonly _requiredKernelPackages: Map<string, PythonPkgDetails[]>;
private readonly _requiredPackagesSet: Set<string>;
constructor(extensionPath: string, outputChannel: OutputChannel, apiWrapper: ApiWrapper, pythonInstallationPath?: string) {
private readonly _runningOnSAW: boolean;
constructor(extensionPath: string, outputChannel: vscode.OutputChannel, apiWrapper: ApiWrapper) {
this.extensionPath = extensionPath;
this.outputChannel = outputChannel;
this.apiWrapper = apiWrapper;
this._pythonInstallationPath = pythonInstallationPath || JupyterServerInstallation.getPythonInstallPath(this.apiWrapper);
this._runningOnSAW = vscode.env.appName.toLowerCase().indexOf('saw') > 0;
vscode.commands.executeCommand(constants.BuiltInCommands.SetContext, 'notebook:runningOnSAW', this._runningOnSAW);
if (this._runningOnSAW) {
this._pythonInstallationPath = `${vscode.env.appRoot}\\ads-python`;
this._usingExistingPython = true;
} else {
this._pythonInstallationPath = JupyterServerInstallation.getPythonInstallPath(this.apiWrapper);
this._usingExistingPython = JupyterServerInstallation.getExistingPythonSetting(this.apiWrapper);
}
this._usingConda = false;
this._installInProgress = false;
this._usingExistingPython = JupyterServerInstallation.getExistingPythonSetting(this.apiWrapper);
this._prompter = new CodeAdapter();
@@ -170,7 +181,7 @@ export class JupyterServerInstallation implements IJupyterServerInstallation {
}
private async installDependencies(backgroundOperation: azdata.BackgroundOperation, forceInstall: boolean, specificPackages?: PythonPkgDetails[]): Promise<void> {
window.showInformationMessage(msgInstallPkgStart);
vscode.window.showInformationMessage(msgInstallPkgStart);
this.outputChannel.show(true);
this.outputChannel.appendLine(msgInstallPkgProgress);
@@ -189,10 +200,10 @@ export class JupyterServerInstallation implements IJupyterServerInstallation {
this.outputChannel.appendLine(msgInstallPkgFinish);
backgroundOperation.updateStatus(azdata.TaskStatus.Succeeded, msgInstallPkgFinish);
window.showInformationMessage(msgInstallPkgFinish);
vscode.window.showInformationMessage(msgInstallPkgFinish);
}
public installPythonPackage(backgroundOperation: azdata.BackgroundOperation, usingExistingPython: boolean, pythonInstallationPath: string, outputChannel: OutputChannel): Promise<void> {
public installPythonPackage(backgroundOperation: azdata.BackgroundOperation, usingExistingPython: boolean, pythonInstallationPath: string, outputChannel: vscode.OutputChannel): Promise<void> {
if (usingExistingPython) {
return Promise.resolve();
}
@@ -435,8 +446,8 @@ export class JupyterServerInstallation implements IJupyterServerInstallation {
this.installDependencies(op, forceInstall, installSettings.specificPackages)
.then(async () => {
let notebookConfig = this.apiWrapper.getConfiguration(constants.notebookConfigKey);
await notebookConfig.update(constants.pythonPathConfigKey, this._pythonInstallationPath, ConfigurationTarget.Global);
await notebookConfig.update(constants.existingPythonConfigKey, this._usingExistingPython, ConfigurationTarget.Global);
await notebookConfig.update(constants.pythonPathConfigKey, this._pythonInstallationPath, vscode.ConfigurationTarget.Global);
await notebookConfig.update(constants.existingPythonConfigKey, this._usingExistingPython, vscode.ConfigurationTarget.Global);
await this.configurePackagePaths();
this._installCompletion.resolve();
@@ -457,6 +468,9 @@ export class JupyterServerInstallation implements IJupyterServerInstallation {
* Opens a dialog for configuring the installation path for the Notebook Python dependencies.
*/
public async promptForPythonInstall(kernelDisplayName: string): Promise<void> {
if (this._runningOnSAW) {
return Promise.resolve();
}
if (this._installInProgress) {
this.apiWrapper.showInfoMessage(msgWaitingForInstall);
return this._installCompletion.promise;
@@ -482,6 +496,9 @@ export class JupyterServerInstallation implements IJupyterServerInstallation {
* Prompts user to upgrade certain python packages if they're below the minimum expected version.
*/
public async promptForPackageUpgrade(kernelName: string): Promise<void> {
if (this._runningOnSAW) {
return Promise.resolve();
}
if (this._installInProgress) {
this.apiWrapper.showInfoMessage(msgWaitingForInstall);
return this._installCompletion.promise;
@@ -835,22 +852,6 @@ export class JupyterServerInstallation implements IJupyterServerInstallation {
return path;
}
/**
* Returns the folder containing the python executable under the path defined in
* "notebook.pythonPath" in the user's settings.
* @param apiWrapper An ApiWrapper to use when retrieving user settings info.
*/
public static getPythonBinPath(apiWrapper: ApiWrapper): string {
let pythonBinPathSuffix = process.platform === constants.winPlatform ? '' : 'bin';
let useExistingInstall = JupyterServerInstallation.getExistingPythonSetting(apiWrapper);
return path.join(
JupyterServerInstallation.getPythonInstallPath(apiWrapper),
useExistingInstall ? '' : constants.pythonBundleVersion,
pythonBinPathSuffix);
}
public static getPythonExePath(pythonInstallPath: string, useExistingInstall: boolean): string {
return path.join(
pythonInstallPath,

View File

@@ -15,7 +15,7 @@ import { JupyterServerInstallation } from './jupyterServerInstallation';
import * as utils from '../common/utils';
import { IServerInstance } from './common';
import { PerFolderServerInstance, IInstanceOptions } from './serverInstance';
import { CommandContext } from '../common/constants';
import { CommandContext, BuiltInCommands } from '../common/constants';
export interface IServerManagerOptions {
documentPath: string;
@@ -112,7 +112,7 @@ export class LocalJupyterServerManager implements nb.ServerManager, vscode.Dispo
if (!installation.previewFeaturesEnabled) {
await installation.promptForPackageUpgrade(kernelSpec.display_name);
}
this._apiWrapper.setCommandContext(CommandContext.NotebookPythonInstalled, true);
vscode.commands.executeCommand(BuiltInCommands.SetContext, CommandContext.NotebookPythonInstalled, true);
// Calculate the path to use as the notebook-dir for Jupyter based on the path of the uri of the
// notebook to open. This will be the workspace folder if the notebook uri is inside a workspace

View File

@@ -127,8 +127,11 @@ export class PerFolderServerInstance implements IServerInstance {
private childProcess: ChildProcess;
private errorHandler: ErrorHandler = new ErrorHandler();
private readonly notebookScriptPath: string;
constructor(private options: IInstanceOptions, fsUtils?: ServerInstanceUtils) {
this.utils = fsUtils || new ServerInstanceUtils();
this.notebookScriptPath = path.join(this.options.install.extensionPath, 'resources', 'pythonScripts', 'startNotebook.py');
}
public get isStarted(): boolean {
@@ -162,7 +165,7 @@ export class PerFolderServerInstance implements IServerInstance {
}
if (this._isStarted) {
let install = this.options.install;
let stopCommand = `"${install.pythonExecutable}" -m jupyter notebook stop ${this._port}`;
let stopCommand = `"${install.pythonExecutable}" "${this.notebookScriptPath}" stop ${this._port}`;
await this.utils.executeBufferedCommand(stopCommand, install.execOptions, install.outputChannel);
}
} catch (error) {
@@ -243,7 +246,7 @@ export class PerFolderServerInstance implements IServerInstance {
let token = await utils.getRandomToken();
this._uri = vscode.Uri.parse(`http://localhost:${port}/?token=${token}`);
this._port = port.toString();
let startCommand = `"${this.options.install.pythonExecutable}" -m jupyter notebook --no-browser --no-mathjax --notebook-dir "${notebookDirectory}" --port=${port} --NotebookApp.token=${token}`;
let startCommand = `"${this.options.install.pythonExecutable}" "${this.notebookScriptPath}" --no-browser --no-mathjax --notebook-dir "${notebookDirectory}" --port=${port} --NotebookApp.token=${token}`;
this.notifyStarting(this.options.install, startCommand);
// Execute the command

View File

@@ -19,7 +19,7 @@ interface TestContext {
describe('Manage Packages', () => {
let jupyterServerInstallation: JupyterServerInstallation;
beforeEach(() => {
jupyterServerInstallation = new JupyterServerInstallation(undefined, undefined, undefined, undefined);
jupyterServerInstallation = new JupyterServerInstallation(undefined, undefined, undefined);
});
it('Should throw exception given undefined providers', async function (): Promise<void> {

View File

@@ -147,7 +147,7 @@ describe('Jupyter server instance', function (): void {
await serverInstance.stop();
// Then I expect stop to be called on the child process
should(actualCommand.indexOf(`jupyter notebook stop ${serverInstance.port}`)).be.greaterThan(-1);
should(actualCommand.includes(`stop ${serverInstance.port}`)).be.true('Command did not contain specified port.');
mockUtils.verify(u => u.removeDir(TypeMoq.It.isAny()), TypeMoq.Times.never());
});