Skip to content

Commit f523170

Browse files
authored
Merge pull request #214 from extrabacon/fix_stderr_being_emitted_in_binary_mode
Fix stderr being emitted in binary mode & other misc changes
2 parents f90f5e5 + e4662ae commit f523170

File tree

5 files changed

+42
-21
lines changed

5 files changed

+42
-21
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -281,9 +281,9 @@ Parses incoming logs from the Python script written via stderr and emits `stderr
281281

282282
Closes the stdin stream, allowing the Python script to finish and exit. The optional callback is invoked when the process is terminated.
283283

284-
#### `.terminate(signal)`
284+
#### `.kill(signal)`
285285

286-
Terminates the python script, the optional end callback is invoked if specified. A kill signal may be provided by `signal`, if `signal` is not specified SIGTERM is sent.
286+
Terminates the python script. A kill signal may be provided by `signal`, if `signal` is not specified SIGTERM is sent.
287287

288288
#### event: `message`
289289

index.ts

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ function getRandomInt(){
3737
}
3838

3939
export interface Options extends SpawnOptions{
40+
/**
41+
* if binary is enabled message and stderr events will not be emitted
42+
*/
4043
mode?: 'text'|'json'|'binary'
4144
formatter?: (param:string)=>any
4245
parser?: (param:string)=>any
@@ -147,12 +150,14 @@ export class PythonShell extends EventEmitter{
147150
}
148151

149152
// listen to stderr and emit errors for incoming data
153+
if (this.stderrParser && this.stderr) {
154+
this.stderr.on('data', this.receiveStderr.bind(this));
155+
}
156+
150157
if (this.stderr) {
151158
this.stderr.on('data', function (data) {
152-
errorData += ''+data;
153-
self.receiveStderr(data);
159+
errorData += '' + data;
154160
});
155-
156161
this.stderr.on('end', function(){
157162
self.stderrHasEnded = true;
158163
terminateIfNeeded();
@@ -229,7 +234,6 @@ export class PythonShell extends EventEmitter{
229234

230235
/**
231236
* checks syntax without executing code
232-
* @param {string} code
233237
* @returns {Promise} rejects w/ stderr if syntax failure
234238
*/
235239
static async checkSyntax(code:string){
@@ -251,7 +255,6 @@ export class PythonShell extends EventEmitter{
251255

252256
/**
253257
* checks syntax without executing code
254-
* @param {string} filePath
255258
* @returns {Promise} rejects w/ stderr if syntax failure
256259
*/
257260
static async checkSyntaxFile(filePath:string){
@@ -343,7 +346,6 @@ export class PythonShell extends EventEmitter{
343346
/**
344347
* Sends a message to the Python shell through stdin
345348
* Override this method to format data to be sent to the Python process
346-
* @param {string|Object} data The message to send
347349
* @returns {PythonShell} The same instance for chaining calls
348350
*/
349351
send(message:string|Object) {
@@ -399,7 +401,8 @@ export class PythonShell extends EventEmitter{
399401
}
400402

401403
/**
402-
* Closes the stdin stream, which should cause the process to finish its work and close
404+
* Closes the stdin stream. Unless python is listening for stdin in a loop
405+
* this should cause the process to finish its work and close.
403406
* @returns {PythonShell} The same instance for chaining calls
404407
*/
405408
end(callback:(err:PythonShellError, exitCode:number,exitSignal:string)=>any) {
@@ -411,12 +414,21 @@ export class PythonShell extends EventEmitter{
411414
};
412415

413416
/**
414-
* Closes the stdin stream, which should cause the process to finish its work and close
417+
* Sends a kill signal to the process
415418
* @returns {PythonShell} The same instance for chaining calls
416419
*/
417-
terminate(signal?:string) {
420+
kill(signal?: NodeJS.Signals) {
418421
this.childProcess.kill(signal);
419422
this.terminated = true;
420423
return this;
421424
};
425+
426+
/**
427+
* Alias for kill.
428+
* @deprecated
429+
*/
430+
terminate(signal?: NodeJS.Signals) {
431+
// todo: remove this next breaking release
432+
return this.kill(signal)
433+
}
422434
};

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "python-shell",
3-
"version": "1.0.8",
3+
"version": "2.0.0",
44
"description": "Run Python scripts from Node.js with simple (but efficient) inter-process communication through stdio",
55
"keywords": [
66
"python"
@@ -13,7 +13,7 @@
1313
"dependencies": {},
1414
"devDependencies": {
1515
"@types/mocha": "^5.2.5",
16-
"@types/node": "^9.3.0",
16+
"@types/node": "^10.5.2",
1717
"mocha": "^5.2.0",
1818
"mocha-appveyor-reporter": "^0.4.0",
1919
"should": "^13.2.1",

test/test-python-shell.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,14 @@ describe('PythonShell', function () {
150150
done();
151151
});
152152
});
153+
it('should run the script and fail with an extended stack trace even when mode is binary', function (done) {
154+
PythonShell.run('error.py', {mode: "binary"}, function (err, results) {
155+
err.should.be.an.Error;
156+
err.exitCode.should.be.exactly(1);
157+
err.stack.should.containEql('----- Python Traceback -----');
158+
done();
159+
});
160+
});
153161
it('should run multiple scripts and fail with an extended stack trace for each of them', function (done) {
154162
let numberOfTimesToRun = 5;
155163
for (let i = 0; i < numberOfTimesToRun; i++) {
@@ -348,7 +356,8 @@ describe('PythonShell', function () {
348356
mode: 'binary'
349357
});
350358
pyshell.receive = function () {
351-
throw new Error('should not emit messages in binary mode');
359+
done('should not emit messages in binary mode');
360+
return undefined
352361
};
353362
pyshell.end(done);
354363
});
@@ -385,12 +394,12 @@ describe('PythonShell', function () {
385394
}).send('hello').send('world').end(done);
386395
});
387396
it('should not be invoked when mode is "binary"', function (done) {
388-
let pyshell = new PythonShell('echo_args.py', {
389-
args: ['hello', 'world'],
397+
let pyshell = new PythonShell('stderrLogging.py', {
390398
mode: 'binary'
391399
});
392400
pyshell.receiveStderr = function () {
393-
throw new Error('should not emit stderr in binary mode');
401+
done('should not emit stderr in binary mode');
402+
return undefined
394403
};
395404
pyshell.end(done);
396405
});

0 commit comments

Comments
 (0)