GeezerVison is showing github.com — Dev/ianhu/fetch variables impl (#4446) · rtu/vscode-python@a69be7a
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: package.nls.json +1Lines changed: 1 addition & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 139 | 139 | "DataScience.notebookVersionFormat": "Jupyter Notebook Version: {0}", | 140 | 140 | "DataScience.jupyterKernelNotSupportedOnActive": "Jupyter kernel cannot be started from '{0}'. Using closest match {1} instead.", | 141 | 141 | "DataScience.jupyterKernelSpecNotFound": "Cannot create a Jupyter kernel spec and none are available for use", | | 142 | + "DataScience.jupyterGetVariablesBadResults": "Failed to fetch variables from the Jupyter server.", | 142 | 143 | "DataScience.liveShareConnectFailure": "Cannot connect to host Jupyter session. URI not found.", | 143 | 144 | "DataScience.liveShareCannotSpawnNotebooks": "Spawning Jupyter notebooks is not supported over a live share connection", | 144 | 145 | "DataScience.liveShareCannotImportNotebooks": "Importing notebooks is not currently supported over a live share connection", | |
Collapse file Copy file name to clipboard +13Lines changed: 13 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| | 1 | +# Query Jupyter server for defined variables list | | 2 | +# Tested on 2.7 and 3.6 | | 3 | +from sys import getsizeof | | 4 | +import json | | 5 | + | | 6 | +# who_ls is a Jupyter line magic to fetch currently defined vars | | 7 | +_VSCode_JupyterVars = %who_ls | | 8 | + | | 9 | +json.dumps([{'name': var, | | 10 | + 'type': type(eval(var)).__name__, | | 11 | + 'size': getsizeof(var), | | 12 | + 'expensive': True | | 13 | + } for var in _VSCode_JupyterVars]) |
Collapse file Copy file name to clipboardExpand all lines: src/client/common/utils/localize.ts +1Lines changed: 1 addition & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -132,6 +132,7 @@ export namespace DataScience { | 132 | 132 | export const liveShareSyncFailure = localize('DataScience.liveShareSyncFailure', 'Synchronization failure during live share startup.'); | 133 | 133 | export const liveShareServiceFailure = localize('DataScience.liveShareServiceFailure', 'Failure starting \'{0}\' service during live share connection.'); | 134 | 134 | export const documentMismatch = localize('DataScience.documentMismatch', 'Cannot run cells, duplicate documents for {0} found.'); | | 135 | + export const jupyterGetVariablesBadResults = localize('DataScience.jupyterGetVariablesBadResults', 'Failed to fetch variables from the Jupyter server.'); | 135 | 136 | } | 136 | 137 |
| 137 | 138 | export namespace DebugConfigurationPrompts { | |
Collapse file Copy file name to clipboardExpand all lines: src/client/datascience/history.ts +1-1Lines changed: 1 addition & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
@@ -424,7 +424,7 @@ export class History implements IHistory { | 424 | 424 | } | 425 | 425 |
| 426 | 426 | // Attempt to evaluate this cell in the jupyter notebook | 427 | | - const observable = this.jupyterServer.executeObservable(code, file, line, id); | | 427 | + const observable = this.jupyterServer.executeObservable(code, file, line, id, false); | 428 | 428 |
| 429 | 429 | // Sign up for cell changes | 430 | 430 | observable.subscribe( | |
Collapse file Copy file name to clipboardExpand all lines: src/client/datascience/jupyter/jupyterServer.ts +33-33Lines changed: 33 additions & 33 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -158,15 +158,15 @@ export class JupyterServerBase implements INotebookServer { | 158 | 158 | return this.session ? this.session.waitForIdle() : Promise.resolve(); | 159 | 159 | } | 160 | 160 |
| 161 | | - public execute(code: string, file: string, line: number, id: string, cancelToken?: CancellationToken): Promise<ICell[]> { | | 161 | + public execute(code: string, file: string, line: number, id: string, cancelToken?: CancellationToken, silent?: boolean): Promise<ICell[]> { | 162 | 162 | // Do initial setup if necessary | 163 | 163 | this.initialNotebookSetup(); | 164 | 164 |
| 165 | 165 | // Create a deferred that we'll fire when we're done | 166 | 166 | const deferred = createDeferred<ICell[]>(); | 167 | 167 |
| 168 | 168 | // Attempt to evaluate this cell in the jupyter notebook | 169 | | - const observable = this.executeObservable(code, file, line, id); | | 169 | + const observable = this.executeObservable(code, file, line, id, silent); | 170 | 170 | let output: ICell[]; | 171 | 171 |
| 172 | 172 | observable.subscribe( | @@ -196,40 +196,10 @@ export class JupyterServerBase implements INotebookServer { | 196 | 196 | } | 197 | 197 | } | 198 | 198 |
| 199 | | - public executeObservable(code: string, file: string, line: number, id: string): Observable<ICell[]> { | | 199 | + public executeObservable(code: string, file: string, line: number, id: string, silent: boolean = false): Observable<ICell[]> { | 200 | 200 | return this.executeObservableImpl(code, file, line, id, false); | 201 | 201 | } | 202 | 202 |
| 203 | | - public executeSilently(code: string, cancelToken?: CancellationToken): Promise<ICell[]> { | 204 | | - // Do initial setup if necessary | 205 | | - this.initialNotebookSetup(); | 206 | | - | 207 | | - // Create a deferred that we'll fire when we're done | 208 | | - const deferred = createDeferred<ICell[]>(); | 209 | | - | 210 | | - // Attempt to evaluate this cell in the jupyter notebook | 211 | | - const observable = this.executeObservableImpl(code, Identifiers.EmptyFileName, 0, uuid(), true); | 212 | | - let output: ICell[]; | 213 | | - | 214 | | - observable.subscribe( | 215 | | - (cells: ICell[]) => { | 216 | | - output = cells; | 217 | | - }, | 218 | | - (error) => { | 219 | | - deferred.reject(error); | 220 | | - }, | 221 | | - () => { | 222 | | - deferred.resolve(output); | 223 | | - }); | 224 | | - | 225 | | - if (cancelToken) { | 226 | | - this.disposableRegistry.push(cancelToken.onCancellationRequested(() => deferred.reject(new CancellationError()))); | 227 | | - } | 228 | | - | 229 | | - // Wait for the execution to finish | 230 | | - return deferred.promise; | 231 | | - } | 232 | | - | 233 | 203 | public async getSysInfo() : Promise<ICell> { | 234 | 204 | // tslint:disable-next-line:no-multiline-string | 235 | 205 | const versionCells = await this.executeSilently(`import sys\r\nsys.version`); | @@ -384,6 +354,36 @@ export class JupyterServerBase implements INotebookServer { | 384 | 354 | }; | 385 | 355 | } | 386 | 356 |
| | 357 | + private executeSilently(code: string, cancelToken?: CancellationToken): Promise<ICell[]> { | | 358 | + // Do initial setup if necessary | | 359 | + this.initialNotebookSetup(); | | 360 | + | | 361 | + // Create a deferred that we'll fire when we're done | | 362 | + const deferred = createDeferred<ICell[]>(); | | 363 | + | | 364 | + // Attempt to evaluate this cell in the jupyter notebook | | 365 | + const observable = this.executeObservableImpl(code, Identifiers.EmptyFileName, 0, uuid(), true); | | 366 | + let output: ICell[]; | | 367 | + | | 368 | + observable.subscribe( | | 369 | + (cells: ICell[]) => { | | 370 | + output = cells; | | 371 | + }, | | 372 | + (error) => { | | 373 | + deferred.reject(error); | | 374 | + }, | | 375 | + () => { | | 376 | + deferred.resolve(output); | | 377 | + }); | | 378 | + | | 379 | + if (cancelToken) { | | 380 | + this.disposableRegistry.push(cancelToken.onCancellationRequested(() => deferred.reject(new CancellationError()))); | | 381 | + } | | 382 | + | | 383 | + // Wait for the execution to finish | | 384 | + return deferred.promise; | | 385 | + } | | 386 | + | 387 | 387 | private extractStreamOutput(cell: ICell): string { | 388 | 388 | let result = ''; | 389 | 389 | if (cell.state === CellState.error || cell.state === CellState.finished) { | |
Collapse file Copy file name to clipboardExpand all lines: src/client/datascience/jupyter/jupyterServerFactory.ts +4-9Lines changed: 4 additions & 9 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -85,21 +85,21 @@ export class JupyterServerFactory implements INotebookServer { | 85 | 85 | return server.waitForIdle(); | 86 | 86 | } | 87 | 87 |
| 88 | | - public async execute(code: string, file: string, line: number, id: string, cancelToken?: CancellationToken): Promise<ICell[]> { | | 88 | + public async execute(code: string, file: string, line: number, id: string, cancelToken?: CancellationToken, silent?: boolean): Promise<ICell[]> { | 89 | 89 | const server = await this.serverFactory.get(); | 90 | | - return server.execute(code, file, line, id, cancelToken); | | 90 | + return server.execute(code, file, line, id, cancelToken, silent); | 91 | 91 | } | 92 | 92 |
| 93 | 93 | public async setInitialDirectory(directory: string): Promise<void> { | 94 | 94 | const server = await this.serverFactory.get(); | 95 | 95 | return server.setInitialDirectory(directory); | 96 | 96 | } | 97 | 97 |
| 98 | | - public executeObservable(code: string, file: string, line: number, id: string): Observable<ICell[]> { | | 98 | + public executeObservable(code: string, file: string, line: number, id: string, silent: boolean = false): Observable<ICell[]> { | 99 | 99 | // Create a wrapper observable around the actual server (because we have to wait for a promise) | 100 | 100 | return new Observable<ICell[]>(subscriber => { | 101 | 101 | this.serverFactory.get().then(s => { | 102 | | - s.executeObservable(code, file, line, id) | | 102 | + s.executeObservable(code, file, line, id, silent) | 103 | 103 | .forEach(n => subscriber.next(n), Promise) | 104 | 104 | .then(f => subscriber.complete()) | 105 | 105 | .catch(e => subscriber.error(e)); | @@ -111,11 +111,6 @@ export class JupyterServerFactory implements INotebookServer { | 111 | 111 | }); | 112 | 112 | } | 113 | 113 |
| 114 | | - public async executeSilently(code: string, cancelToken?: CancellationToken): Promise<void> { | 115 | | - const server = await this.serverFactory.get(); | 116 | | - return server.dispose(); | 117 | | - } | 118 | | - | 119 | 114 | public async restartKernel(): Promise<void> { | 120 | 115 | const server = await this.serverFactory.get(); | 121 | 116 | return server.restartKernel(); | |
Collapse file Copy file name to clipboardExpand all lines: src/client/datascience/jupyter/jupyterServerManager.ts +6Lines changed: 6 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -81,6 +81,12 @@ export class JupyterServerManager implements INotebookServerManager, IAsyncDispo | 81 | 81 | } | 82 | 82 | } | 83 | 83 |
| | 84 | + // Don't check the launch paramters, just return back the active | | 85 | + // used for components that never create or control the active server like the variables view | | 86 | + public getActiveServer(): INotebookServer | undefined { | | 87 | + return this.activeServer; | | 88 | + } | | 89 | + | 84 | 90 | public dispose(): Promise<void> { | 85 | 91 | if (this.activeServer) { | 86 | 92 | return this.activeServer.dispose(); | |
Collapse file Copy file name to clipboard +74Lines changed: 74 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| | 1 | +// Copyright (c) Microsoft Corporation. All rights reserved. | | 2 | +// Licensed under the MIT License. | | 3 | + | | 4 | +'use strict'; | | 5 | + | | 6 | +import { nbformat } from '@jupyterlab/coreutils'; | | 7 | +import { inject, injectable } from 'inversify'; | | 8 | +import * as path from 'path'; | | 9 | +import * as uuid from 'uuid/v4'; | | 10 | +import { IFileSystem } from '../../common/platform/types'; | | 11 | +import * as localize from '../../common/utils/localize'; | | 12 | +import { EXTENSION_ROOT_DIR } from '../../constants'; | | 13 | +import { Identifiers } from '../constants'; | | 14 | +import { ICell, IJupyterVariable, IJupyterVariables, INotebookServerManager } from '../types'; | | 15 | + | | 16 | +@injectable() | | 17 | +export class JupyterVariables implements IJupyterVariables { | | 18 | + private fetchVariablesScript?: string; | | 19 | + | | 20 | + constructor( | | 21 | + @inject(IFileSystem) private fileSystem: IFileSystem, | | 22 | + @inject(INotebookServerManager) private jupyterServerManager: INotebookServerManager | | 23 | + ) { | | 24 | + } | | 25 | + | | 26 | + // IJupyterVariables implementation | | 27 | + public async getVariables(): Promise<IJupyterVariable[]> { | | 28 | + // First make sure our python file is loaded up | | 29 | + if (!this.fetchVariablesScript) { | | 30 | + await this.loadVariablesFile(); | | 31 | + } | | 32 | + | | 33 | + const activeServer = this.jupyterServerManager.getActiveServer(); | | 34 | + if (!activeServer) { | | 35 | + // No active server will just return an empty list | | 36 | + return []; | | 37 | + } | | 38 | + | | 39 | + // Get our results and convert them to IJupyterVariable objects | | 40 | + const results = await activeServer.execute(this.fetchVariablesScript!, Identifiers.EmptyFileName, 0, uuid(), undefined, true); | | 41 | + return this.deserializeVariableData(results); | | 42 | + } | | 43 | + | | 44 | + // Private methods | | 45 | + private async loadVariablesFile(): Promise<void> { | | 46 | + if (this.fetchVariablesScript) { | | 47 | + return; | | 48 | + } | | 49 | + | | 50 | + const file = path.join(EXTENSION_ROOT_DIR, 'pythonFiles', 'datascience', 'getJupyterVariableList.py'); | | 51 | + this.fetchVariablesScript = await this.fileSystem.readFile(file); | | 52 | + } | | 53 | + | | 54 | + private deserializeVariableData(cells: ICell[]): IJupyterVariable[] { | | 55 | + // Verify that we have the correct cell type and outputs | | 56 | + if (cells.length > 0 && cells[0].data) { | | 57 | + const codeCell = cells[0].data as nbformat.ICodeCell; | | 58 | + if (codeCell.outputs.length > 0) { | | 59 | + const codeCellOutput = codeCell.outputs[0] as nbformat.IOutput; | | 60 | + if (codeCellOutput.data && codeCellOutput.data.hasOwnProperty('text/plain')) { | | 61 | + // tslint:disable-next-line:no-any | | 62 | + let resultString = ((codeCellOutput.data as any)['text/plain']); | | 63 | + | | 64 | + // Trim the excess ' character on the string | | 65 | + resultString = resultString.slice(1, resultString.length - 1); | | 66 | + | | 67 | + return JSON.parse(resultString) as IJupyterVariable[]; | | 68 | + } | | 69 | + } | | 70 | + } | | 71 | + | | 72 | + throw new Error(localize.DataScience.jupyterGetVariablesBadResults()); | | 73 | + } | | 74 | +} |
Collapse file Copy file name to clipboardExpand all lines: src/client/datascience/jupyter/liveshare/guestJupyterServer.ts -5Lines changed: 0 additions & 5 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -109,11 +109,6 @@ export class GuestJupyterServer | 109 | 109 | }); | 110 | 110 | } | 111 | 111 |
| 112 | | - public async executeSilently(code: string, cancelToken?: CancellationToken): Promise<void> { | 113 | | - // We don't need the result from this. It should have already happened on the host side | 114 | | - return Promise.resolve(); | 115 | | - } | 116 | | - | 117 | 112 | public async restartKernel(): Promise<void> { | 118 | 113 | await this.waitForResponse(ServerResponseType.Restart); | 119 | 114 | } | |
Collapse file Copy file name to clipboardExpand all lines: src/client/datascience/serviceRegistry.ts +3Lines changed: 3 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -17,6 +17,7 @@ import { JupyterImporter } from './jupyter/jupyterImporter'; | 17 | 17 | import { JupyterServerFactory } from './jupyter/jupyterServerFactory'; | 18 | 18 | import { JupyterServerManager } from './jupyter/jupyterServerManager'; | 19 | 19 | import { JupyterSessionManager } from './jupyter/jupyterSessionManager'; | | 20 | +import { JupyterVariables } from './jupyter/jupyterVariables'; | 20 | 21 | import { StatusProvider } from './statusProvider'; | 21 | 22 | import { | 22 | 23 | ICodeCssGenerator, | @@ -30,6 +31,7 @@ import { | 30 | 31 | IJupyterCommandFactory, | 31 | 32 | IJupyterExecution, | 32 | 33 | IJupyterSessionManager, | | 34 | + IJupyterVariables, | 33 | 35 | INotebookExporter, | 34 | 36 | INotebookImporter, | 35 | 37 | INotebookServer, | @@ -52,6 +54,7 @@ export function registerTypes(serviceManager: IServiceManager) { | 52 | 54 | serviceManager.addSingleton<ICodeCssGenerator>(ICodeCssGenerator, CodeCssGenerator); | 53 | 55 | serviceManager.addSingleton<IStatusProvider>(IStatusProvider, StatusProvider); | 54 | 56 | serviceManager.addSingleton<IJupyterSessionManager>(IJupyterSessionManager, JupyterSessionManager); | | 57 | + serviceManager.addSingleton<IJupyterVariables>(IJupyterVariables, JupyterVariables); | 55 | 58 | serviceManager.add<ICodeWatcher>(ICodeWatcher, CodeWatcher); | 56 | 59 | serviceManager.add<IJupyterCommandFactory>(IJupyterCommandFactory, JupyterCommandFactory); | 57 | 60 | } |
|