Skip to content

Commit f91833c

Browse files
authored
Merge pull request #79 from brucedjones/master
terminate() function
2 parents 0daee5f + 2c2b7e4 commit f91833c

File tree

4 files changed

+61
-10
lines changed

4 files changed

+61
-10
lines changed

README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,11 @@ pyshell.on('message', function (message) {
7171
});
7272

7373
// end the input stream and allow the process to exit
74-
pyshell.end(function (err) {
74+
pyshell.end(function (err,code,signal) {
7575
if (err) throw err;
76+
console.log('The exit code was: ' + code);
77+
console.log('The exit signal was: ' + signal);
78+
console.log('finished');
7679
console.log('finished');
7780
});
7881
```
@@ -209,6 +212,10 @@ Parses incoming data from the Python script written via stdout and emits `messag
209212

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

215+
#### `.terminate(signal)`
216+
217+
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.
218+
212219
#### event: `message`
213220

214221
Fires when a chunk of data is parsed from the stdout stream via the `receive` method. If a `parser` method is specified, the result of this function will be the message value. This event is not emitted in binary mode.

index.js

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -83,17 +83,17 @@ var PythonShell = function (script, options) {
8383
terminateIfNeeded();
8484
})
8585

86-
this.childProcess.on('exit', function (code) {
86+
this.childProcess.on('exit', function (code,signal) {
8787
self.exitCode = code;
88+
self.exitSignal = signal;
8889
terminateIfNeeded();
8990
});
9091

9192
function terminateIfNeeded() {
92-
if (!self.stderrHasEnded || !self.stdoutHasEnded || self.exitCode == null) {
93-
return;
94-
}
93+
if(!self.stderrHasEnded || !self.stdoutHasEnded || (self.exitCode == null && self.exitSignal == null)) return;
94+
9595
var err;
96-
if (errorData || self.exitCode !== 0) {
96+
if (errorData || (self.exitCode && self.exitCode !== 0)) {
9797
if (errorData) {
9898
err = self.parseError(errorData);
9999
} else {
@@ -111,10 +111,11 @@ var PythonShell = function (script, options) {
111111
self.emit('error', err);
112112
}
113113
}
114+
114115
self.terminated = true;
115116
self.emit('close');
116-
self._endCallback && self._endCallback(err);
117-
}
117+
self._endCallback && self._endCallback(err,self.exitCode,self.exitSignal);
118+
};
118119
};
119120
util.inherits(PythonShell, EventEmitter);
120121

@@ -245,4 +246,14 @@ PythonShell.prototype.end = function (callback) {
245246
return this;
246247
};
247248

249+
/**
250+
* Closes the stdin stream, which should cause the process to finish its work and close
251+
* @returns {PythonShell} The same instance for chaining calls
252+
*/
253+
PythonShell.prototype.terminate = function (signal) {
254+
this.childProcess.kill(signal);
255+
this.terminated = true;
256+
return this;
257+
};
258+
248259
module.exports = PythonShell;

test/python/infinite_loop.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
a = 0
2+
while(True):
3+
a += 1

test/test-python-shell.js

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -238,9 +238,9 @@ describe('PythonShell', function () {
238238
describe('.end(callback)', function () {
239239
it('should end normally when exit code is zero', function (done) {
240240
var pyshell = new PythonShell('exit-code.py');
241-
pyshell.end(function (err) {
241+
pyshell.end(function (err,code,signal) {
242242
if (err) return done(err);
243-
pyshell.exitCode.should.be.exactly(0);
243+
code.should.be.exactly(0);
244244
done();
245245
});
246246
});
@@ -287,4 +287,34 @@ describe('PythonShell', function () {
287287
});
288288
});
289289
});
290+
291+
describe('.terminate()', function () {
292+
it('set terminated to true', function (done) {
293+
var pyshell = new PythonShell('infinite_loop.py');
294+
pyshell.terminate();
295+
pyshell.terminated.should.be.true
296+
done();
297+
});
298+
it('run the end callback if specified', function (done) {
299+
var pyshell = new PythonShell('infinite_loop.py');
300+
var endCalled = false;
301+
pyshell.end(()=>{
302+
endCalled = true;
303+
})
304+
pyshell.terminate();
305+
pyshell.terminated.should.be.true
306+
done();
307+
});
308+
it('terminate with correct kill signal', function (done) {
309+
var pyshell = new PythonShell('infinite_loop.py');
310+
var endCalled = false;
311+
pyshell.end(()=>{
312+
endCalled = true;
313+
})
314+
pyshell.terminate('SIGKILL');
315+
pyshell.terminated.should.be.true;
316+
setTimeout(()=>{pyshell.exitSignal.should.be.exactly('SIGKILL');},500);
317+
done();
318+
});
319+
});
290320
});

0 commit comments

Comments
 (0)