Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,11 @@ pyshell.on('message', function (message) {
});

// end the input stream and allow the process to exit
pyshell.end(function (err) {
pyshell.end(function (err,code,signal) {
if (err) throw err;
console.log('The exit code was: ' + code);
console.log('The exit signal was: ' + signal);
console.log('finished');
console.log('finished');
});
```
Expand Down Expand Up @@ -209,6 +212,10 @@ Parses incoming data from the Python script written via stdout and emits `messag

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

#### `.terminate(signal)`

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.

#### event: `message`

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.
Expand Down
25 changes: 18 additions & 7 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,17 +83,17 @@ var PythonShell = function (script, options) {
terminateIfNeeded();
})

this.childProcess.on('exit', function (code) {
this.childProcess.on('exit', function (code,signal) {
self.exitCode = code;
self.exitSignal = signal;
terminateIfNeeded();
});

function terminateIfNeeded() {
if (!self.stderrHasEnded || !self.stdoutHasEnded || self.exitCode == null) {
return;
}
if(!self.stderrHasEnded || !self.stdoutHasEnded || (self.exitCode == null && self.exitSignal == null)) return;

var err;
if (errorData || self.exitCode !== 0) {
if (errorData || (self.exitCode && self.exitCode !== 0)) {
if (errorData) {
err = self.parseError(errorData);
} else {
Expand All @@ -111,10 +111,11 @@ var PythonShell = function (script, options) {
self.emit('error', err);
}
}

self.terminated = true;
self.emit('close');
self._endCallback && self._endCallback(err);
}
self._endCallback && self._endCallback(err,self.exitCode,self.exitSignal);
};
};
util.inherits(PythonShell, EventEmitter);

Expand Down Expand Up @@ -245,4 +246,14 @@ PythonShell.prototype.end = function (callback) {
return this;
};

/**
* Closes the stdin stream, which should cause the process to finish its work and close
* @returns {PythonShell} The same instance for chaining calls
*/
PythonShell.prototype.terminate = function (signal) {
this.childProcess.kill(signal);
this.terminated = true;
return this;
};

module.exports = PythonShell;
3 changes: 3 additions & 0 deletions test/python/infinite_loop.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
a = 0
while(True):
a += 1
34 changes: 32 additions & 2 deletions test/test-python-shell.js
Original file line number Diff line number Diff line change
Expand Up @@ -238,9 +238,9 @@ describe('PythonShell', function () {
describe('.end(callback)', function () {
it('should end normally when exit code is zero', function (done) {
var pyshell = new PythonShell('exit-code.py');
pyshell.end(function (err) {
pyshell.end(function (err,code,signal) {
if (err) return done(err);
pyshell.exitCode.should.be.exactly(0);
code.should.be.exactly(0);
done();
});
});
Expand Down Expand Up @@ -287,4 +287,34 @@ describe('PythonShell', function () {
});
});
});

describe('.terminate()', function () {
it('set terminated to true', function (done) {
var pyshell = new PythonShell('infinite_loop.py');
pyshell.terminate();
pyshell.terminated.should.be.true
done();
});
it('run the end callback if specified', function (done) {
var pyshell = new PythonShell('infinite_loop.py');
var endCalled = false;
pyshell.end(()=>{
endCalled = true;
})
pyshell.terminate();
pyshell.terminated.should.be.true
done();
});
it('terminate with correct kill signal', function (done) {
var pyshell = new PythonShell('infinite_loop.py');
var endCalled = false;
pyshell.end(()=>{
endCalled = true;
})
pyshell.terminate('SIGKILL');
pyshell.terminated.should.be.true;
setTimeout(()=>{pyshell.exitSignal.should.be.exactly('SIGKILL');},500);
done();
});
});
});