mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-17 02:51:36 -05:00
Disable python downloads when running notebooks on a SAW. (#11186)
This commit is contained in:
@@ -302,6 +302,14 @@
|
|||||||
"command": "jupyter.task.openNotebook",
|
"command": "jupyter.task.openNotebook",
|
||||||
"when": "false"
|
"when": "false"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"command": "jupyter.cmd.configurePython",
|
||||||
|
"when": "!notebook:runningOnSAW"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "jupyter.reinstallDependencies",
|
||||||
|
"when": "!notebook:runningOnSAW"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"command": "jupyter.cmd.managePackages",
|
"command": "jupyter.cmd.managePackages",
|
||||||
"when": "false"
|
"when": "false"
|
||||||
@@ -418,7 +426,7 @@
|
|||||||
"notebook/toolbar": [
|
"notebook/toolbar": [
|
||||||
{
|
{
|
||||||
"command": "jupyter.cmd.managePackages",
|
"command": "jupyter.cmd.managePackages",
|
||||||
"when": "providerId == jupyter && notebook:pythonInstalled"
|
"when": "providerId == jupyter && notebook:pythonInstalled && !notebook:runningOnSAW"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
import notebook.notebookapp
|
||||||
|
notebook.notebookapp.main()
|
||||||
@@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import * as azdata from 'azdata';
|
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
|
* 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);
|
azdata.tasks.startBackgroundOperation(operationInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
public setCommandContext(key: CommandContext | string, value: any): Thenable<any> {
|
|
||||||
return vscode.commands.executeCommand(BuiltInCommands.SetContext, key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public getNotebookDocuments() {
|
public getNotebookDocuments() {
|
||||||
return azdata.nb.notebookDocuments;
|
return azdata.nb.notebookDocuments;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* 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 fs from 'fs-extra';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as nls from 'vscode-nls';
|
import * as nls from 'vscode-nls';
|
||||||
@@ -15,7 +16,6 @@ import * as tar from 'tar';
|
|||||||
import { ApiWrapper } from '../common/apiWrapper';
|
import { ApiWrapper } from '../common/apiWrapper';
|
||||||
import * as constants from '../common/constants';
|
import * as constants from '../common/constants';
|
||||||
import * as utils from '../common/utils';
|
import * as utils from '../common/utils';
|
||||||
import { OutputChannel, ConfigurationTarget, window } from 'vscode';
|
|
||||||
import { Deferred } from '../common/promise';
|
import { Deferred } from '../common/promise';
|
||||||
import { ConfigurePythonWizard } from '../dialog/configurePython/configurePythonWizard';
|
import { ConfigurePythonWizard } from '../dialog/configurePython/configurePythonWizard';
|
||||||
import { IPrompter, IQuestion, confirm } from '../prompts/question';
|
import { IPrompter, IQuestion, confirm } from '../prompts/question';
|
||||||
@@ -59,13 +59,13 @@ export interface IJupyterServerInstallation {
|
|||||||
uninstallPipPackages(packages: PythonPkgDetails[]): Promise<void>;
|
uninstallPipPackages(packages: PythonPkgDetails[]): Promise<void>;
|
||||||
pythonExecutable: string;
|
pythonExecutable: string;
|
||||||
pythonInstallationPath: 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 {
|
export class JupyterServerInstallation implements IJupyterServerInstallation {
|
||||||
public apiWrapper: ApiWrapper;
|
public apiWrapper: ApiWrapper;
|
||||||
public extensionPath: string;
|
public extensionPath: string;
|
||||||
public pythonBinPath: string;
|
public pythonBinPath: string;
|
||||||
public outputChannel: OutputChannel;
|
public outputChannel: vscode.OutputChannel;
|
||||||
public pythonEnvVarPath: string;
|
public pythonEnvVarPath: string;
|
||||||
public execOptions: ExecOptions;
|
public execOptions: ExecOptions;
|
||||||
|
|
||||||
@@ -112,14 +112,25 @@ export class JupyterServerInstallation implements IJupyterServerInstallation {
|
|||||||
private readonly _requiredKernelPackages: Map<string, PythonPkgDetails[]>;
|
private readonly _requiredKernelPackages: Map<string, PythonPkgDetails[]>;
|
||||||
private readonly _requiredPackagesSet: Set<string>;
|
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.extensionPath = extensionPath;
|
||||||
this.outputChannel = outputChannel;
|
this.outputChannel = outputChannel;
|
||||||
this.apiWrapper = apiWrapper;
|
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._usingConda = false;
|
||||||
this._installInProgress = false;
|
this._installInProgress = false;
|
||||||
this._usingExistingPython = JupyterServerInstallation.getExistingPythonSetting(this.apiWrapper);
|
|
||||||
|
|
||||||
this._prompter = new CodeAdapter();
|
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> {
|
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.show(true);
|
||||||
this.outputChannel.appendLine(msgInstallPkgProgress);
|
this.outputChannel.appendLine(msgInstallPkgProgress);
|
||||||
@@ -189,10 +200,10 @@ export class JupyterServerInstallation implements IJupyterServerInstallation {
|
|||||||
|
|
||||||
this.outputChannel.appendLine(msgInstallPkgFinish);
|
this.outputChannel.appendLine(msgInstallPkgFinish);
|
||||||
backgroundOperation.updateStatus(azdata.TaskStatus.Succeeded, 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) {
|
if (usingExistingPython) {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
@@ -435,8 +446,8 @@ export class JupyterServerInstallation implements IJupyterServerInstallation {
|
|||||||
this.installDependencies(op, forceInstall, installSettings.specificPackages)
|
this.installDependencies(op, forceInstall, installSettings.specificPackages)
|
||||||
.then(async () => {
|
.then(async () => {
|
||||||
let notebookConfig = this.apiWrapper.getConfiguration(constants.notebookConfigKey);
|
let notebookConfig = this.apiWrapper.getConfiguration(constants.notebookConfigKey);
|
||||||
await notebookConfig.update(constants.pythonPathConfigKey, this._pythonInstallationPath, ConfigurationTarget.Global);
|
await notebookConfig.update(constants.pythonPathConfigKey, this._pythonInstallationPath, vscode.ConfigurationTarget.Global);
|
||||||
await notebookConfig.update(constants.existingPythonConfigKey, this._usingExistingPython, ConfigurationTarget.Global);
|
await notebookConfig.update(constants.existingPythonConfigKey, this._usingExistingPython, vscode.ConfigurationTarget.Global);
|
||||||
await this.configurePackagePaths();
|
await this.configurePackagePaths();
|
||||||
|
|
||||||
this._installCompletion.resolve();
|
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.
|
* Opens a dialog for configuring the installation path for the Notebook Python dependencies.
|
||||||
*/
|
*/
|
||||||
public async promptForPythonInstall(kernelDisplayName: string): Promise<void> {
|
public async promptForPythonInstall(kernelDisplayName: string): Promise<void> {
|
||||||
|
if (this._runningOnSAW) {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
if (this._installInProgress) {
|
if (this._installInProgress) {
|
||||||
this.apiWrapper.showInfoMessage(msgWaitingForInstall);
|
this.apiWrapper.showInfoMessage(msgWaitingForInstall);
|
||||||
return this._installCompletion.promise;
|
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.
|
* Prompts user to upgrade certain python packages if they're below the minimum expected version.
|
||||||
*/
|
*/
|
||||||
public async promptForPackageUpgrade(kernelName: string): Promise<void> {
|
public async promptForPackageUpgrade(kernelName: string): Promise<void> {
|
||||||
|
if (this._runningOnSAW) {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
if (this._installInProgress) {
|
if (this._installInProgress) {
|
||||||
this.apiWrapper.showInfoMessage(msgWaitingForInstall);
|
this.apiWrapper.showInfoMessage(msgWaitingForInstall);
|
||||||
return this._installCompletion.promise;
|
return this._installCompletion.promise;
|
||||||
@@ -835,22 +852,6 @@ export class JupyterServerInstallation implements IJupyterServerInstallation {
|
|||||||
return path;
|
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 {
|
public static getPythonExePath(pythonInstallPath: string, useExistingInstall: boolean): string {
|
||||||
return path.join(
|
return path.join(
|
||||||
pythonInstallPath,
|
pythonInstallPath,
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import { JupyterServerInstallation } from './jupyterServerInstallation';
|
|||||||
import * as utils from '../common/utils';
|
import * as utils from '../common/utils';
|
||||||
import { IServerInstance } from './common';
|
import { IServerInstance } from './common';
|
||||||
import { PerFolderServerInstance, IInstanceOptions } from './serverInstance';
|
import { PerFolderServerInstance, IInstanceOptions } from './serverInstance';
|
||||||
import { CommandContext } from '../common/constants';
|
import { CommandContext, BuiltInCommands } from '../common/constants';
|
||||||
|
|
||||||
export interface IServerManagerOptions {
|
export interface IServerManagerOptions {
|
||||||
documentPath: string;
|
documentPath: string;
|
||||||
@@ -112,7 +112,7 @@ export class LocalJupyterServerManager implements nb.ServerManager, vscode.Dispo
|
|||||||
if (!installation.previewFeaturesEnabled) {
|
if (!installation.previewFeaturesEnabled) {
|
||||||
await installation.promptForPackageUpgrade(kernelSpec.display_name);
|
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
|
// 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
|
// notebook to open. This will be the workspace folder if the notebook uri is inside a workspace
|
||||||
|
|||||||
@@ -127,8 +127,11 @@ export class PerFolderServerInstance implements IServerInstance {
|
|||||||
private childProcess: ChildProcess;
|
private childProcess: ChildProcess;
|
||||||
private errorHandler: ErrorHandler = new ErrorHandler();
|
private errorHandler: ErrorHandler = new ErrorHandler();
|
||||||
|
|
||||||
|
private readonly notebookScriptPath: string;
|
||||||
|
|
||||||
constructor(private options: IInstanceOptions, fsUtils?: ServerInstanceUtils) {
|
constructor(private options: IInstanceOptions, fsUtils?: ServerInstanceUtils) {
|
||||||
this.utils = fsUtils || new ServerInstanceUtils();
|
this.utils = fsUtils || new ServerInstanceUtils();
|
||||||
|
this.notebookScriptPath = path.join(this.options.install.extensionPath, 'resources', 'pythonScripts', 'startNotebook.py');
|
||||||
}
|
}
|
||||||
|
|
||||||
public get isStarted(): boolean {
|
public get isStarted(): boolean {
|
||||||
@@ -162,7 +165,7 @@ export class PerFolderServerInstance implements IServerInstance {
|
|||||||
}
|
}
|
||||||
if (this._isStarted) {
|
if (this._isStarted) {
|
||||||
let install = this.options.install;
|
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);
|
await this.utils.executeBufferedCommand(stopCommand, install.execOptions, install.outputChannel);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -243,7 +246,7 @@ export class PerFolderServerInstance implements IServerInstance {
|
|||||||
let token = await utils.getRandomToken();
|
let token = await utils.getRandomToken();
|
||||||
this._uri = vscode.Uri.parse(`http://localhost:${port}/?token=${token}`);
|
this._uri = vscode.Uri.parse(`http://localhost:${port}/?token=${token}`);
|
||||||
this._port = port.toString();
|
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);
|
this.notifyStarting(this.options.install, startCommand);
|
||||||
|
|
||||||
// Execute the command
|
// Execute the command
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ interface TestContext {
|
|||||||
describe('Manage Packages', () => {
|
describe('Manage Packages', () => {
|
||||||
let jupyterServerInstallation: JupyterServerInstallation;
|
let jupyterServerInstallation: JupyterServerInstallation;
|
||||||
beforeEach(() => {
|
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> {
|
it('Should throw exception given undefined providers', async function (): Promise<void> {
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ describe('Jupyter server instance', function (): void {
|
|||||||
await serverInstance.stop();
|
await serverInstance.stop();
|
||||||
|
|
||||||
// Then I expect stop to be called on the child process
|
// 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());
|
mockUtils.verify(u => u.removeDir(TypeMoq.It.isAny()), TypeMoq.Times.never());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user