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

Support remote commands in the kernel picker #10602

Merged
merged 27 commits into from
Jun 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
c1bb432
Add commands and fixup the server selector
rchiodo Jun 22, 2022
9690f55
Merge remote-tracking branch 'origin/main' into rchiodo/toggle_remote
rchiodo Jun 23, 2022
e667411
Filter list of controllers by connection type
rchiodo Jun 23, 2022
22f7599
Wire up commands
rchiodo Jun 23, 2022
c610482
Update telemetry
rchiodo Jun 23, 2022
4e05ded
Add another command for when already remote
rchiodo Jun 23, 2022
4a3e97b
Make sure activation failures don't stop other activations
rchiodo Jun 23, 2022
a4e478c
Merge remote-tracking branch 'origin/main' into rchiodo/toggle_remote
rchiodo Jun 23, 2022
ca03019
Some more parts working
rchiodo Jun 24, 2022
5c5a7db
Using multistep to setup back button and filtering
rchiodo Jun 24, 2022
0af1629
Update telemetry
rchiodo Jun 24, 2022
abd9596
Fix showing duplicates in custom quick pick
rchiodo Jun 24, 2022
da88bc5
Fix localization and refreshing between local and remote
rchiodo Jun 24, 2022
4361612
First try at a test
rchiodo Jun 25, 2022
a8073e8
Remove ability to set local launch independent of URI
rchiodo Jun 27, 2022
5ab57a7
Fix back button
rchiodo Jun 27, 2022
dc68e1e
Get all tests passing
rchiodo Jun 27, 2022
d8a013a
Merge remote-tracking branch 'origin/main' into rchiodo/toggle_remote
rchiodo Jun 27, 2022
40ea168
Update telemetry
rchiodo Jun 28, 2022
ed9d88e
Add news entries
rchiodo Jun 28, 2022
efcafc8
Fix isLocalLaunch to actually use the internal flag
rchiodo Jun 28, 2022
c188e9f
Fix unit tests and use serverId
rchiodo Jun 29, 2022
14f9dcc
Merge remote-tracking branch 'origin/main' into rchiodo/toggle_remote
rchiodo Jun 30, 2022
13d7912
Update telemetry
rchiodo Jun 30, 2022
9094eb8
Fix bug in load order
rchiodo Jun 30, 2022
f98ba1f
Merge remote-tracking branch 'origin/main' into rchiodo/toggle_remote
rchiodo Jun 30, 2022
12db879
Update telemetry
rchiodo Jun 30, 2022
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
202 changes: 101 additions & 101 deletions TELEMETRY.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions news/1 Enhancements/10435.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Rework kernel selection to be in either 'remote' mode or 'local' mode to avoid confusion about what kernels should be displayed.
1 change: 1 addition & 0 deletions news/2 Fixes/10191.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixes problem where clipboard permissions are required in order to enter a Jupyter server URL.
1 change: 1 addition & 0 deletions news/2 Fixes/10363.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix problem of determining whether or not in 'local' or 'remote' mode for a jupyer connection.
40 changes: 38 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -841,11 +841,23 @@
},
{
"command": "jupyter.installPythonExtensionViaKernelPicker",
"title": "Install Python Extension"
"title": "%DataScience.installPythonExtensionViaKernelPickerTitle%"
},
{
"command": "jupyter.installPythonViaKernelPicker",
"title": "Install Python"
"title": "%DataScience.installPythonTitle%"
},
{
"command": "jupyter.switchToLocalKernels",
"title": "%DataScience.switchToLocalKernelsTitle%"
},
{
"command": "jupyter.switchToRemoteKernels",
"title": "%DataScience.switchToRemoteKernelsTitle%"
},
{
"command": "jupyter.switchToAnotherRemoteKernels",
"title": "%DataScience.switchToAnotherRemoteKernelsTitle%"
}
],
"menus": {
Expand Down Expand Up @@ -1007,6 +1019,18 @@
{
"command": "jupyter.installPythonViaKernelPicker",
"when": "jupyter.showInstallPythonCommand"
},
{
"command": "jupyter.switchToLocalKernels",
"when": "jupyter.showingRemoteNotWeb"
},
{
"command": "jupyter.switchToRemoteKernels",
"when": "jupyter.showingLocalOrWebEmpty"
},
{
"command": "jupyter.switchToAnotherRemoteKernels",
"when": "jupyter.showingRemoteKernels"
}
],
"interactive/toolbar": [
Expand Down Expand Up @@ -1089,6 +1113,18 @@
"command": "jupyter.installPythonViaKernelPicker",
"when": "false"
},
{
"command": "jupyter.switchToLocalKernels",
"when": "false"
},
{
"command": "jupyter.switchToRemoteKernels",
"when": "false"
},
{
"command": "jupyter.switchToAnotherRemoteKernels",
"when": "false"
},
{
"command": "jupyter.replayPylanceLog",
"title": "Replay Pylance Log",
Expand Down
6 changes: 5 additions & 1 deletion package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -956,6 +956,10 @@
"Products.installingModule": "Installing {0}",
"DataScience.webNotSupported": "Operation not supported in web version of Jupyter Extension.",
"DataScience.outputSizeExceedLimit": "Output exceeds the <a href={0}>size limit</a>. Open the full output data <a href={1}>in a text editor</a>",
"DataScience.installPythonTitle": "Install Python",
Copy link
Contributor

Choose a reason for hiding this comment

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

@IanMatthewHuff looks like this will need to be reviewed closly as you're also working in the similar area (installing python when its missing). I.e. you might want to review the workflow & the changes.
Feels like this stuff related to no python might require its own folder/set of classes & its been worked on for months if not years (i.e. workflow keeps changing, hence better to keep it isolated & easier to manage)

Agai, I haven't reviewed anything yet, but just a thought about this (prompting to install python - getting started) part of the exetnsion

Copy link
Member

Choose a reason for hiding this comment

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

@DonJayamanne I think Rich was just adding on the Command localization that I missed in my addition. The only real conflict to consider here is just the fact that we won't have only one command anymore in the new user scenario. Means that we don't get that nice "just hit the run button" launch, but we can tweak that as we move forward. Maybe prioritization for commands in the kernel picker somehow.

"DataScience.installPythonExtensionViaKernelPickerTitle": "Install Python Extension",
"DataScience.switchToLocalKernelsTitle": "Connect to Local Kernels",
"DataScience.switchToRemoteKernelsTitle": "Connect to Your Own Jupyter Server",
"DataScience.switchToAnotherRemoteKernelsTitle": "Connect to Another Jupyter Server",
"DataScience.failedToInstallPythonExtension": "Failed to install the Python Extension."
}

3 changes: 3 additions & 0 deletions src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,4 +194,7 @@ export interface ICommandNameArgumentTypeMapping extends ICommandNameWithoutArgu
[DSCommands.ReplayPylanceLogStep]: [];
[DSCommands.InstallPythonExtensionViaKernelPicker]: [];
[DSCommands.InstallPythonViaKernelPicker]: [];
[DSCommands.SwitchToLocalKernels]: [];
[DSCommands.SwitchToRemoteKernels]: [];
[DSCommands.SwitchToAnotherRemoteKernels]: [];
}
6 changes: 3 additions & 3 deletions src/kernels/jupyter/jupyterConnection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ import { RemoteJupyterServerUriProviderError } from '../errors/remoteJupyterServ
import { BaseError } from '../../platform/errors/types';
import { IJupyterConnection } from '../types';
import { computeServerId, createRemoteConnectionInfo, extractJupyterServerHandleAndId } from './jupyterUtils';
import { ServerConnectionType } from './launcher/serverConnectionType';
import {
IJupyterServerUri,
IJupyterServerUriStorage,
IJupyterSessionManager,
IJupyterSessionManagerFactory,
IJupyterUriProviderRegistration
IJupyterUriProviderRegistration,
IServerConnectionType
} from './types';

@injectable()
Expand All @@ -29,7 +29,7 @@ export class JupyterConnection implements IExtensionSyncActivationService {
private readonly jupyterSessionManagerFactory: IJupyterSessionManagerFactory,
@inject(IDisposableRegistry)
private readonly disposables: IDisposableRegistry,
@inject(ServerConnectionType) private readonly serverConnectionType: ServerConnectionType,
@inject(IServerConnectionType) private readonly serverConnectionType: IServerConnectionType,
@inject(IJupyterServerUriStorage) private readonly serverUriStorage: IJupyterServerUriStorage
) {
disposables.push(this);
Expand Down
4 changes: 2 additions & 2 deletions src/kernels/jupyter/launcher/commandLineSelector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ export class JupyterCommandLineSelector {
}

@captureTelemetry(Telemetry.SelectJupyterURI)
public selectJupyterCommandLine(file: Uri): Promise<void> {
public async selectJupyterCommandLine(file: Uri): Promise<void> {
const multiStep = this.multiStepFactory.create<{}>();
return multiStep.run(this.startSelectingCommandLine.bind(this, file), {});
await multiStep.run(this.startSelectingCommandLine.bind(this, file), {});
}

private async onDidChangeConfiguration(e: ConfigurationChangeEvent) {
Expand Down
5 changes: 2 additions & 3 deletions src/kernels/jupyter/launcher/notebookProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ import {
import { Cancellation } from '../../../platform/common/cancellation';
import { DisplayOptions } from '../../displayOptions';
import { IRawNotebookProvider } from '../../raw/types';
import { IJupyterNotebookProvider } from '../types';
import { ServerConnectionType } from './serverConnectionType';
import { IJupyterNotebookProvider, IServerConnectionType } from '../types';
import { sendKernelTelemetryWhenDone } from '../../telemetry/sendKernelTelemetryEvent';

@injectable()
Expand All @@ -33,7 +32,7 @@ export class NotebookProvider implements INotebookProvider {
@inject(IJupyterNotebookProvider)
private readonly jupyterNotebookProvider: IJupyterNotebookProvider,
@inject(IPythonExtensionChecker) private readonly extensionChecker: IPythonExtensionChecker,
@inject(ServerConnectionType) private readonly serverConnectionType: ServerConnectionType
@inject(IServerConnectionType) private readonly serverConnectionType: IServerConnectionType
) {}

// Attempt to connect to our server provider, and if we do, return the connection info
Expand Down
41 changes: 0 additions & 41 deletions src/kernels/jupyter/launcher/serverConnectionType.ts

This file was deleted.

58 changes: 45 additions & 13 deletions src/kernels/jupyter/launcher/serverUriStorage.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,30 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import { inject, injectable, named } from 'inversify';
import { EventEmitter, Memento } from 'vscode';
import { Event, EventEmitter, Memento } from 'vscode';
import {
IWorkspaceService,
IEncryptedStorage,
IApplicationEnvironment
} from '../../../platform/common/application/types';
import { Settings } from '../../../platform/common/constants';
import { getFilePath } from '../../../platform/common/platform/fs-paths';
import { ICryptoUtils, IMemento, GLOBAL_MEMENTO } from '../../../platform/common/types';
import { IJupyterServerUriStorage } from '../types';
import { ServerConnectionType } from './serverConnectionType';
import { ICryptoUtils, IMemento, GLOBAL_MEMENTO, IsWebExtension } from '../../../platform/common/types';
import { computeServerId } from '../jupyterUtils';
import { IJupyterServerUriStorage, IServerConnectionType } from '../types';

export const mementoKeyToIndicateIfConnectingToLocalKernelsOnly = 'connectToLocalKernelsOnly';
export const currentServerHashKey = 'currentServerHash';

/**
* Class for storing Jupyter Server URI values
*/
@injectable()
export class JupyterServerUriStorage implements IJupyterServerUriStorage {
export class JupyterServerUriStorage implements IJupyterServerUriStorage, IServerConnectionType {
private lastSavedList?: Promise<{ uri: string; time: number; displayName?: string | undefined }[]>;
private currentUriPromise: Promise<string> | undefined;
private _currentServerId: string | undefined;
private _localOnly: boolean = false;
private _onDidChangeUri = new EventEmitter<void>();
public get onDidChangeUri() {
return this._onDidChangeUri.event;
Expand All @@ -28,14 +33,29 @@ export class JupyterServerUriStorage implements IJupyterServerUriStorage {
public get onDidRemoveUris() {
return this._onDidRemoveUris.event;
}
public get currentServerId(): string | undefined {
return this._currentServerId;
}
public get onDidChange(): Event<void> {
return this._onDidChangeUri.event;
}
public get isLocalLaunch(): boolean {
return this._localOnly;
}
constructor(
@inject(IWorkspaceService) private readonly workspaceService: IWorkspaceService,
@inject(ICryptoUtils) private readonly crypto: ICryptoUtils,
@inject(IEncryptedStorage) private readonly encryptedStorage: IEncryptedStorage,
@inject(IApplicationEnvironment) private readonly appEnv: IApplicationEnvironment,
@inject(IMemento) @named(GLOBAL_MEMENTO) private readonly globalMemento: Memento,
@inject(ServerConnectionType) private readonly serverConnectionType: ServerConnectionType
@inject(IsWebExtension) readonly isWebExtension: boolean
) {
// Remember if local only
Copy link
Contributor Author

Choose a reason for hiding this comment

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

THis is the code that was originally in the serverConnectionType.ts file.

this._localOnly = isWebExtension
? false
: this.globalMemento.get<boolean>(mementoKeyToIndicateIfConnectingToLocalKernelsOnly, true);
this._currentServerId = this.globalMemento.get<string | undefined>(currentServerHashKey, undefined);

// Cache our current state so we don't keep asking for it from the encrypted storage
this.getUri().ignoreErrors();
}
Expand Down Expand Up @@ -182,33 +202,45 @@ export class JupyterServerUriStorage implements IJupyterServerUriStorage {
await this.setUri(Settings.JupyterServerLocalLaunch);
}
public async setUriToRemote(uri: string, displayName: string): Promise<void> {
await this.setUri(uri);
// Make sure to add to the saved list before we set the uri. Otherwise
// handlers for the URI changing will use the saved list to make sure the
// server id matches
await this.addToUriList(uri, Date.now(), displayName);
await this.setUri(uri);
Copy link
Member

Choose a reason for hiding this comment

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

Looks like addToUriList is happening in two spots? Both here and in setUri, do we need both?

}

public async setUri(uri: string) {
// Set the URI as our current state
this.currentUriPromise = Promise.resolve(uri);
if (uri === Settings.JupyterServerLocalLaunch) {
await this.serverConnectionType.setIsLocalLaunch(true);
} else {
this._currentServerId = computeServerId(uri);
this._localOnly = uri === Settings.JupyterServerLocalLaunch || uri === undefined;
this._onDidChangeUri.fire(); // Needs to happen as soon as we change so that dependencies update synchronously

// No update the async parts
await this.globalMemento.update(mementoKeyToIndicateIfConnectingToLocalKernelsOnly, this._localOnly);
await this.globalMemento.update(currentServerHashKey, this._currentServerId);

if (!this._localOnly) {
await this.addToUriList(uri, Date.now(), uri);
await this.serverConnectionType.setIsLocalLaunch(false);

// Save in the storage (unique account per workspace)
const key = this.getUriAccountKey();
await this.encryptedStorage.store(Settings.JupyterServerRemoteLaunchService, key, uri);
}
this._onDidChangeUri.fire();
}
private async getUriInternal(): Promise<string> {
if (this.serverConnectionType.isLocalLaunch) {
if (this.isLocalLaunch) {
return Settings.JupyterServerLocalLaunch;
} else {
// Should be stored in encrypted storage based on the workspace
const key = this.getUriAccountKey();
const storedUri = await this.encryptedStorage.retrieve(Settings.JupyterServerRemoteLaunchService, key);

// Update server id if not already set
if (!this._currentServerId && storedUri) {
this._currentServerId = computeServerId(storedUri);
}

return storedUri || Settings.JupyterServerLocalLaunch;
}
}
Expand Down
Loading