diff --git a/.gitignore b/.gitignore index 2244430..c4ca807 100644 --- a/.gitignore +++ b/.gitignore @@ -2,8 +2,6 @@ node_modules npm-debug.log.* .vscode personal -*.js -*.js.map # DEFAULT PYTHON GITIGNORE @@ -111,4 +109,4 @@ venv.bak/ /site # mypy -.mypy_cache/ \ No newline at end of file +.mypy_cache/ diff --git a/index.js b/index.js new file mode 100644 index 0000000..2a2b885 --- /dev/null +++ b/index.js @@ -0,0 +1,343 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const events_1 = require("events"); +const child_process_1 = require("child_process"); +const os_1 = require("os"); +const path_1 = require("path"); +const fs_1 = require("fs"); +function toArray(source) { + if (typeof source === 'undefined' || source === null) { + return []; + } + else if (!Array.isArray(source)) { + return [source]; + } + return source; +} +/** + * adds arguments as properties to obj + */ +function extend(obj, ...args) { + Array.prototype.slice.call(arguments, 1).forEach(function (source) { + if (source) { + for (let key in source) { + obj[key] = source[key]; + } + } + }); + return obj; +} +class PythonShellError extends Error { +} +/** + * An interactive Python shell exchanging data through stdio + * @param {string} script The python script to execute + * @param {object} [options] The launch options (also passed to child_process.spawn) + * @constructor + */ +class PythonShell extends events_1.EventEmitter { + constructor(scriptPath, options) { + super(); + /** + * returns either pythonshell func (if val string) or custom func (if val Function) + */ + function resolve(type, val) { + if (typeof val === 'string') { + // use a built-in function using its name + return PythonShell[type][val]; + } + else if (typeof val === 'function') { + // use a custom function + return val; + } + } + let self = this; + let errorData = ''; + events_1.EventEmitter.call(this); + options = extend({}, PythonShell.defaultOptions, options); + let pythonPath; + if (!options.pythonPath) { + pythonPath = PythonShell.defaultPythonPath; + } + else + pythonPath = options.pythonPath; + let pythonOptions = toArray(options.pythonOptions); + let scriptArgs = toArray(options.args); + this.scriptPath = path_1.join(options.scriptPath || './', scriptPath); + this.command = pythonOptions.concat(this.scriptPath, scriptArgs); + this.mode = options.mode || 'text'; + this.formatter = resolve('format', options.formatter || this.mode); + this.parser = resolve('parse', options.parser || this.mode); + this.stderrParser = resolve('parse', options.stderrParser || this.mode); + this.terminated = false; + this.childProcess = child_process_1.spawn(pythonPath, this.command, options); + ['stdout', 'stdin', 'stderr'].forEach(function (name) { + self[name] = self.childProcess[name]; + self.parser && self[name].setEncoding(options.encoding || 'utf8'); + }); + // parse incoming data on stdout + if (this.parser) { + this.stdout.on('data', this.receive.bind(this)); + } + // listen to stderr and emit errors for incoming data + this.stderr.on('data', function (data) { + errorData += '' + data; + self.receiveStderr(data); + }); + this.stderr.on('end', function () { + self.stderrHasEnded = true; + terminateIfNeeded(); + }); + this.stdout.on('end', function () { + self.stdoutHasEnded = true; + terminateIfNeeded(); + }); + this.childProcess.on('exit', function (code, signal) { + self.exitCode = code; + self.exitSignal = signal; + terminateIfNeeded(); + }); + function terminateIfNeeded() { + if (!self.stderrHasEnded || !self.stdoutHasEnded || (self.exitCode == null && self.exitSignal == null)) + return; + let err; + if (self.exitCode && self.exitCode !== 0) { + if (errorData) { + err = self.parseError(errorData); + } + else { + err = new PythonShellError('process exited with code ' + self.exitCode); + } + err = extend(err, { + executable: pythonPath, + options: pythonOptions.length ? pythonOptions : null, + script: self.scriptPath, + args: scriptArgs.length ? scriptArgs : null, + exitCode: self.exitCode + }); + // do not emit error if only a callback is used + if (self.listeners('error').length || !self._endCallback) { + self.emit('error', err); + } + } + self.terminated = true; + self.emit('close'); + self._endCallback && self._endCallback(err, self.exitCode, self.exitSignal); + } + ; + } + /** + * checks syntax without executing code + * @param {string} code + * @returns {Promise} rejects w/ stderr if syntax failure + */ + static checkSyntax(code) { + return __awaiter(this, void 0, void 0, function* () { + let randomInt = PythonShell.getRandomInt(); + let filePath = os_1.tmpdir + path_1.sep + `pythonShellSyntaxCheck${randomInt}.py`; + // todo: replace this with util.promisify (once we no longer support node v7) + return new Promise((resolve, reject) => { + fs_1.writeFile(filePath, code, (err) => { + if (err) + reject(err); + resolve(this.checkSyntaxFile(filePath)); + }); + }); + }); + } + /** + * checks syntax without executing code + * @param {string} filePath + * @returns {Promise} rejects w/ stderr if syntax failure + */ + static checkSyntaxFile(filePath) { + return __awaiter(this, void 0, void 0, function* () { + let compileCommand = `${this.defaultPythonPath} -m py_compile ${filePath}`; + return new Promise((resolve, reject) => { + child_process_1.exec(compileCommand, (error, stdout, stderr) => { + if (error == null) + resolve(); + else + reject(stderr); + }); + }); + }); + } + /** + * Runs a Python script and returns collected messages + * @param {string} scriptPath The path to the script to execute + * @param {Options} options The execution options + * @param {Function} callback The callback function to invoke with the script results + * @return {PythonShell} The PythonShell instance + */ + static run(scriptPath, options, callback) { + let pyshell = new PythonShell(scriptPath, options); + let output = []; + return pyshell.on('message', function (message) { + output.push(message); + }).end(function (err) { + if (err) + return callback(err); + return callback(null, output.length ? output : null); + }); + } + ; + /** + * Runs the inputted string of python code and returns collected messages. DO NOT ALLOW UNTRUSTED USER INPUT HERE! + * @param {string} code The python code to execute + * @param {Options} options The execution options + * @param {Function} callback The callback function to invoke with the script results + * @return {PythonShell} The PythonShell instance + */ + static runString(code, options, callback) { + // put code in temp file + let randomInt = PythonShell.getRandomInt(); + let filePath = os_1.tmpdir + path_1.sep + `pythonShellFile${randomInt}.py`; + fs_1.writeFileSync(filePath, code); + return PythonShell.run(filePath, options, callback); + } + ; + /** + * Parses an error thrown from the Python process through stderr + * @param {string|Buffer} data The stderr contents to parse + * @return {Error} The parsed error with extended stack trace when traceback is available + */ + parseError(data) { + let text = '' + data; + let error; + if (/^Traceback/.test(text)) { + // traceback data is available + let lines = ('' + data).trim().split(new RegExp(os_1.EOL, 'g')); + let exception = lines.pop(); + error = new PythonShellError(exception); + error.traceback = data; + // extend stack trace + error.stack += os_1.EOL + ' ----- Python Traceback -----' + os_1.EOL + ' '; + error.stack += lines.slice(1).join(os_1.EOL + ' '); + } + else { + // otherwise, create a simpler error with stderr contents + error = new PythonShellError(text); + } + return error; + } + ; + /** + * gets a random int from 0-10000000000 + */ + static getRandomInt() { + return Math.floor(Math.random() * 10000000000); + } + /** + * Sends a message to the Python shell through stdin + * Override this method to format data to be sent to the Python process + * @param {string|Object} data The message to send + * @returns {PythonShell} The same instance for chaining calls + */ + send(message) { + let data = this.formatter ? this.formatter(message) : message; + if (this.mode !== 'binary') + data += os_1.EOL; + this.stdin.write(data); + return this; + } + ; + /** + * Parses data received from the Python shell stdout stream and emits "message" events + * This method is not used in binary mode + * Override this method to parse incoming data from the Python process into messages + * @param {string|Buffer} data The data to parse into messages + */ + receive(data) { + return this.recieveInternal(data, 'message'); + } + ; + /** + * Parses data received from the Python shell stderr stream and emits "stderr" events + * This method is not used in binary mode + * Override this method to parse incoming logs from the Python process into messages + * @param {string|Buffer} data The data to parse into messages + */ + receiveStderr(data) { + return this.recieveInternal(data, 'stderr'); + } + ; + recieveInternal(data, emitType) { + let self = this; + let parts = ('' + data).split(new RegExp(os_1.EOL, 'g')); + if (parts.length === 1) { + // an incomplete record, keep buffering + this._remaining = (this._remaining || '') + parts[0]; + return this; + } + let lastLine = parts.pop(); + // fix the first line with the remaining from the previous iteration of 'receive' + parts[0] = (this._remaining || '') + parts[0]; + // keep the remaining for the next iteration of 'receive' + this._remaining = lastLine; + parts.forEach(function (part) { + if (emitType == 'message') + self.emit(emitType, self.parser(part)); + else if (emitType == 'stderr') + self.emit(emitType, self.stderrParser(part)); + }); + 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 + */ + end(callback) { + this.childProcess.stdin.end(); + this._endCallback = 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 + */ + terminate(signal) { + this.childProcess.kill(signal); + this.terminated = true; + return this; + } + ; +} +// starting 2020 python2 is deprecated so we choose 3 as default +// except for windows which just has "python" command +PythonShell.defaultPythonPath = process.platform != "win32" ? "python3" : "python"; +PythonShell.defaultOptions = {}; //allow global overrides for options +// built-in formatters +PythonShell.format = { + text: function toText(data) { + if (!data) + return ''; + else if (typeof data !== 'string') + return data.toString(); + return data; + }, + json: function toJson(data) { + return JSON.stringify(data); + } +}; +//built-in parsers +PythonShell.parse = { + text: function asText(data) { + return data; + }, + json: function asJson(data) { + return JSON.parse(data); + } +}; +exports.PythonShell = PythonShell; +; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/index.js.map b/index.js.map new file mode 100644 index 0000000..0dea9dc --- /dev/null +++ b/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 5d4f9e4..2f6075d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "python-shell", - "version": "1.0.0", + "version": "1.0.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index c98b4fe..1dee0a2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "python-shell", - "version": "1.0.0", + "version": "1.0.1", "description": "Run Python scripts from Node.js with simple (but efficient) inter-process communication through stdio", "keywords": [ "python" @@ -8,7 +8,7 @@ "scripts": { "test": "tsc -p ./ && mocha -R spec", "appveyorTest": "tsc -p ./ && mocha --ui tdd --reporter mocha-appveyor-reporter test/*.js", - "compile":"tsc -watch -p ./" + "compile": "tsc -watch -p ./" }, "dependencies": {}, "devDependencies": { diff --git a/test/test-python-shell.js b/test/test-python-shell.js new file mode 100644 index 0000000..a6e7793 --- /dev/null +++ b/test/test-python-shell.js @@ -0,0 +1,406 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const should = require("should"); +const __1 = require(".."); +const path_1 = require("path"); +const os_1 = require("os"); +describe('PythonShell', function () { + __1.PythonShell.defaultOptions = { + scriptPath: './test/python' + }; + describe('#ctor(script, options)', function () { + it('should spawn a Python process', function (done) { + let pyshell = new __1.PythonShell('exit-code.py'); + pyshell.command.should.eql(['test' + path_1.sep + 'python' + path_1.sep + 'exit-code.py']); + pyshell.terminated.should.be.false; + pyshell.end(function (err) { + if (err) + return done(err); + pyshell.terminated.should.be.true; + done(); + }); + }); + it('should spawn a Python process with options', function (done) { + let pyshell = new __1.PythonShell('exit-code.py', { + pythonOptions: ['-u'] + }); + pyshell.command.should.eql(['-u', 'test' + path_1.sep + 'python' + path_1.sep + 'exit-code.py']); + pyshell.end(done); + }); + it('should spawn a Python process with script arguments', function (done) { + let pyshell = new __1.PythonShell('echo_args.py', { + args: ['hello', 'world'] + }); + pyshell.command.should.eql(['test' + path_1.sep + 'python' + path_1.sep + 'echo_args.py', 'hello', 'world']); + pyshell.end(done); + }); + }); + describe('#checkSyntax(code:string)', function () { + // note checkSyntax is a wrapper around checkSyntaxFile + // so this tests checkSyntaxFile as well + it('should check syntax', function (done) { + __1.PythonShell.checkSyntax("x=1").then(() => { + done(); + }); + }); + it('should invalidate bad syntax', function (done) { + __1.PythonShell.checkSyntax("x=").catch(() => { + done(); + }); + }); + }); + describe('#runString(script, options)', function () { + before(() => { + __1.PythonShell.defaultOptions = {}; + }); + it('should be able to execute a string of python code', function (done) { + __1.PythonShell.runString('print("hello");print("world")', null, function (err, results) { + if (err) + return done(err); + results.should.be.an.Array().and.have.lengthOf(2); + results.should.eql(['hello', 'world']); + done(); + }); + }); + after(() => { + __1.PythonShell.defaultOptions = { + // reset to match initial value + scriptPath: './test/python' + }; + }); + }); + describe('#run(script, options)', function () { + it('should run the script and return output data', function (done) { + __1.PythonShell.run('echo_args.py', { + args: ['hello', 'world'] + }, function (err, results) { + if (err) + return done(err); + results.should.be.an.Array().and.have.lengthOf(2); + results.should.eql(['hello', 'world']); + done(); + }); + }); + it('should try to run the script and fail appropriately', function (done) { + __1.PythonShell.run('unknown_script.py', null, function (err, results) { + err.should.be.an.Error; + err.exitCode.should.be.exactly(2); + done(); + }); + }); + it('should run the script and fail with an extended stack trace', function (done) { + __1.PythonShell.run('error.py', null, function (err, results) { + err.should.be.an.Error; + err.exitCode.should.be.exactly(1); + err.stack.should.containEql('----- Python Traceback -----'); + done(); + }); + }); + it('should run multiple scripts and fail with an extended stack trace for each of them', function (done) { + let numberOfTimesToRun = 20; + for (let i = 0; i < numberOfTimesToRun; i++) { + runSingleErrorScript(end); + } + let count = 0; + function end() { + count++; + if (count === numberOfTimesToRun) { + done(); + } + } + function runSingleErrorScript(callback) { + __1.PythonShell.run('error.py', null, function (err, results) { + err.should.be.an.Error; + err.exitCode.should.be.exactly(1); + err.stack.should.containEql('----- Python Traceback -----'); + callback(); + }); + } + }); + it('should run multiple scripts and return output data for each of them', function (done) { + let numberOfTimesToRun = 20; + for (let i = 0; i < numberOfTimesToRun; i++) { + runSingleScript(end); + } + let count = 0; + function end() { + count++; + if (count === numberOfTimesToRun) { + done(); + } + } + function runSingleScript(callback) { + __1.PythonShell.run('echo_args.py', { + args: ['hello', 'world'] + }, function (err, results) { + if (err) + return done(err); + results.should.be.an.Array().and.have.lengthOf(2); + results.should.eql(['hello', 'world']); + callback(); + }); + } + }); + }); + describe('.send(message)', function () { + it('should send string messages when mode is "text"', function (done) { + let pyshell = new __1.PythonShell('echo_text.py', { + mode: 'text' + }); + let output = ''; + pyshell.stdout.on('data', function (data) { + output += '' + data; + }); + pyshell.send('hello').send('world').end(function (err) { + if (err) + return done(err); + output.should.be.exactly('hello' + os_1.EOL + 'world' + os_1.EOL); + done(); + }); + }); + it('should send JSON messages when mode is "json"', function (done) { + let pyshell = new __1.PythonShell('echo_json.py', { + mode: 'json' + }); + let output = ''; + pyshell.stdout.on('data', function (data) { + output += '' + data; + }); + pyshell.send({ a: 'b' }).send(null).send([1, 2, 3]).end(function (err) { + if (err) + return done(err); + output.should.be.exactly('{"a": "b"}' + os_1.EOL + 'null' + os_1.EOL + '[1, 2, 3]' + os_1.EOL); + done(); + }); + }); + it('should use a custom formatter', function (done) { + let pyshell = new __1.PythonShell('echo_text.py', { + formatter: function (message) { + return message.toUpperCase(); + } + }); + let output = ''; + pyshell.stdout.on('data', function (data) { + output += '' + data; + }); + pyshell.send('hello').send('world').end(function (err) { + if (err) + return done(err); + output.should.be.exactly('HELLO' + os_1.EOL + 'WORLD' + os_1.EOL + ''); + done(); + }); + }); + it('should write as-is when mode is "binary"', function (done) { + let pyshell = new __1.PythonShell('echo_binary.py', { + mode: 'binary' + }); + let output = ''; + pyshell.stdout.on('data', function (data) { + output += '' + data; + }); + pyshell.send(new Buffer('i am not a string')).end(function (err) { + if (err) + return done(err); + output.should.be.exactly('i am not a string'); + done(); + }); + }); + }); + describe('.receive(data)', function () { + it('should emit messages as strings when mode is "text"', function (done) { + let pyshell = new __1.PythonShell('echo_text.py', { + mode: 'text' + }); + let count = 0; + pyshell.on('message', function (message) { + count === 0 && message.should.be.exactly('hello'); + count === 1 && message.should.be.exactly('world'); + count++; + }).on('close', function () { + count.should.be.exactly(2); + }).send('hello').send('world').end(done); + }); + it('should emit messages as JSON when mode is "json"', function (done) { + let pyshell = new __1.PythonShell('echo_json.py', { + mode: 'json' + }); + let count = 0; + pyshell.send({ a: 'b' }).send(null).send([1, 2, 3, 4, 5]); + pyshell.on('message', function (message) { + count === 0 && message.should.eql({ a: 'b' }); + count === 1 && should(message).eql(null); + count === 2 && message.should.eql([1, 2, 3, 4, 5]); + count++; + }).on('close', function () { + count.should.be.exactly(3); + }).end(done); + }); + it('should properly buffer partial messages', function (done) { + let pyshell = new __1.PythonShell('echo_json.py', { + mode: 'json' + }); + pyshell.on('message', function (message) { + message.should.be.an.Object; + message.should.eql({ a: true }); + }).receive('{"a"').receive(':').receive('true}' + os_1.EOL + '').end(done); + }); + it('should not be invoked when mode is "binary"', function (done) { + let pyshell = new __1.PythonShell('echo_args.py', { + args: ['hello', 'world'], + mode: 'binary' + }); + pyshell.receive = function () { + throw new Error('should not emit messages in binary mode'); + }; + pyshell.end(done); + }); + it('should use a custom parser function', function (done) { + let pyshell = new __1.PythonShell('echo_text.py', { + mode: 'text', + parser: function (message) { + return message.toUpperCase(); + } + }); + let count = 0; + pyshell.on('message', function (message) { + count === 0 && message.should.be.exactly('HELLO'); + count === 1 && message.should.be.exactly('WORLD!'); + count++; + }).on('close', function () { + count.should.be.exactly(2); + }).send('hello').send('world!').end(done); + }); + }); + describe('.receiveStderr(data)', function () { + it('should emit stderr logs as strings when mode is "text"', function (done) { + let pyshell = new __1.PythonShell('stderrLogging.py', { + mode: 'text' + }); + let count = 0; + pyshell.on('stderr', function (stderr) { + count === 0 && stderr.should.be.exactly('INFO:root:Jackdaws love my big sphinx of quartz.'); + count === 1 && stderr.should.be.exactly('DEBUG:log1:Quick zephyrs blow, vexing daft Jim.'); + count++; + }).on('close', function () { + count.should.be.exactly(5); + }).send('hello').send('world').end(done); + }); + it('should not be invoked when mode is "binary"', function (done) { + let pyshell = new __1.PythonShell('echo_args.py', { + args: ['hello', 'world'], + mode: 'binary' + }); + pyshell.receiveStderr = function () { + throw new Error('should not emit stderr in binary mode'); + }; + pyshell.end(done); + }); + it('should use a custom parser function', function (done) { + let pyshell = new __1.PythonShell('stderrLogging.py', { + mode: 'text', + stderrParser: function (stderr) { + return stderr.toUpperCase(); + } + }); + let count = 0; + pyshell.on('stderr', function (stderr) { + count === 0 && stderr.should.be.exactly('INFO:ROOT:JACKDAWS LOVE MY BIG SPHINX OF QUARTZ.'); + count === 1 && stderr.should.be.exactly('DEBUG:LOG1:QUICK ZEPHYRS BLOW, VEXING DAFT JIM.'); + count++; + }).on('close', function () { + count.should.be.exactly(5); + }).send('hello').send('world!').end(done); + }); + }); + describe('.end(callback)', function () { + it('should end normally when exit code is zero', function (done) { + let pyshell = new __1.PythonShell('exit-code.py'); + pyshell.end(function (err, code, signal) { + if (err) + return done(err); + code.should.be.exactly(0); + done(); + }); + }); + it('should emit error if exit code is not zero', function (done) { + let pyshell = new __1.PythonShell('exit-code.py', { + args: ['3'] + }); + pyshell.on('error', function (err) { + err.should.have.properties({ + message: 'process exited with code 3', + exitCode: 3 + }); + done(); + }); + }); + it('should emit error when the program exits because of an unhandled exception', function (done) { + let pyshell = new __1.PythonShell('error.py'); + pyshell.on('error', function (err) { + err.message.should.be.equalOneOf('ZeroDivisionError: integer division or modulo by zero', 'ZeroDivisionError: division by zero'); + err.should.have.property('traceback'); + err.traceback.should.containEql('Traceback (most recent call last)'); + done(); + }); + }); + it('should NOT emit error when logging is written to stderr', function (done) { + let pyshell = new __1.PythonShell('stderrLogging.py'); + pyshell.on('error', function (err) { + done(new Error("an error should not have been raised")); + }); + pyshell.on('close', function () { + done(); + }); + }); + }); + describe('.parseError(data)', function () { + it('should extend error with context properties', function (done) { + let pyshell = new __1.PythonShell('exit-code.py', { + args: ['1'] + }); + pyshell.on('error', function (err) { + err.should.have.properties(['exitCode', 'script', 'options', 'args']); + done(); + }); + }); + it('should extend err.stack with traceback', function (done) { + let pyshell = new __1.PythonShell('error.py'); + pyshell.on('error', function (err) { + err.stack.should.containEql('----- Python Traceback -----'); + err.stack.should.containEql('File "test' + path_1.sep + 'python' + path_1.sep + 'error.py", line 4'); + err.stack.should.containEql('File "test' + path_1.sep + 'python' + path_1.sep + 'error.py", line 6'); + done(); + }); + }); + }); + describe('.terminate()', function () { + it('set terminated to true', function (done) { + let pyshell = new __1.PythonShell('infinite_loop.py'); + pyshell.terminate(); + pyshell.terminated.should.be.true; + done(); + }); + it('run the end callback if specified', function (done) { + let pyshell = new __1.PythonShell('infinite_loop.py'); + let endCalled = false; + pyshell.end(() => { + endCalled = true; + }); + pyshell.terminate(); + pyshell.terminated.should.be.true; + done(); + }); + it('terminate with correct kill signal', function (done) { + let pyshell = new __1.PythonShell('infinite_loop.py'); + let endCalled = false; + pyshell.end(() => { + endCalled = true; + }); + pyshell.terminate('SIGKILL'); + pyshell.terminated.should.be.true; + setTimeout(() => { pyshell.exitSignal.should.be.exactly('SIGKILL'); }, 500); + done(); + }); + }); +}); +//# sourceMappingURL=test-python-shell.js.map \ No newline at end of file diff --git a/test/test-python-shell.js.map b/test/test-python-shell.js.map new file mode 100644 index 0000000..8a90e8d --- /dev/null +++ b/test/test-python-shell.js.map @@ -0,0 +1 @@ +{"version":3,"file":"test-python-shell.js","sourceRoot":"","sources":["test-python-shell.ts"],"names":[],"mappings":"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"} \ No newline at end of file