Skip to content

Commit 6104071

Browse files
committed
Fix magics and comments parsing (#5746)
* Fix magics and comments parsing * Fix mime types without real jupyter
1 parent 5c99a53 commit 6104071

7 files changed

Lines changed: 41 additions & 21 deletions

File tree

news/2 Fixes/5537.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix magics running from a python file.

src/client/datascience/cellMatcher.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ export class CellMatcher {
3232
return this.codeMatchRegEx.test(code);
3333
}
3434

35+
public stripMarkers(code: string) : string {
36+
const lines = code.splitLines({trim: false, removeEmptyEntries: false});
37+
return lines.filter(l => !this.isCode(l) && !this.isMarkdown(l)).join('\n');
38+
}
39+
3540
public exec(code: string) : string | undefined {
3641
let result: RegExpExecArray | null = null;
3742
if (this.codeMatchRegEx.test(code)) {

src/client/datascience/common.ts

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,13 @@ export function concatMultilineString(str: nbformat.MultilineString): string {
2424
}
2525

2626
// Strip out comment lines from code
27-
export function stripComments(str: nbformat.MultilineString): nbformat.MultilineString {
28-
if (Array.isArray(str)) {
29-
return extractNonComments(str);
30-
} else {
31-
return extractNonComments([str]);
32-
}
27+
export function stripComments(str: string): string {
28+
let result: string = '';
29+
parseForComments(
30+
str.splitLines({trim: false, removeEmptyEntries: false}),
31+
(_s) => noop,
32+
(s) => result = result.concat(`${s}\n`));
33+
return result;
3334
}
3435

3536
export function formatStreamText(str: string): string {
@@ -77,6 +78,7 @@ export function generateMarkdownFromCodeLines(lines: string[]) {
7778
return appendLineFeed(extractComments(lines.slice(1)));
7879
}
7980

81+
// tslint:disable-next-line: cyclomatic-complexity
8082
export function parseForComments(
8183
lines: string[],
8284
foundCommentLine: (s: string, i: number) => void,
@@ -109,15 +111,20 @@ export function parseForComments(
109111
}
110112
// Not inside either, see if starting a quote
111113
} else if (isMultilineQuote && !isMultilineComment) {
112-
insideMultilineQuote = isMultilineQuote;
114+
// Make sure doesn't begin and end on the same line.
115+
const beginQuote = trim.indexOf(isMultilineQuote);
116+
const endQuote = trim.lastIndexOf(isMultilineQuote);
117+
insideMultilineQuote = endQuote !== beginQuote ? undefined : isMultilineQuote;
113118
foundNonCommentLine(l, pos);
114119
// Not starting a quote, might be starting a comment
115120
} else if (isMultilineComment) {
116-
insideMultilineComment = isMultilineComment;
121+
// See if this line ends the comment too or not
122+
const endIndex = trim.indexOf(isMultilineComment, 3);
123+
insideMultilineComment = endIndex >= 0 ? undefined : isMultilineComment;
117124

118125
// Might end with text too
119126
if (trim.length > 3) {
120-
foundCommentLine(trim.slice(3), pos);
127+
foundCommentLine(trim.slice(3, endIndex >= 0 ? endIndex : undefined), pos);
121128
}
122129
} else {
123130
// Normal line
@@ -136,9 +143,3 @@ function extractComments(lines: string[]): string[] {
136143
parseForComments(lines, (s) => result.push(s), (_s) => noop());
137144
return result;
138145
}
139-
140-
function extractNonComments(lines: string[]): string[] {
141-
const result: string[] = [];
142-
parseForComments(lines, (_s) => noop, (s) => result.push(s));
143-
return result;
144-
}

src/client/datascience/jupyter/jupyterServer.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { createDeferred, Deferred, sleep } from '../../common/utils/async';
2121
import * as localize from '../../common/utils/localize';
2222
import { noop } from '../../common/utils/misc';
2323
import { generateCells } from '../cellFactory';
24+
import { CellMatcher } from '../cellMatcher';
2425
import { concatMultilineString } from '../common';
2526
import { Identifiers } from '../constants';
2627
import {
@@ -514,10 +515,11 @@ export class JupyterServerBase implements INotebookServer {
514515
private generateRequest = (code: string, silent?: boolean): Kernel.IFuture | undefined => {
515516
//this.logger.logInformation(`Executing code in jupyter : ${code}`)
516517
try {
518+
const cellMatcher = new CellMatcher(this.configService.getSettings().datascience);
517519
return this.session ? this.session.requestExecute(
518520
{
519-
// Replace windows line endings with unix line endings.
520-
code: code.replace(/\r\n/g, '\n'),
521+
// Remove the cell marker if we have one.
522+
code: cellMatcher.stripMarkers(code),
521523
stop_on_error: false,
522524
allow_stdin: false,
523525
store_history: !silent // Silent actually means don't output anything. Store_history is what affects execution_count

src/test/datascience/datascience.unit.test.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import { assert } from 'chai';
55

66
import { generateCells } from '../../client/datascience/cellFactory';
7-
import { formatStreamText } from '../../client/datascience/common';
7+
import { formatStreamText, stripComments } from '../../client/datascience/common';
88
import { InputHistory } from '../../datascience-ui/history-react/inputHistory';
99

1010
// tslint:disable: max-func-body-length
@@ -219,5 +219,14 @@ class Pizza(object):
219219
assert.equal(cells[1].data.cell_type, 'code', 'code cell not generated');
220220
assert.equal(cells[1].data.source.length, 7, 'Lines for code not emitted');
221221
assert.equal(cells[1].data.source[3], ' self.toppings = toppings\n', 'Lines for cell not emitted');
222+
223+
// Non comments tests
224+
let nonComments = stripComments(multilineCode);
225+
assert.ok(nonComments.startsWith('myvar = """ # Lorem Ipsum'), 'Variable set to multiline string not working');
226+
nonComments = stripComments(multilineTwo);
227+
assert.equal(nonComments, '', 'Multline comment is not being stripped');
228+
nonComments = stripComments(multilineQuoteInFunc);
229+
assert.equal(nonComments.splitLines().length, 6, 'Splitting quote in func wrong number of lines');
222230
});
231+
223232
});

src/test/datascience/mockJupyterManager.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { ExecutionResult, IProcessServiceFactory, IPythonExecutionFactory, Outpu
1717
import { IAsyncDisposableRegistry, IConfigurationService } from '../../client/common/types';
1818
import { EXTENSION_ROOT_DIR } from '../../client/constants';
1919
import { generateCells } from '../../client/datascience/cellFactory';
20+
import { CellMatcher } from '../../client/datascience/cellMatcher';
2021
import { concatMultilineString } from '../../client/datascience/common';
2122
import { Identifiers } from '../../client/datascience/constants';
2223
import {
@@ -192,7 +193,8 @@ export class MockJupyterManager implements IJupyterSessionManager {
192193
public addCell(code: string, result?: undefined | string | number | nbformat.IUnrecognizedOutput | nbformat.IExecuteResult | nbformat.IDisplayData | nbformat.IStream | nbformat.IError, mimeType?: string) {
193194
const cells = generateCells(undefined, code, 'foo.py', 1, true, uuid());
194195
cells.forEach(c => {
195-
const key = concatMultilineString(c.data.source).replace(LineFeedRegEx, '');
196+
const cellMatcher = new CellMatcher();
197+
const key = cellMatcher.stripMarkers(concatMultilineString(c.data.source)).replace(LineFeedRegEx, '');
196198
if (c.data.cell_type === 'code') {
197199
const massagedResult = this.massageCellResult(result, mimeType);
198200
const data: nbformat.ICodeCell = c.data as nbformat.ICodeCell;

src/test/datascience/notebook.functional.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -661,10 +661,10 @@ df.head()`,
661661
},
662662
{
663663
// Important to test as multiline cell magics only work if they are the first item in the cell
664-
// Doesn't work with a comment though.
665664
markdownRegEx: undefined,
666665
code:
667-
`%%bash
666+
`#%%
667+
%%bash
668668
echo 'hello'`,
669669
mimeType: 'text/plain',
670670
cellType: 'code',

0 commit comments

Comments
 (0)