Skip to content

Commit 9008938

Browse files
authored
Fixes to for escaping of output in native notebooks (#14159) (#156)
1 parent 1e9b08c commit 9008938

File tree

2 files changed

+51
-15
lines changed

2 files changed

+51
-15
lines changed

src/client/datascience/jupyter/kernels/cellExecution.ts

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,6 @@ import {
3838
import { IKernel } from './types';
3939
// tslint:disable-next-line: no-var-requires no-require-imports
4040
const vscodeNotebookEnums = require('vscode') as typeof import('vscode-proposed');
41-
// tslint:disable-next-line: no-require-imports
42-
import escape = require('lodash/escape');
4341

4442
export class CellExecutionFactory {
4543
constructor(
@@ -458,11 +456,6 @@ export class CellExecution {
458456
// See this for docs on the messages:
459457
// https://jupyter-client.readthedocs.io/en/latest/messaging.html#messaging-in-jupyter
460458
private async handleExecuteResult(msg: KernelMessage.IExecuteResultMsg, clearState: RefBool) {
461-
// Escape text output
462-
if (msg.content.data && msg.content.data.hasOwnProperty('text/plain')) {
463-
msg.content.data['text/plain'] = escape(msg.content.data['text/plain'] as string);
464-
}
465-
466459
await this.addToCellData(
467460
{
468461
output_type: 'execute_result',
@@ -487,7 +480,7 @@ export class CellExecution {
487480
// Mark as stream output so the text is formatted because it likely has ansi codes in it.
488481
output_type: 'stream',
489482
// tslint:disable-next-line: no-any
490-
text: escape((o.data as any)['text/plain'].toString()),
483+
text: (o.data as any)['text/plain'].toString(),
491484
name: 'stdout',
492485
metadata: {},
493486
execution_count: reply.execution_count
@@ -528,11 +521,11 @@ export class CellExecution {
528521
if (existing && 'text/plain' in existing.data) {
529522
// tslint:disable-next-line:restrict-plus-operands
530523
existing.data['text/plain'] = formatStreamText(
531-
concatMultilineString(`${existing.data['text/plain']}${escape(msg.content.text)}`)
524+
concatMultilineString(`${existing.data['text/plain']}${msg.content.text}`)
532525
);
533526
edit.replaceCellOutput(this.cellIndex, [...exitingCellOutput]); // This is necessary to get VS code to update (for now)
534527
} else {
535-
const originalText = formatStreamText(concatMultilineString(escape(msg.content.text)));
528+
const originalText = formatStreamText(concatMultilineString(msg.content.text));
536529
// Create a new stream entry
537530
const output: nbformat.IStream = {
538531
output_type: 'stream',
@@ -545,11 +538,6 @@ export class CellExecution {
545538
}
546539

547540
private async handleDisplayData(msg: KernelMessage.IDisplayDataMsg, clearState: RefBool) {
548-
// Escape text output
549-
if (msg.content.data && msg.content.data.hasOwnProperty('text/plain')) {
550-
msg.content.data['text/plain'] = escape(msg.content.data['text/plain'] as string);
551-
}
552-
553541
const output: nbformat.IDisplayData = {
554542
output_type: 'display_data',
555543
data: msg.content.data,

src/test/datascience/notebook/executionService.vscode.test.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,4 +343,52 @@ suite('DataScience - VSCode Notebook - (Execution) (slow)', function () {
343343
'Incorrect output'
344344
);
345345
});
346+
test('Verify escaping of output', async () => {
347+
await insertPythonCellAndWait('1');
348+
await insertPythonCellAndWait(dedent`
349+
a="<a href=f>"
350+
a`);
351+
await insertPythonCellAndWait(dedent`
352+
a="<a href=f>"
353+
print(a)`);
354+
await insertPythonCellAndWait('raise Exception("<whatever>")');
355+
const cells = vscodeNotebook.activeNotebookEditor?.document.cells!;
356+
357+
await executeActiveDocument();
358+
359+
// Wait till execution count changes and status is error.
360+
await waitForCondition(
361+
async () => assertHasExecutionCompletedWithErrors(cells[3]),
362+
15_000,
363+
'Cell did not get executed'
364+
);
365+
366+
for (const cell of cells) {
367+
assert.lengthOf(cell.outputs, 1, 'Incorrect output');
368+
}
369+
assert.equal(
370+
cells[0].outputs[0].outputKind,
371+
vscodeNotebookEnums.CellOutputKind.Rich,
372+
'Incorrect output for first cell'
373+
);
374+
assert.equal(
375+
cells[1].outputs[0].outputKind,
376+
vscodeNotebookEnums.CellOutputKind.Rich,
377+
'Incorrect output for first cell'
378+
);
379+
assert.equal(
380+
cells[2].outputs[0].outputKind,
381+
vscodeNotebookEnums.CellOutputKind.Rich,
382+
'Incorrect output for first cell'
383+
);
384+
assertHasTextOutputInVSCode(cells[0], '1');
385+
assertHasTextOutputInVSCode(cells[1], '<a href=f>', 0, false);
386+
assertHasTextOutputInVSCode(cells[2], '<a href=f>', 0, false);
387+
const errorOutput = cells[3].outputs[0] as CellErrorOutput;
388+
assert.equal(errorOutput.outputKind, vscodeNotebookEnums.CellOutputKind.Error, 'Incorrect output');
389+
assert.equal(errorOutput.ename, 'Exception', 'Incorrect ename'); // As status contains ename, we don't want this displayed again.
390+
assert.equal(errorOutput.evalue, '<whatever>', 'Incorrect evalue'); // As status contains ename, we don't want this displayed again.
391+
assert.isNotEmpty(errorOutput.traceback, 'Incorrect traceback');
392+
assert.include(errorOutput.traceback.join(''), '<whatever>');
393+
});
346394
});

0 commit comments

Comments
 (0)