Skip to content

Commit acd7a3d

Browse files
authored
Save python version info in metadata when running cells (#8225)
* Store python version * News * Remove blank lines
1 parent c831ce6 commit acd7a3d

File tree

3 files changed

+62
-4
lines changed

3 files changed

+62
-4
lines changed

news/2 Fixes/8064.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Store version of the `Python` interpreter (kernel) in the notebook metadata when running cells.

src/client/datascience/interactive-ipynb/nativeEditor.ts

+21-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import * as detectIndent from 'detect-indent';
88
import { inject, injectable, multiInject, named } from 'inversify';
99
import * as path from 'path';
1010
import * as uuid from 'uuid/v4';
11-
import { Event, EventEmitter, Memento, Uri, ViewColumn } from 'vscode';
11+
import { Event, EventEmitter, Memento, TextEditor, Uri, ViewColumn } from 'vscode';
1212

1313
import {
1414
IApplicationShell,
@@ -310,6 +310,12 @@ export class NativeEditor extends InteractiveBase implements INotebookEditor {
310310
}
311311
}
312312

313+
protected submitCode(code: string, file: string, line: number, id?: string, editor?: TextEditor, debug?: boolean): Promise<boolean> {
314+
// When code is executed, update the version number in the metadata.
315+
this.updateVersionInfoInNotebook().ignoreErrors();
316+
return super.submitCode(code, file, line, id, editor, debug);
317+
}
318+
313319
@captureTelemetry(Telemetry.SubmitCellThroughInput, undefined, false)
314320
// tslint:disable-next-line:no-any
315321
protected submitNewCell(info: ISubmitNewCell) {
@@ -455,6 +461,20 @@ export class NativeEditor extends InteractiveBase implements INotebookEditor {
455461
// Actually don't close, just let the error bubble out
456462
}
457463

464+
/**
465+
* Update the Python Version number in the notebook data.
466+
*
467+
* @private
468+
* @memberof NativeEditor
469+
*/
470+
private async updateVersionInfoInNotebook(): Promise<void>{
471+
// Use the active interpreter
472+
const usableInterpreter = await this.jupyterExecution.getUsableJupyterPython();
473+
if (usableInterpreter && usableInterpreter.version && this.notebookJson.metadata && this.notebookJson.metadata.language_info){
474+
this.notebookJson.metadata.language_info.version = `${usableInterpreter.version.major}.${usableInterpreter.version.minor}.${usableInterpreter.version.patch}`;
475+
}
476+
}
477+
458478
private async loadContents(contents: string | undefined, forceDirty: boolean): Promise<void> {
459479
// tslint:disable-next-line: no-any
460480
const json = contents ? JSON.parse(contents) as any : undefined;

src/test/datascience/interactive-ipynb/nativeEditor.unit.test.ts

+40-3
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22
// Licensed under the MIT License.
33
'use strict';
44
import { expect } from 'chai';
5-
import { anything, instance, mock, when } from 'ts-mockito';
5+
import { anything, instance, mock, verify, when } from 'ts-mockito';
66
import { ConfigurationChangeEvent, Disposable, EventEmitter, TextEditor, Uri } from 'vscode';
77

8+
import { nbformat } from '@jupyterlab/coreutils';
89
import * as sinon from 'sinon';
910
import { ApplicationShell } from '../../../client/common/application/applicationShell';
1011
import { CommandManager } from '../../../client/common/application/commandManager';
@@ -24,7 +25,7 @@ import { ConfigurationService } from '../../../client/common/configuration/servi
2425
import { LiveShareApi } from '../../../client/common/liveshare/liveshare';
2526
import { FileSystem } from '../../../client/common/platform/fileSystem';
2627
import { IFileSystem } from '../../../client/common/platform/types';
27-
import { IConfigurationService } from '../../../client/common/types';
28+
import { IConfigurationService, Version } from '../../../client/common/types';
2829
import { CodeCssGenerator } from '../../../client/datascience/codeCssGenerator';
2930
import { DataViewerProvider } from '../../../client/datascience/data-viewing/dataViewerProvider';
3031
import { DataScienceErrorHandler } from '../../../client/datascience/errorHandler/errorHandler';
@@ -55,6 +56,7 @@ import { IInterpreterService } from '../../../client/interpreter/contracts';
5556
import { InterpreterService } from '../../../client/interpreter/interpreterService';
5657
import { createEmptyCell } from '../../../datascience-ui/interactive-common/mainState';
5758
import { waitForCondition } from '../../common';
59+
import { noop } from '../../core';
5860
import { MockMemento } from '../../mocks/mementos';
5961

6062
// tslint:disable: no-any chai-vague-errors no-unused-expression
@@ -324,7 +326,6 @@ suite('Data Science - Native Editor', () => {
324326

325327
return editor;
326328
}
327-
328329
test('Editing a notebook will save uncommitted changes into memento', async () => {
329330
const file = Uri.parse('file://foo.ipynb');
330331

@@ -416,4 +417,40 @@ suite('Data Science - Native Editor', () => {
416417
expect(newEditor.contents).to.be.equal(baseFile);
417418
expect(newEditor.cells).to.be.lengthOf(3);
418419
});
420+
421+
test('Pyton version info will be updated in notebook when a cell has been executed', async () => {
422+
const file = Uri.parse('file://foo.ipynb');
423+
424+
const editor = createEditor();
425+
await editor.load(baseFile, file);
426+
expect(editor.contents).to.be.equal(baseFile);
427+
// At the begining version info is NOT in the file (at least not the same as what we are using to run cells).
428+
let contents = JSON.parse(editor.contents) as nbformat.INotebookContent;
429+
expect(contents.metadata!.language_info!.version).to.not.equal('10.11.12');
430+
431+
// When a cell is executed, then ensure we store the python version info in the notebook data.
432+
const version: Version = {build: [], major: 10, minor: 11, patch: 12, prerelease: [], raw: '10.11.12'};
433+
when(executionProvider.getUsableJupyterPython()).thenResolve(({version} as any));
434+
435+
try {
436+
editor.onMessage(InteractiveWindowMessages.SubmitNewCell, {code: 'hello', id: '1'});
437+
} catch {
438+
// Ignore errors related to running cells, assume that works.
439+
noop();
440+
}
441+
442+
// Wait for the version info to be retrieved (done in the background).
443+
await waitForCondition(async () => {
444+
try {
445+
verify(executionProvider.getUsableJupyterPython()).atLeast(1);
446+
return true;
447+
} catch {
448+
return false;
449+
}
450+
}, 5_000, 'Timeout');
451+
452+
// Verify the version info is in the notbook.
453+
contents = JSON.parse(editor.contents) as nbformat.INotebookContent;
454+
expect(contents.metadata!.language_info!.version).to.equal('10.11.12');
455+
});
419456
});

0 commit comments

Comments
 (0)