From 2d793336ff3b6f4b4f9139cd0f2045e9d92f6861 Mon Sep 17 00:00:00 2001 From: Alce Ops Date: Tue, 28 Apr 2026 14:18:45 +0000 Subject: [PATCH] fix: parse tracebacks after stderr prefixes --- index.ts | 11 +++++++---- test/python/error_with_stderr_prefix.py | 10 ++++++++++ test/test-python-shell.ts | 9 +++++++++ 3 files changed, 26 insertions(+), 4 deletions(-) create mode 100644 test/python/error_with_stderr_prefix.py diff --git a/index.ts b/index.ts index 9569354..4a8bd1e 100644 --- a/index.ts +++ b/index.ts @@ -395,13 +395,16 @@ export class PythonShell extends EventEmitter { private parseError(data: string | Buffer) { let text = '' + data; let error: PythonShellError; + const tracebackHeader = 'Traceback (most recent call last):'; + const tracebackStart = text.indexOf(tracebackHeader); - if (/^Traceback/.test(text)) { - // traceback data is available - let lines = text.trim().split(newline); + if (tracebackStart >= 0) { + // Traceback can be prefixed by stderr logs, so parse from the traceback header. + const tracebackText = text.slice(tracebackStart).trim(); + let lines = tracebackText.split(newline); let exception = lines.pop(); error = new PythonShellError(exception); - error.traceback = data; + error.traceback = tracebackText; // extend stack trace error.stack += newline + ' ----- Python Traceback -----' + newline + ' '; diff --git a/test/python/error_with_stderr_prefix.py b/test/python/error_with_stderr_prefix.py new file mode 100644 index 0000000..457d543 --- /dev/null +++ b/test/python/error_with_stderr_prefix.py @@ -0,0 +1,10 @@ +import sys + +sys.stderr.write('prefix log before traceback\n') + + +def fail(): + raise Exception('Error sample') + + +fail() diff --git a/test/test-python-shell.ts b/test/test-python-shell.ts index 3d5de81..bd7c8bf 100644 --- a/test/test-python-shell.ts +++ b/test/test-python-shell.ts @@ -614,6 +614,15 @@ describe('PythonShell', function () { done(); }); }); + it('should parse traceback when stderr has prefixed logs', function (done) { + let pyshell = new PythonShell('error_with_stderr_prefix.py'); + pyshell.on('pythonError', function (err) { + err.message.should.be.equal('Exception: Error sample'); + err.should.have.property('traceback'); + err.traceback.should.containEql('Traceback (most recent call last)'); + done(); + }); + }); }); describe('.kill()', function () {