Skip to content

Commit e157ced

Browse files
committed
Fix converting from a python script (#8699)
* Fix converting from a python script * Fix linter error
1 parent b6a8a28 commit e157ced

File tree

6 files changed

+54
-34
lines changed

6 files changed

+54
-34
lines changed

news/2 Fixes/8677.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Converting to python script no longer working from a notebook.

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -791,7 +791,7 @@ export class NativeEditor extends InteractiveBase implements INotebookEditor {
791791
tempFile = await this.fileSystem.createTemporaryFile('.ipynb');
792792

793793
// Translate the cells into a notebook
794-
await this.fileSystem.writeFile(tempFile.filePath, this.generateNotebookContent(cells), { encoding: 'utf-8' });
794+
await this.fileSystem.writeFile(tempFile.filePath, await this.generateNotebookContent(cells), { encoding: 'utf-8' });
795795

796796
// Import this file and show it
797797
const contents = await this.importer.importFromFile(tempFile.filePath, this.file.fsPath);

src/client/datascience/jupyter/jupyterImporter.ts

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT License.
33
'use strict';
4+
import '../../common/extensions';
5+
46
import { nbformat } from '@jupyterlab/coreutils';
57
import * as fs from 'fs-extra';
68
import { inject, injectable } from 'inversify';
79
import * as os from 'os';
810
import * as path from 'path';
9-
import '../../common/extensions';
1011

1112
import { IWorkspaceService } from '../../common/application/types';
13+
import { traceError } from '../../common/logger';
1214
import { IFileSystem, IPlatformService } from '../../common/platform/types';
1315
import { IConfigurationService, IDisposableRegistry } from '../../common/types';
1416
import * as localize from '../../common/utils/localize';
@@ -138,35 +140,39 @@ export class JupyterImporter implements INotebookImporter {
138140
// When importing a file, calculate if we can create a %cd so that the relative paths work
139141
private async calculateDirectoryChange(notebookFile: string): Promise<string | undefined> {
140142
let directoryChange: string | undefined;
141-
// Make sure we don't already have an import/export comment in the file
142-
const contents = await this.fileSystem.readFile(notebookFile);
143-
const haveChangeAlready = contents.includes(CodeSnippits.ChangeDirectoryCommentIdentifier);
144-
145-
if (!haveChangeAlready) {
146-
const notebookFilePath = path.dirname(notebookFile);
147-
// First see if we have a workspace open, this only works if we have a workspace root to be relative to
148-
if (this.workspaceService.hasWorkspaceFolders) {
149-
const workspacePath = this.workspaceService.workspaceFolders![0].uri.fsPath;
150-
151-
// Make sure that we have everything that we need here
152-
if (workspacePath && path.isAbsolute(workspacePath) && notebookFilePath && path.isAbsolute(notebookFilePath)) {
153-
directoryChange = path.relative(workspacePath, notebookFilePath);
143+
try {
144+
// Make sure we don't already have an import/export comment in the file
145+
const contents = await this.fileSystem.readFile(notebookFile);
146+
const haveChangeAlready = contents.includes(CodeSnippits.ChangeDirectoryCommentIdentifier);
147+
148+
if (!haveChangeAlready) {
149+
const notebookFilePath = path.dirname(notebookFile);
150+
// First see if we have a workspace open, this only works if we have a workspace root to be relative to
151+
if (this.workspaceService.hasWorkspaceFolders) {
152+
const workspacePath = this.workspaceService.workspaceFolders![0].uri.fsPath;
153+
154+
// Make sure that we have everything that we need here
155+
if (workspacePath && path.isAbsolute(workspacePath) && notebookFilePath && path.isAbsolute(notebookFilePath)) {
156+
directoryChange = path.relative(workspacePath, notebookFilePath);
157+
}
154158
}
155159
}
156-
}
157160

158-
// If path.relative can't calculate a relative path, then it just returns the full second path
159-
// so check here, we only want this if we were able to calculate a relative path, no network shares or drives
160-
if (directoryChange && !path.isAbsolute(directoryChange)) {
161+
// If path.relative can't calculate a relative path, then it just returns the full second path
162+
// so check here, we only want this if we were able to calculate a relative path, no network shares or drives
163+
if (directoryChange && !path.isAbsolute(directoryChange)) {
161164

162-
// Escape windows path chars so they end up in the source escaped
163-
if (this.platform.isWindows) {
164-
directoryChange = directoryChange.replace('\\', '\\\\');
165-
}
165+
// Escape windows path chars so they end up in the source escaped
166+
if (this.platform.isWindows) {
167+
directoryChange = directoryChange.replace('\\', '\\\\');
168+
}
166169

167-
return directoryChange;
168-
} else {
169-
return undefined;
170+
return directoryChange;
171+
} else {
172+
return undefined;
173+
}
174+
} catch (e) {
175+
traceError(e);
170176
}
171177
}
172178

src/test/datascience/liveshare.functional.test.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import {
2525
IJupyterExecution
2626
} from '../../client/datascience/types';
2727
import { InteractivePanel } from '../../datascience-ui/history-react/interactivePanel';
28-
import { asyncDump } from '../common/asyncDump';
28+
//import { asyncDump } from '../common/asyncDump';
2929
import { DataScienceIocContainer } from './dataScienceIocContainer';
3030
import { createDocument } from './editor-integration/helpers';
3131
import { waitForUpdate } from './reactHelpers';
@@ -62,7 +62,7 @@ suite('DataScience LiveShare tests', () => {
6262
});
6363

6464
suiteTeardown(() => {
65-
asyncDump();
65+
//asyncDump();
6666
});
6767

6868
function createContainer(role: vsls.Role): DataScienceIocContainer {

src/test/datascience/mockJupyterManager.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ export class MockJupyterManager implements IJupyterSessionManager {
401401
this.setupPythonServiceExec(service, 'jupyter', ['nbconvert', '--version'], () => Promise.resolve({ stdout: '1.1.1.1' }));
402402
this.setupPythonServiceExec(service, 'jupyter', ['nbconvert', /.*/, '--to', 'python', '--stdout', '--template', /.*/], () => {
403403
return Promise.resolve({
404-
stdout: '#%%\r\nimport os\r\nos.chdir()'
404+
stdout: '#%%\r\nimport os\r\nos.chdir()\r\n#%%\r\na=1'
405405
});
406406
});
407407
}

src/test/datascience/nativeEditor.functional.test.tsx

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -226,17 +226,17 @@ for _ in range(50):
226226
assert.equal(afterDelete.length, 1, `Delete should NOT remove the last cell`);
227227
}, () => { return ioc; });
228228

229-
runMountedTest('Export', async (wrapper) => {
229+
runMountedTest('Convert to python', async (wrapper) => {
230230
// Export should cause the export dialog to come up. Remap appshell so we can check
231231
const dummyDisposable = {
232232
dispose: () => { return; }
233233
};
234-
let exportCalled = false;
234+
let saveCalled = false;
235235
const appShell = TypeMoq.Mock.ofType<IApplicationShell>();
236236
appShell.setup(a => a.showErrorMessage(TypeMoq.It.isAnyString())).returns((e) => { throw e; });
237237
appShell.setup(a => a.showInformationMessage(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve(''));
238238
appShell.setup(a => a.showSaveDialog(TypeMoq.It.isAny())).returns(() => {
239-
exportCalled = true;
239+
saveCalled = true;
240240
return Promise.resolve(undefined);
241241
});
242242
appShell.setup(a => a.setStatusBarMessage(TypeMoq.It.isAny())).returns(() => dummyDisposable);
@@ -247,9 +247,22 @@ for _ in range(50):
247247
await addCell(wrapper, ioc, 'a=1\na');
248248

249249
// Export should cause exportCalled to change to true
250-
const exportButton = findButton(wrapper, NativeEditor, 8);
250+
const saveButton = findButton(wrapper, NativeEditor, 8);
251+
await waitForMessageResponse(ioc, () => saveButton!.simulate('click'));
252+
assert.equal(saveCalled, true, 'Save should have been called');
253+
254+
// Click export and wait for a document to change
255+
const documentChange = createDeferred();
256+
const docManager = ioc.get<IDocumentManager>(IDocumentManager) as MockDocumentManager;
257+
docManager.onDidChangeTextDocument(() => documentChange.resolve());
258+
const exportButton = findButton(wrapper, NativeEditor, 9);
251259
await waitForMessageResponse(ioc, () => exportButton!.simulate('click'));
252-
assert.equal(exportCalled, true, 'Export should have been called');
260+
await waitForPromise(documentChange.promise, 3000);
261+
// Verify the new document is valid python
262+
const newDoc = docManager.activeTextEditor;
263+
assert.ok(newDoc, 'New doc not created');
264+
assert.ok(newDoc!.document.getText().includes('a=1'), 'Export did not create a python file');
265+
253266
}, () => { return ioc; });
254267

255268
runMountedTest('RunAllCells', async (wrapper) => {

0 commit comments

Comments
 (0)