mirror of
https://github.com/Microsoft/vscode
synced 2024-08-27 04:49:35 +00:00
clean raw jupyter error stack traces
This commit is contained in:
parent
9e36f4c03e
commit
8e8811a5c1
|
@ -7,6 +7,7 @@ import type { ActivationFunction, OutputItem, RendererContext } from 'vscode-not
|
|||
import { createOutputContent, appendOutput, scrollableClass } from './textHelper';
|
||||
import { HtmlRenderingHook, IDisposable, IRichRenderContext, JavaScriptRenderingHook, OutputWithAppend, RenderOptions } from './rendererTypes';
|
||||
import { ttPolicy } from './htmlHelper';
|
||||
import { cleanStackTrace } from './stackTraceHelper';
|
||||
|
||||
function clearContainer(container: HTMLElement) {
|
||||
while (container.firstChild) {
|
||||
|
@ -172,8 +173,10 @@ function renderError(
|
|||
if (err.stack) {
|
||||
outputElement.classList.add('traceback');
|
||||
|
||||
const stackTrace = cleanStackTrace(err.stack);
|
||||
|
||||
const outputScrolling = scrollingEnabled(outputInfo, ctx.settings);
|
||||
const content = createOutputContent(outputInfo.id, err.stack ?? '', { linesLimit: ctx.settings.lineLimit, scrollable: outputScrolling, trustHtml });
|
||||
const content = createOutputContent(outputInfo.id, stackTrace ?? '', { linesLimit: ctx.settings.lineLimit, scrollable: outputScrolling, trustHtml });
|
||||
const contentParent = document.createElement('div');
|
||||
contentParent.classList.toggle('word-wrap', ctx.settings.outputWordWrap);
|
||||
disposableStore.push(ctx.onDidChangeSettings(e => {
|
||||
|
|
26
extensions/notebook-renderers/src/stackTraceHelper.ts
Normal file
26
extensions/notebook-renderers/src/stackTraceHelper.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export function cleanStackTrace(stack: string) {
|
||||
let cleaned: string;
|
||||
// Ansi colors are described here:
|
||||
// https://en.wikipedia.org/wiki/ANSI_escape_code under the SGR section
|
||||
|
||||
// Remove background colors. The ones from IPython don't work well with
|
||||
// themes 40-49 sets background color
|
||||
cleaned = stack.replace(/\u001b\[4\dm/g, '');
|
||||
|
||||
// Also remove specific foreground colors (38 is the ascii code for picking one) (they don't translate either)
|
||||
// Turn them into default foreground
|
||||
cleaned = cleaned.replace(/\u001b\[38;.*?\d+m/g, '\u001b[39m');
|
||||
|
||||
// Turn all foreground colors after the --> to default foreground
|
||||
cleaned = cleaned.replace(/(;32m[ ->]*?)(\d+)(.*)\n/g, (_s, prefix, num, suffix) => {
|
||||
suffix = suffix.replace(/\u001b\[3\d+m/g, '\u001b[39m');
|
||||
return `${prefix}${num}${suffix}\n`;
|
||||
});
|
||||
|
||||
return cleaned;
|
||||
}
|
|
@ -451,5 +451,32 @@ suite('Notebook builtin output renderer', () => {
|
|||
|
||||
assert.equal(settingsChangedHandlers.length, handlerCount);
|
||||
});
|
||||
|
||||
const rawIPythonError = {
|
||||
name: "NameError",
|
||||
message: "name 'x' is not defined",
|
||||
stack: "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m" +
|
||||
"\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)" +
|
||||
"Cell \u001b[1;32mIn[2], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m \u001b[43mmyfunc\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n" +
|
||||
"Cell \u001b[1;32mIn[1], line 2\u001b[0m, in \u001b[0;36mmyfunc\u001b[1;34m()\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mmyfunc\u001b[39m():\n\u001b[1;32m----> 2\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[43mx\u001b[49m)\n" +
|
||||
"\u001b[1;31mNameError\u001b[0m: name 'x' is not defined"
|
||||
};
|
||||
|
||||
test(`Should clean up raw IPython error stack traces`, async () => {
|
||||
LinkDetector.injectedHtmlCreator = (value: string) => value;
|
||||
const context = createContext({ outputWordWrap: true, outputScrolling: true });
|
||||
const renderer = await activate(context);
|
||||
assert.ok(renderer, 'Renderer not created');
|
||||
|
||||
const outputElement = new OutputHtml().getFirstOuputElement();
|
||||
const outputItem = createOutputItem(JSON.stringify(rawIPythonError), errorMimeType);
|
||||
await renderer!.renderOutputItem(outputItem, outputElement);
|
||||
|
||||
const inserted = outputElement.firstChild as HTMLElement;
|
||||
assert.ok(inserted, `nothing appended to output element: ${outputElement.innerHTML}`);
|
||||
//assert.ok(false, `TextContent:\n ${outputElement.textContent}`);
|
||||
assert.ok(outputElement.innerHTML.indexOf('class="code-background-colored"') === -1, `inner HTML:\n ${outputElement.innerHTML}`);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in a new issue